Обзор проекций
Проекции хранят данные в формате, оптимизированном для выполнения запросов. Эта возможность полезна в следующих случаях:- Выполнение запросов по столбцу, который не входит в первичный ключ
- Предварительная агрегация столбцов, что снижает как вычислительные затраты, так и объём операций ввода-вывода
Использование дискаПроекции внутренне создают новую скрытую таблицу, а это значит, что потребуется больше операций ввода-вывода и места на диске.
Например, если для проекции задан другой первичный ключ, все данные из исходной таблицы будут дублироваться.
Использование проекций
Пример фильтрации без использования первичных ключей
Создание таблицы:ALTER TABLE можно добавить проекцию в существующую таблицу:
user_name, даже если в исходной таблице user_name не был определён как PRIMARY_KEY.
Во время выполнения запроса ClickHouse определяет, что при использовании проекции будет обработано меньше данных, так как данные упорядочены по user_name.
system.query_log. В поле projections указано имя использованной проекции или пустое значение, если проекция не использовалась:
Пример запроса с предварительной агрегацией
Создайте таблицу с проекциейprojection_visits_by_user:
GROUP BY, используя поле user_agent.
Этот запрос не будет использовать проекцию, так как предварительная агрегация ему не соответствует.
GROUP BY:
system.query_log, чтобы понять, использовалась ли проекция.
Поле projections показывает имя использованной проекции.
Оно будет пустым, если проекция не использовалась:
Создание и использование индексов-проекций
Создание индекса-проекции:_part_offset сохраняет своё значение при слияниях и мутациях, что делает его полезным для вторичной индексации. Это можно использовать в запросах:
Пример проекции с предложением WHERE
Проекции могут включать предложениеWHERE, чтобы хранить только подмножество строк. Это полезно, когда запросы часто используют известный предикат фильтрации — проекция материализует только подходящие строки, уменьшая объём хранимых данных и повышая производительность запросов.
Создание таблицы и добавление отфильтрованной проекции:
WHERE-предложение запроса подразумевает WHERE-предложение проекции (то есть каждое условие в фильтре проекции также присутствует в фильтре запроса), оптимизатор может автоматически использовать проекцию, если сочтёт это целесообразным:
Управление проекциями
Доступны следующие операции с проекциями:ADD PROJECTION
Используйте оператор ниже, чтобы добавить описание проекции к метаданным таблицы:Когда проекция задаёт предложение
WHERE, материализуются только строки, соответствующие предикату. Оптимизатор может использовать такую проекцию, если WHERE в запросе логически следует из WHERE проекции и эта проекция выгодна для плана запроса. Это относится и к обычным, и к агрегатным проекциям.Конструкция WITH SETTINGS
WITH SETTINGS определяет настройки уровня проекции, которые задают, как проекция хранит данные (например, index_granularity или index_granularity_bytes).
Они напрямую соответствуют настройкам таблиц семейства MergeTree, но применяются только к этой проекции.
Пример:
MODIFY PROJECTION
Используйте приведённый ниже оператор, чтобы изменить конструкциюWITH SETTINGS существующей проекции без пересоздания её данных:
SELECT-запроса повторно укажите объявление INDEX:
WITH SETTINGS.
Сам запрос проекции (или, для индекса-проекции, выражение и тип индекса) должен оставаться прежним, поскольку существующие части проекции содержат построенные на его основе данные; чтобы изменить его, используйте DROP PROJECTION, а затем ADD PROJECTION.
Команда изменяет только метаданные таблицы и не переписывает данные: существующие части проекции сохраняют настройки, с которыми были записаны, тогда как части проекции, созданные последующими вставками и слияниями, используют новые настройки.
MATERIALIZE PROJECTION тоже не применяет новые настройки к существующим частям: она строит проекцию только в тех частях, где та отсутствует или повреждена, а уже существующие части проекции оставляет без изменений.
Чтобы перестроить существующие части с новыми настройками, выполните CLEAR PROJECTION, а затем MATERIALIZE PROJECTION либо выполните слияние частей, например с помощью OPTIMIZE TABLE ... FINAL.
Пример:
DROP PROJECTION
Используйте оператор ниже, чтобы удалить описание проекции из метаданных таблицы и удалить файлы проекции с диска. Эта операция выполняется как мутация.MATERIALIZE PROJECTION
Используйте приведённый ниже оператор, чтобы построить проекциюname в тех частях, где она отсутствует или повреждена (при необходимости — только в партиции partition_name).
Части, в которых проекция уже есть, остаются без изменений, даже если настройки проекции были изменены с помощью MODIFY PROJECTION после записи этих частей; чтобы перестроить их, сначала выполните CLEAR PROJECTION.
Это реализовано как мутация.
CLEAR PROJECTION
Используйте приведённый ниже оператор, чтобы удалить с диска файлы проекции, не удаляя её описание. Это реализовано как мутация.ADD, MODIFY, DROP и CLEAR считаются легковесными, поскольку изменяют только метаданные или удаляют файлы.
Кроме того, эти команды реплицируются и синхронизируют метаданные проекций через ClickHouse Keeper или ZooKeeper.
Операции с проекциями поддерживаются только для таблиц с движком
таблица семейства *MergeTree (включая реплицируемые варианты).Управление поведением слияния проекций
Когда вы выполняете запрос, ClickHouse выбирает, читать ли данные из исходной таблицы или из одной из её проекций. Это решение принимается отдельно для каждой части таблицы. Как правило, ClickHouse старается читать как можно меньше данных и использует несколько приёмов, чтобы определить, из какой части лучше читать, например сэмплирование по первичному ключу части. В некоторых случаях у частей исходной таблицы нет соответствующих частей проекций. Это может происходить, например, потому что создание проекции для таблицы в SQL по умолчанию выполняется «лениво»: оно затрагивает только вновь вставленные данные, а существующие части не изменяются. Поскольку одна из проекций уже содержит заранее вычисленные агрегированные значения, ClickHouse старается читать из соответствующих частей проекций, чтобы избежать повторной агрегации во время выполнения запроса. Если у конкретной части нет соответствующей части проекции, запрос выполняется по исходной части. Но что происходит, если строки в исходной таблице нетривиально изменяются из-за нетривиальных фоновых слияний частей данных? Например, предположим, что таблица использует движок таблицыReplacingMergeTree.
Если во время слияния в нескольких входных частях обнаруживается одна и та же строка, сохраняется только самая новая версия строки (из части, вставленной последней), а все более старые версии отбрасываются.
Аналогично, если таблица использует движок таблицы AggregatingMergeTree, операция слияния может сворачивать одинаковые строки во входных частях (на основе значений первичного ключа) в одну строку, чтобы обновить промежуточные состояния агрегации.
До ClickHouse v24.8 части проекций либо незаметно рассинхронизировались с основными данными, либо некоторые операции, такие как обновления и удаления, вообще нельзя было выполнять, поскольку база данных автоматически генерировала исключение, если у таблицы были проекции.
Начиная с v24.8, новый параметр уровня таблицы deduplicate_merge_projection_mode управляет поведением в случае, если вышеупомянутые нетривиальные фоновые операции слияния происходят в частях исходной таблицы.
Мутации удаления — ещё один пример операций слияния частей, при которых удаляются строки в частях исходной таблицы. Начиная с v24.7, также есть параметр для управления поведением в отношении мутаций удаления, запускаемых легковесными удалениями: lightweight_mutation_projection_mode.
Ниже приведены возможные значения для deduplicate_merge_projection_mode и lightweight_mutation_projection_mode:
throw(по умолчанию): генерируется исключение, что не позволяет частям проекций рассинхронизироваться.drop: Затронутые части таблицы проекций удаляются. Для таких частей запросы будут выполняться по исходной части таблицы.rebuild: Затронутая часть проекции перестраивается, чтобы оставаться согласованной с данными в части исходной таблицы.
Ограничения
Нельзя использовать столбецALIAS в предложении ORDER BY проекции. Например:
ALIAS физически не хранятся и вычисляются на лету во время выполнения запроса, поэтому они недоступны при записи части проекции, когда вычисляется выражение сортировки.
Вместо этого используйте столбцы MATERIALIZED или встроите выражение напрямую: