Движок таблиц MergeTree
Движок MergeTree и другие движки семейства MergeTree (например, ReplacingMergeTree, AggregatingMergeTree) являются наиболее часто используемыми и наиболее надежными движками таблиц в ClickHouse.
Движки таблиц семейства MergeTree разработаны для высокой скорости загрузки данных и работы с очень большими объемами данных.
Операции вставки создают части таблицы (table parts), которые фоновым процессом сливаются с другими частями таблицы.
Основные особенности движков таблиц семейства MergeTree:
-
Первичный ключ таблицы определяет порядок сортировки внутри каждой части таблицы (кластерный индекс). При этом первичный ключ ссылается не на отдельные строки, а на блоки по 8192 строки, называемые гранулами. Это делает первичные ключи огромных наборов данных достаточно компактными, чтобы оставаться загруженными в оперативной памяти, при этом обеспечивая быстрый доступ к данным на диске.
-
Таблицы могут быть секционированы (разделены на партиции) с использованием произвольного выражения партиционирования. Отсечение партиций (partition pruning) обеспечивает пропуск чтения партиций, если запрос позволяет это сделать.
-
Данные могут реплицироваться между несколькими узлами кластера для обеспечения высокой доступности, отказоустойчивости и обновлений без простоя. См. раздел Data replication.
-
Движки таблиц
MergeTreeподдерживают различные типы статистики и методы семплирования, которые помогают в оптимизации запросов.
Несмотря на схожее название, движок Merge отличается от движков *MergeTree.
Создание таблиц
Подробное описание параметров см. в описании оператора CREATE TABLE.
Секции запроса
ENGINE
ENGINE — имя и параметры движка. ENGINE = MergeTree(). Движок MergeTree не имеет параметров.
ORDER BY
ORDER BY — ключ сортировки.
Кортеж из имен столбцов или произвольных выражений. Пример: ORDER BY (CounterID + 1, EventDate).
Если первичный ключ не определен (т.е. секция PRIMARY KEY не указана), ClickHouse использует ключ сортировки в качестве первичного ключа.
Если сортировка не требуется, можно использовать синтаксис ORDER BY tuple().
Альтернативно, если включена настройка create_table_empty_primary_key_by_default, секция ORDER BY () неявно добавляется к операторам CREATE TABLE. См. Выбор первичного ключа.
PARTITION BY
PARTITION BY — ключ партиционирования. Необязательный параметр. В большинстве случаев ключ партиционирования не требуется, а если партиционирование необходимо, обычно не нужен ключ более детальный, чем по месяцам. Партиционирование не ускоряет запросы (в отличие от выражения ORDER BY). Не следует использовать слишком детальное партиционирование. Не партиционируйте данные по идентификаторам или именам клиентов (вместо этого сделайте идентификатор или имя клиента первым столбцом в выражении ORDER BY).
Для партиционирования по месяцам используйте выражение toYYYYMM(date_column), где date_column — столбец с датой типа Date. Имена партиций в этом случае имеют формат "YYYYMM".
PRIMARY KEY
PRIMARY KEY — первичный ключ, если он отличается от ключа сортировки. Необязательный параметр.
Указание ключа сортировки (с помощью секции ORDER BY) неявно задает первичный ключ.
Обычно нет необходимости указывать первичный ключ дополнительно к ключу сортировки.
SAMPLE BY
SAMPLE BY — выражение для сэмплирования. Необязательный параметр.
Если указано, оно должно содержаться в первичном ключе. Выражение для сэмплирования должно возвращать беззнаковое целое число.
Пример: SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID)).
TTL
TTL — список правил, определяющих длительность хранения строк и логику автоматического перемещения частей между дисками и томами. Необязательный параметр.
Выражение должно возвращать Date или DateTime, например, TTL date + INTERVAL 1 DAY.
Тип правила DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'|GROUP BY определяет действие, которое будет выполнено с частью данных при выполнении условия выражения (достижении текущего времени): удаление устаревших строк, перемещение части (если выражение выполнено для всех строк в части) на указанный диск (TO DISK 'xxx') или том (TO VOLUME 'xxx'), либо агрегирование значений в устаревших строках. Тип правила по умолчанию — удаление (DELETE). Можно указать список из нескольких правил, но должно быть не более одного правила DELETE.
Подробнее см. TTL для столбцов и таблиц
SETTINGS
См. Настройки MergeTree.
Пример настройки секций
В примере задано партиционирование по месяцам.
Также задано выражение для сэмплирования в виде хеша по идентификатору пользователя. Это позволяет псевдослучайным образом перемешать данные в таблице для каждого CounterID и EventDate. Если при выборке данных указать секцию SAMPLE, ClickHouse вернёт равномерную псевдослучайную выборку данных для подмножества пользователей.
Настройку index_granularity можно опустить, так как 8192 является значением по умолчанию.
Устаревший метод создания таблицы
Не используйте этот метод в новых проектах. По возможности переведите старые проекты на метод, описанный выше.
Параметры MergeTree()
date-column— Имя столбца типа Date. ClickHouse автоматически создаёт партиции по месяцам на основе этого столбца. Имена партиций имеют формат"YYYYMM".sampling_expression— Выражение для сэмплирования.(primary, key)— Первичный ключ. Тип: Tuple()index_granularity— Гранулярность индекса. Количество строк данных между «метками» индекса. Значение 8192 подходит для большинства задач.
Пример
Движок MergeTree настраивается так же, как в примере выше для основного метода конфигурации движка.
Хранение данных
Таблица состоит из кусков данных, отсортированных по первичному ключу.
При вставке данных в таблицу создаются отдельные куски данных, каждый из которых лексикографически сортируется по первичному ключу. Например, если первичный ключ — (CounterID, Date), данные в куске сортируются по CounterID, а внутри каждого CounterID упорядочиваются по Date.
Данные, относящиеся к разным партициям, разделяются на разные куски. В фоновом режиме ClickHouse объединяет куски данных для более эффективного хранения. Куски, принадлежащие разным партициям, не объединяются. Механизм слияния не гарантирует, что все строки с одинаковым первичным ключом окажутся в одном куске данных.
Куски данных могут храниться в формате Wide или Compact. В формате Wide каждый столбец хранится в отдельном файле файловой системы, в формате Compact все столбцы хранятся в одном файле. Формат Compact может использоваться для повышения производительности при небольших и частых вставках.
Формат хранения данных управляется настройками движка таблицы min_bytes_for_wide_part и min_rows_for_wide_part. Если количество байтов или строк в куске данных меньше значения соответствующей настройки, кусок хранится в формате Compact. В противном случае он хранится в формате Wide. Если ни одна из этих настроек не задана, куски данных хранятся в формате Wide.
Каждый кусок данных логически разделён на гранулы. Гранула — это наименьший неделимый набор данных, который ClickHouse читает при выборке данных. ClickHouse не разделяет строки или значения, поэтому каждая гранула всегда содержит целое число строк. Первая строка гранулы отмечается значением первичного ключа для этой строки. Для каждого куска данных ClickHouse создаёт индексный файл, в котором хранятся метки. Для каждого столбца, независимо от того, входит ли он в первичный ключ или нет, ClickHouse также сохраняет те же метки. Эти метки позволяют находить данные непосредственно в файлах столбцов.
Размер гранулы ограничивается настройками движка таблицы index_granularity и index_granularity_bytes. Количество строк в грануле находится в диапазоне [1, index_granularity] в зависимости от размера строк. Размер гранулы может превышать index_granularity_bytes, если размер одной строки больше значения настройки. В этом случае размер гранулы равен размеру строки.
Первичные ключи и индексы в запросах
Рассмотрим первичный ключ (CounterID, Date) в качестве примера. В этом случае сортировка и индекс могут быть проиллюстрированы следующим образом:
Если в запросе данных указано:
CounterID in ('a', 'h'), сервер читает данные в диапазонах меток[0, 3)и[6, 8).CounterID IN ('a', 'h') AND Date = 3, сервер читает данные в диапазонах меток[1, 3)и[7, 8).Date = 3, сервер читает данные в диапазоне меток[1, 10].
Приведенные выше примеры показывают, что использование индекса всегда эффективнее полного сканирования.
Разреженный индекс допускает чтение дополнительных данных. При чтении одного диапазона первичного ключа может быть прочитано до index_granularity * 2 дополнительных строк в каждом блоке данных.
Разреженные индексы позволяют работать с очень большим количеством строк таблицы, поскольку в большинстве случаев такие индексы помещаются в оперативной памяти компьютера.
ClickHouse не требует уникальности первичного ключа. Вы можете вставлять несколько строк с одинаковым первичным ключом.
Вы можете использовать выражения типа Nullable в секциях PRIMARY KEY и ORDER BY, но это крайне не рекомендуется. Чтобы разрешить эту возможность, включите настройку allow_nullable_key. Для значений NULL в секции ORDER BY применяется принцип NULLS_LAST.
Выбор первичного ключа
Количество столбцов в первичном ключе явно не ограничено. В зависимости от структуры данных вы можете включить в первичный ключ больше или меньше столбцов. Это может:
-
Улучшить производительность индекса.
Если первичный ключ — это
(a, b), то добавление еще одного столбцаcулучшит производительность, если выполняются следующие условия:- Существуют запросы с условием на столбец
c. - Длинные диапазоны данных (в несколько раз длиннее, чем
index_granularity) с идентичными значениями для(a, b)встречаются часто. Другими словами, когда добавление еще одного столбца позволяет пропускать довольно длинные диапазоны данных.
- Существуют запросы с условием на столбец
-
Улучшить сжатие данных.
ClickHouse сортирует данные по первичному ключу, поэтому чем выше согласованность данных, тем лучше сжатие.
-
Обеспечить дополнительную логику при слиянии частей данных в движках CollapsingMergeTree и SummingMergeTree.
В этом случае имеет смысл указать ключ сортировки, отличающийся от первичного ключа.
Длинный первичный ключ негативно повлияет на производительность вставки и потребление памяти, но дополнительные столбцы в первичном ключе не влияют на производительность ClickHouse при выполнении запросов SELECT.
Вы можете создать таблицу без первичного ключа, используя синтаксис ORDER BY tuple(). В этом случае ClickHouse хранит данные в порядке вставки. Если вы хотите сохранить порядок данных при вставке данных запросами INSERT ... SELECT, установите max_insert_threads = 1.
Для выборки данных в исходном порядке используйте однопоточные запросы SELECT.
Выбор первичного ключа, отличающегося от ключа сортировки
Возможно указать первичный ключ (выражение, значения которого записываются в индексный файл для каждой отметки), отличающийся от ключа сортировки (выражения для сортировки строк в частях данных). В этом случае кортеж выражения первичного ключа должен быть префиксом кортежа выражения ключа сортировки.
Эта возможность полезна при использовании движков таблиц SummingMergeTree и
AggregatingMergeTree. В типичном случае при использовании этих движков таблица имеет два типа столбцов: измерения и метрики. Типичные запросы агрегируют значения столбцов метрик с произвольным GROUP BY и фильтрацией по измерениям. Поскольку SummingMergeTree и AggregatingMergeTree агрегируют строки с одинаковым значением ключа сортировки, естественно добавить в него все измерения. В результате выражение ключа состоит из длинного списка столбцов, и этот список необходимо часто обновлять при добавлении новых измерений.
В этом случае имеет смысл оставить в первичном ключе только несколько столбцов, которые обеспечат эффективное сканирование диапазонов, и добавить остальные столбцы измерений в кортеж ключа сортировки.
ALTER ключа сортировки является лёгкой операцией, поскольку при одновременном добавлении нового столбца в таблицу и в ключ сортировки существующие части данных не требуют изменения. Так как старый ключ сортировки является префиксом нового ключа сортировки, а во вновь добавленном столбце нет данных, данные отсортированы как по старому, так и по новому ключу сортировки в момент модификации таблицы.
Использование индексов и партиций в запросах
Для запросов SELECT ClickHouse анализирует, может ли быть использован индекс. Индекс может быть использован, если в секции WHERE/PREWHERE присутствует выражение (как один из элементов конъюнкции или полностью), представляющее операцию сравнения на равенство или неравенство, или если оно содержит IN или LIKE с фиксированным префиксом для столбцов или выражений, которые входят в первичный ключ или ключ партиционирования, или для определённых частично повторяющихся функций этих столбцов, или логических отношений этих выражений.
Таким образом, возможно быстро выполнять запросы по одному или нескольким диапазонам первичного ключа. В этом примере запросы будут выполняться быстро для конкретного тега отслеживания, для конкретного тега и диапазона дат, для конкретного тега и даты, для нескольких тегов с диапазоном дат и так далее.
Рассмотрим движок, настроенный следующим образом:
В этом случае в запросах:
ClickHouse будет использовать индекс первичного ключа для отсечения неподходящих данных и ключ месячного партиционирования для отсечения партиций, находящихся в неподходящих диапазонах дат.
Приведённые выше запросы показывают, что индекс используется даже для сложных выражений. Чтение из таблицы организовано таким образом, что использование индекса не может быть медленнее полного сканирования.
В примере ниже индекс не может быть использован.
Чтобы проверить, может ли ClickHouse использовать индекс при выполнении запроса, используйте настройки force_index_by_date и force_primary_key.
Ключ партиционирования по месяцам позволяет читать только те блоки данных, которые содержат даты из соответствующего диапазона. В этом случае блок данных может содержать данные для многих дат (до целого месяца). Внутри блока данные отсортированы по первичному ключу, который может не содержать дату в качестве первого столбца. Из-за этого использование запроса только с условием по дате, не указывающим префикс первичного ключа, приведёт к чтению большего объёма данных, чем для одной даты.
Использование индекса для частично монотонных первичных ключей
Рассмотрим, например, дни месяца. Они образуют монотонную последовательность в пределах одного месяца, но не являются монотонными для более длительных периодов. Это частично монотонная последовательность. Если пользователь создает таблицу с частично монотонным первичным ключом, ClickHouse создает разреженный индекс как обычно. Когда пользователь выбирает данные из такой таблицы, ClickHouse анализирует условия запроса. Если пользователь хочет получить данные между двумя отметками индекса и обе эти отметки попадают в пределы одного месяца, ClickHouse может использовать индекс в этом конкретном случае, поскольку он может вычислить расстояние между параметрами запроса и отметками индекса.
ClickHouse не может использовать индекс, если значения первичного ключа в диапазоне параметров запроса не представляют собой монотонную последовательность. В этом случае ClickHouse использует метод полного сканирования.
ClickHouse использует эту логику не только для последовательностей дней месяца, но и для любого первичного ключа, который представляет собой частично монотонную последовательность.
Индексы пропуска данных
Объявление индекса находится в секции столбцов запроса CREATE.
Для таблиц семейства *MergeTree можно указывать индексы пропуска данных.
Эти индексы агрегируют некоторую информацию о заданном выражении на блоках, которые состоят из granularity_value гранул (размер гранулы задается с помощью настройки index_granularity в движке таблицы). Затем эти агрегаты используются в запросах SELECT для уменьшения объема данных, считываемых с диска, путем пропуска больших блоков данных, где условие where не может быть выполнено.
Предложение GRANULARITY может быть опущено, значение granularity_value по умолчанию равно 1.
Пример
Индексы из примера могут использоваться ClickHouse для уменьшения объема данных, считываемых с диска, в следующих запросах:
Индексы пропуска данных также могут быть созданы на составных столбцах:
Типы индексов пропуска
Движок таблиц MergeTree поддерживает следующие типы индексов пропуска.
Для получения дополнительной информации о том, как индексы пропуска могут использоваться для оптимизации производительности,
см. «Понимание индексов пропуска данных ClickHouse».
- Индекс
MinMax - Индекс
Set - Индекс
bloom_filter - Индекс
ngrambf_v1 - Индекс
tokenbf_v1
Индекс пропуска MinMax
Для каждой гранулы индекса сохраняются минимальное и максимальное значения выражения.
(Если выражение имеет тип tuple, сохраняются минимум и максимум для каждого элемента кортежа.)
Set
Для каждой гранулы индекса сохраняется не более max_rows уникальных значений указанного выражения.
max_rows = 0 означает «сохранять все уникальные значения».
Bloom filter
Для каждой гранулы индекса сохраняется фильтр Блума для указанных столбцов.
Параметр false_positive_rate может принимать значение от 0 до 1 (по умолчанию: 0.025) и задает вероятность ложноположительного срабатывания (что увеличивает объем считываемых данных).
Поддерживаются следующие типы данных:
(U)Int*Float*EnumDateDateTimeStringFixedStringArrayLowCardinalityNullableUUIDMap
N-граммный фильтр Блума
Для каждой гранулы индекса сохраняется фильтр Блума для n-грамм указанных столбцов.
| Параметр | Описание |
|---|---|
n | Размер n-граммы |
size_of_bloom_filter_in_bytes | Размер фильтра Блума в байтах. Здесь можно использовать большое значение, например 256 или 512, так как оно хорошо сжимается. |
number_of_hash_functions | Количество хеш-функций, используемых в фильтре Блума. |
random_seed | Начальное значение для хеш-функций фильтра Блума. |
Этот индекс работает только со следующими типами данных:
Для оценки параметров ngrambf_v1 можно использовать следующие пользовательские функции (UDF).
Для использования этих функций необходимо указать как минимум два параметра:
total_number_of_all_gramsprobability_of_false_positives
Например, в грануле содержится 4300 n-грамм, и вы ожидаете, что вероятность ложных срабатываний будет меньше 0.0001.
Остальные параметры можно оценить, выполнив следующие запросы:
Разумеется, эти функции также можно использовать для оценки параметров при других условиях. Приведенные выше функции основаны на калькуляторе фильтра Блума, доступном здесь.
Токенный фильтр Блума
Токенный фильтр Блума аналогичен ngrambf_v1, но сохраняет токены (последовательности, разделенные неалфавитно-цифровыми символами) вместо n-грамм.
Фильтр Блума на основе разреженных грамм
Фильтр Блума на основе разреженных грамм аналогичен ngrambf_v1, но использует токены разреженных грамм вместо n-грамм.
Текстовый индекс
Поддерживает полнотекстовый поиск, подробности см. здесь.
Векторное сходство
Поддерживает приближённый поиск ближайших соседей, подробности см. здесь.
Поддержка функций
Условия в секции WHERE содержат вызовы функций, работающих со столбцами. Если столбец является частью индекса, ClickHouse пытается использовать этот индекс при выполнении функций. ClickHouse поддерживает различные подмножества функций для использования индексов.
Индексы типа set могут использоваться всеми функциями. Другие типы индексов поддерживаются следующим образом:
| Функция (оператор) / индекс | первичный ключ | minmax | ngrambf_v1 | tokenbf_v1 | bloom_filter | text | sparse_grams |
|---|---|---|---|---|---|---|---|
| equals (=, ==) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| notEquals(!=, <>) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| like | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ | ✔ |
| notLike | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ | ✔ |
| match | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ | ✔ |
| startsWith | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ | ✔ |
| endsWith | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ | ✔ |
| multiSearchAny | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ |
| in | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| notIn | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
меньше (<) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
больше (>) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
lessOrEquals (<=) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
greaterOrEquals (>=) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
| empty | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ | ✗ |
| notEmpty | ✗ | ✔ | ✗ | ✗ | ✗ | ✗ | ✔ |
| has | ✗ | ✗ | ✔ | ✔ | ✔ | ✔ | ✔ |
| hasAny | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ | ✔ |
| hasAll | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ | ✔ |
| hasToken | ✗ | ✗ | ✗ | ✔ | ✗ | ✔ | ✗ |
| hasTokenOrNull | ✗ | ✗ | ✗ | ✔ | ✗ | ✔ | ✗ |
hasTokenCaseInsensitive (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ |
hasTokenCaseInsensitiveOrNull (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ |
| hasAnyTokens | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ | ✗ |
| hasAllTokens | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ | ✗ |
| mapContains | ✗ | ✗ | ✗ | ✗ | ✗ | ✔ | ✗ |
Функции с константным аргументом, который меньше размера n-граммы, не могут использоваться индексом ngrambf_v1 для оптимизации запросов.
(*) Чтобы hasTokenCaseInsensitive и hasTokenCaseInsensitiveOrNull были эффективны, индекс tokenbf_v1 должен быть создан по данным в нижнем регистре, например INDEX idx (lower(str_col)) TYPE tokenbf_v1(512, 3, 0).
Фильтры Блума могут давать ложноположительные совпадения, поэтому индексы ngrambf_v1, tokenbf_v1, sparse_grams и bloom_filter не могут использоваться для оптимизации запросов, в которых ожидается, что результат функции будет ложным.
Например:
- Может быть оптимизировано:
s LIKE '%test%'NOT s NOT LIKE '%test%'s = 1NOT s != 1startsWith(s, 'test')
- Не может быть оптимизировано:
NOT s LIKE '%test%'s NOT LIKE '%test%'NOT s = 1s != 1NOT startsWith(s, 'test')
Проекции
Проекции похожи на материализованные представления, но определяются на уровне части таблицы. Они обеспечивают гарантии согласованности и автоматически используются в запросах.
При использовании проекций следует также учитывать настройку force_optimize_projection.
Проекции не поддерживаются в операторах SELECT с модификатором FINAL.
Запрос проекции
Запрос проекции определяет проекцию. Он неявно выбирает данные из родительской таблицы. Синтаксис
Проекции можно изменять или удалять с помощью оператора ALTER.
Хранение проекций
Проекции хранятся внутри директории части таблицы. Это похоже на индекс, но содержит поддиректорию, в которой хранится часть анонимной таблицы MergeTree. Таблица создается на основе определяющего запроса проекции. Если присутствует секция GROUP BY, базовым движком хранения становится AggregatingMergeTree, и все агрегатные функции преобразуются в AggregateFunction. Если присутствует секция ORDER BY, таблица MergeTree использует её в качестве выражения первичного ключа. В процессе слияния часть проекции объединяется через процедуру слияния её хранилища. Контрольная сумма части родительской таблицы объединяется с контрольной суммой части проекции. Другие операции обслуживания аналогичны индексам с пропуском данных.
Анализ запросов
- Проверяется, может ли проекция использоваться для ответа на данный запрос, то есть генерирует ли она тот же результат, что и запрос к базовой таблице.
- Выбирается наилучшее подходящее совпадение, которое содержит наименьшее количество гранул для чтения.
- Конвейер запроса, использующий проекции, будет отличаться от того, который использует исходные части. Если проекция отсутствует в некоторых частях, можно добавить конвейер для её создания «на лету».
Параллельный доступ к данным
Для параллельного доступа к таблице используется многоверсионность. Иными словами, когда таблица одновременно читается и обновляется, данные читаются из набора кусков, актуального на момент выполнения запроса. Длительные блокировки отсутствуют. Операции вставки не мешают операциям чтения.
Чтение из таблицы автоматически распараллеливается.
TTL для столбцов и таблиц
Определяет время жизни значений.
Секция TTL может быть задана как для всей таблицы, так и для каждого отдельного столбца. TTL на уровне таблицы также может определять логику автоматического перемещения данных между дисками и томами или повторного сжатия кусков, в которых все данные устарели.
Выражения должны возвращать тип данных Date, Date32, DateTime или DateTime64.
Синтаксис
Установка времени жизни для столбца:
Для определения interval используйте операторы временных интервалов, например:
TTL столбца
Когда значения в столбце устаревают, ClickHouse заменяет их значениями по умолчанию для типа данных столбца. Если все значения столбца в куске данных устаревают, ClickHouse удаляет этот столбец из куска данных в файловой системе.
Секция TTL не может использоваться для ключевых столбцов.
Примеры
Создание таблицы с TTL:
Добавление TTL к столбцу существующей таблицы
Изменение TTL столбца
TTL таблицы
Таблица может иметь выражение для удаления устаревших строк и несколько выражений для автоматического перемещения кусков между дисками или томами. Когда строки в таблице устаревают, ClickHouse удаляет все соответствующие строки. Для перемещения или повторного сжатия кусков все строки куска должны удовлетворять критериям выражения TTL.
Тип правила TTL может следовать за каждым выражением TTL. Он определяет действие, которое должно быть выполнено после того, как выражение будет удовлетворено (достигнет текущего времени):
DELETE— удалить устаревшие строки (действие по умолчанию);RECOMPRESS codec_name— повторно сжать кусок данных с помощьюcodec_name;TO DISK 'aaa'— переместить кусок на дискaaa;TO VOLUME 'bbb'— переместить кусок на томbbb;GROUP BY— агрегировать устаревшие строки.
Действие DELETE может использоваться вместе с секцией WHERE для удаления только некоторых устаревших строк на основе условия фильтрации:
Выражение GROUP BY должно быть префиксом первичного ключа таблицы.
Если столбец не является частью выражения GROUP BY и не задан явно в секции SET, в результирующей строке он содержит произвольное значение из сгруппированных строк (как если бы к нему была применена агрегатная функция any).
Примеры
Создание таблицы с TTL:
Изменение TTL таблицы:
Создание таблицы, в которой строки истекают через месяц. Истекшие строки, даты которых приходятся на понедельники, удаляются:
Создание таблицы, в которой истекшие строки перекомпрессируются:
Создание таблицы, в которой истекшие строки агрегируются. В результирующих строках x содержит максимальное значение среди сгруппированных строк, y — минимальное значение, а d — любое случайное значение из сгруппированных строк.
Удаление истекших данных
Данные с истекшим TTL удаляются при слиянии частей данных в ClickHouse.
Когда ClickHouse обнаруживает истекшие данные, он выполняет внеплановое слияние. Для управления частотой таких слияний можно задать параметр merge_with_ttl_timeout. Если значение слишком низкое, будет выполняться много внеплановых слияний, что может потреблять значительные ресурсы.
Если вы выполняете запрос SELECT между слияниями, вы можете получить истекшие данные. Чтобы этого избежать, используйте запрос OPTIMIZE перед SELECT.
См. также
- настройка ttl_only_drop_parts
Типы дисков
Помимо локальных блочных устройств, ClickHouse поддерживает следующие типы хранилищ:
s3для S3 и MinIOgcsдля GCSblob_storage_diskдля Azure Blob Storagehdfsдля HDFSwebдля чтения данных из веб-источников в режиме только для чтенияcacheдля локального кэшированияs3_plainдля резервного копирования в S3s3_plain_rewritableдля неизменяемых нереплицируемых таблиц в S3
Использование нескольких блочных устройств для хранения данных
Введение
Семейство движков таблиц MergeTree может хранить данные на нескольких блочных устройствах. Например, это полезно, когда данные определённой таблицы неявно делятся на «горячие» и «холодные». К наиболее свежим данным регулярно обращаются, но они занимают небольшой объём. Напротив, исторические данные с «длинным хвостом» запрашиваются редко. Если доступно несколько дисков, «горячие» данные можно размещать на быстрых дисках (например, NVMe SSD или в памяти), а «холодные» данные — на относительно медленных (например, HDD).
Часть данных является минимальной перемещаемой единицей для таблиц на движке MergeTree. Данные, относящиеся к одной части, хранятся на одном диске. Части данных могут перемещаться между дисками в фоновом режиме (в соответствии с пользовательскими настройками), а также с помощью запросов ALTER.
Термины
- Диск — блочное устройство, подключённое к файловой системе.
- Диск по умолчанию — диск, на котором расположен путь, указанный в настройке сервера path.
- Том — упорядоченный набор однотипных дисков (аналогично JBOD).
- Политика хранения — набор томов и правила перемещения данных между ними.
Названия указанных сущностей можно найти в системных таблицах system.storage_policies и system.disks. Чтобы применить одну из настроенных политик хранения к таблице, используйте настройку storage_policy для таблиц семейства движков MergeTree.
Конфигурация
Диски, тома и политики хранения должны быть объявлены внутри тега <storage_configuration> в файле в каталоге config.d.
Диски также могут быть объявлены в секции SETTINGS запроса. Это полезно
для разового анализа, когда необходимо временно подключить диск, который, например, доступен по URL.
Подробнее см. в разделе динамическое хранилище.
Структура конфигурации:
Теги:
<disk_name_N>— имя диска. Имена должны отличаться для всех дисков.path— путь, по которому сервер будет хранить данные (каталогиdataиshadow); должен заканчиваться на «/».keep_free_space_bytes— объём свободного дискового пространства, который необходимо зарезервировать.
Порядок определения дисков не имеет значения.
Разметка конфигурации политик хранения:
Теги:
policy_name_N— имя политики. Имена политик должны быть уникальными.volume_name_N— имя тома. Имена томов должны быть уникальными.disk— диск внутри тома.max_data_part_size_bytes— максимальный размер части данных, которая может быть сохранена на любом из дисков тома. Если оцениваемый размер слитой части данных больше, чемmax_data_part_size_bytes, то эта часть будет записана на следующий том. По сути, эта возможность позволяет хранить новые/маленькие части данных на «горячем» томе (SSD) и перемещать их на «холодный» том (HDD), когда они становятся достаточно крупными. Не используйте этот параметр, если ваша политика содержит только один том.move_factor— когда количество доступного места становится меньше этого коэффициента, данные автоматически начинают перемещаться на следующий том, если он есть (по умолчанию 0.1). ClickHouse сортирует существующие части данных по размеру от наибольшей к наименьшей (в порядке убывания) и выбирает части с суммарным размером, достаточным для выполнения условияmove_factor. Если суммарного размера всех частей недостаточно, будут перемещены все части.perform_ttl_move_on_insert— отключает перемещение по TTL при INSERT части данных. По умолчанию (если параметр включен), если вставляется часть данных, которая уже просрочена по правилу перемещения TTL, она сразу записывается на том/диск, указанный в правиле перемещения. Это может значительно замедлить вставку, если целевой том/диск медленный (например, S3). Если параметр отключен, уже просроченная часть данных сначала записывается на том по умолчанию, а затем сразу же переносится на том, указанный правилом TTL.load_balancing— политика балансировки по дискам:round_robinилиleast_used.least_used_ttl_ms— настройка тайм-аута (в миллисекундах) для обновления информации о доступном пространстве на всех дисках (0— обновлять всегда,-1— никогда не обновлять, значение по умолчанию —60000). Обратите внимание: если диск может использоваться только ClickHouse и не подвержен онлайн-изменению размера/сжатию файловой системы, можно использовать-1; во всех остальных случаях это не рекомендуется, так как в итоге это приведёт к некорректному распределению пространства.prefer_not_to_merge— не следует использовать этот параметр. Отключает слияние частей данных на этом томе (это вредно и приводит к деградации производительности). Когда этот параметр включён (не делайте этого), слияние данных на этом томе не допускается (что плохо). Это позволяет (но вам это не нужно) управлять (если вы хотите чем-то управлять, вы совершаете ошибку) тем, как ClickHouse работает с медленными дисками (но ClickHouse знает лучше, поэтому, пожалуйста, не используйте этот параметр).volume_priority— определяет приоритет (порядок), в котором заполняются тома. Чем меньше значение, тем выше приоритет. Значения параметра должны быть натуральными числами и совместно покрывать диапазон от 1 до N (где N — наименьший приоритет) без пропуска каких-либо чисел.- Если у всех томов задан приоритет, они используются в указанном порядке.
- Если только у некоторых томов задан приоритет, тома без приоритета имеют наименьший приоритет и используются в том порядке, в котором они определены в конфигурации.
- Если ни у одного тома приоритет не задан, их приоритет устанавливается в соответствии с порядком их объявления в конфигурации.
- Два тома не могут иметь одинаковое значение приоритета.
Примеры конфигурации:
В данном примере политика hdd_in_order реализует подход циклического перебора. Эта политика определяет только один том (single), куски данных хранятся на всех его дисках в циклическом порядке. Такая политика может быть весьма полезна, если к системе подключено несколько однотипных дисков, но RAID не настроен. Имейте в виду, что каждый отдельный дисковый накопитель не является надёжным, и вы можете компенсировать это коэффициентом репликации 3 или более.
Если в системе доступны различные типы дисков, можно использовать политику moving_from_ssd_to_hdd. Том hot состоит из SSD-диска (fast_ssd), максимальный размер куска, который может храниться на этом томе, составляет 1 ГБ. Все куски размером более 1 ГБ будут храниться непосредственно на томе cold, который содержит HDD-диск disk1.
Кроме того, как только диск fast_ssd заполнится более чем на 80%, данные будут перенесены на disk1 фоновым процессом.
Порядок перечисления томов в политике хранения важен в случае, если хотя бы один из перечисленных томов не имеет явного параметра volume_priority.
Как только том переполняется, данные перемещаются на следующий. Порядок перечисления дисков также важен, поскольку данные хранятся на них по очереди.
При создании таблицы к ней можно применить одну из настроенных политик хранения:
Политика хранения default подразумевает использование только одного тома, который состоит из одного диска, указанного в <path>.
Политику хранения можно изменить после создания таблицы с помощью запроса [ALTER TABLE ... MODIFY SETTING], новая политика должна включать все старые диски и тома с теми же именами.
Количество потоков, выполняющих фоновое перемещение кусков данных, можно изменить с помощью настройки background_move_pool_size.
Подробности
В случае таблиц MergeTree данные попадают на диск различными способами:
- В результате вставки (запрос
INSERT). - Во время фоновых слияний и мутаций.
- При загрузке с другой реплики.
- В результате заморозки партиции ALTER TABLE ... FREEZE PARTITION.
Во всех этих случаях, за исключением мутаций и заморозки партиций, кусок хранится на томе и диске в соответствии с заданной политикой хранения:
- Выбирается первый том (в порядке определения), который имеет достаточно дискового пространства для хранения куска (
unreserved_space > current_part_size) и позволяет хранить куски заданного размера (max_data_part_size_bytes > current_part_size). - В пределах этого тома выбирается диск, который следует за тем, который использовался для хранения предыдущего фрагмента данных, и который имеет свободное пространство больше размера куска (
unreserved_space - keep_free_space_bytes > current_part_size).
Внутри мутации и заморозка партиций используют жёсткие ссылки. Жёсткие ссылки между различными дисками не поддерживаются, поэтому в таких случаях результирующие куски хранятся на тех же дисках, что и исходные.
В фоновом режиме куски перемещаются между томами на основе объёма свободного пространства (параметр move_factor) в соответствии с порядком, в котором тома объявлены в конфигурационном файле.
Данные никогда не переносятся с последнего тома на первый. Для мониторинга фоновых перемещений можно использовать системные таблицы system.part_log (поле type = MOVE_PART) и system.parts (поля path и disk). Также подробная информация доступна в логах сервера.
Пользователь может принудительно переместить кусок или партицию с одного тома на другой с помощью запроса ALTER TABLE ... MOVE PART|PARTITION ... TO VOLUME|DISK ..., при этом учитываются все ограничения для фоновых операций. Запрос инициирует перемещение самостоятельно и не ожидает завершения фоновых операций. Пользователь получит сообщение об ошибке, если недостаточно свободного пространства или если какое-либо из требуемых условий не выполнено.
Перемещение данных не влияет на репликацию данных. Поэтому для одной и той же таблицы на разных репликах могут быть указаны различные политики хранения.
После завершения фоновых слияний и мутаций старые части удаляются только по истечении заданного времени (old_parts_lifetime).
В течение этого времени они не перемещаются на другие тома или диски. Поэтому, пока части окончательно не удалены, они продолжают учитываться при расчёте занятого дискового пространства.
Пользователь может равномерно распределять новые крупные части по разным дискам тома JBOD с помощью настройки min_bytes_to_rebalance_partition_over_jbod.
Использование внешнего хранилища для хранения данных
Движки таблиц семейства MergeTree могут хранить данные в S3, AzureBlobStorage, HDFS, используя диски с типами s3, azure_blob_storage, hdfs соответственно. Подробнее см. в разделе настройка параметров внешнего хранилища.
Пример использования S3 в качестве внешнего хранилища с диском типа s3.
Разметка конфигурации:
См. также настройка параметров внешнего хранилища.
В версиях ClickHouse с 22.3 по 22.7 используется другая конфигурация кеша. См. раздел использование локального кеша, если вы используете одну из этих версий.
Виртуальные столбцы
_part— Имя части._part_index— Порядковый индекс части в результате запроса._part_starting_offset— Накопительное смещение начальной строки части в результате запроса._part_offset— Номер строки в части._part_granule_offset— Номер гранулы в части._partition_id— Имя партиции._part_uuid— Уникальный идентификатор части (если включена настройка MergeTreeassign_part_uuids)._part_data_version— Версия данных части (минимальный номер блока или версия мутации)._partition_value— Значения (кортеж) выраженияpartition by._sample_factor— Коэффициент выборки (из запроса)._block_number— Исходный номер блока для строки, назначенный при вставке; сохраняется при слияниях, если включена настройкаenable_block_number_column._block_offset— Исходный номер строки в блоке, назначенный при вставке; сохраняется при слияниях, если включена настройкаenable_block_offset_column._disk_name— Имя диска, используемого для хранения данных.
Статистика столбцов
Объявление статистики находится в секции столбцов запроса CREATE для таблиц семейства *MergeTree* при включении set allow_experimental_statistics = 1.
Статистикой также можно управлять с помощью операторов ALTER.
Эта легковесная статистика агрегирует информацию о распределении значений в столбцах. Статистика хранится в каждом куске и обновляется при каждой вставке данных.
Она может использоваться для оптимизации prewhere только при включении set allow_statistics_optimize = 1.
Доступные типы статистики столбцов
-
MinMaxМинимальное и максимальное значения столбца, что позволяет оценить селективность диапазонных фильтров для числовых столбцов.
Синтаксис:
minmax -
TDigestСкетчи TDigest, которые позволяют вычислять приблизительные процентили (например, 90-й процентиль) для числовых столбцов.
Синтаксис:
tdigest -
UniqСкетчи HyperLogLog, которые предоставляют оценку количества уникальных значений в столбце.
Синтаксис:
uniq -
CountMinСкетчи CountMin, которые предоставляют приблизительный подсчет частоты каждого значения в столбце.
Синтаксис:
countmin
Поддерживаемые типы данных
| (U)Int*, Float*, Decimal(), Date, Boolean, Enum* | String или FixedString | |
|---|---|---|
| CountMin | ✔ | ✔ |
| MinMax | ✔ | ✗ |
| TDigest | ✔ | ✗ |
| Uniq | ✔ | ✔ |
Поддерживаемые операции
| Фильтры равенства (==) | Диапазонные фильтры (>, >=, <, <=) | |
|---|---|---|
| CountMin | ✔ | ✗ |
| MinMax | ✗ | ✔ |
| TDigest | ✗ | ✔ |
| Uniq | ✔ | ✗ |
Настройки на уровне столбцов
Некоторые настройки MergeTree можно переопределить на уровне столбцов:
max_compress_block_size— Максимальный размер блоков несжатых данных перед сжатием при записи в таблицу.min_compress_block_size— Минимальный размер блоков несжатых данных, требуемый для сжатия при записи следующей метки.
Пример:
Настройки на уровне столбцов можно изменить или удалить с помощью ALTER MODIFY COLUMN, например:
- Удаление
SETTINGSиз объявления столбца:
- Изменение настройки:
- Сброс одной или нескольких настроек также удаляет объявление настройки в выражении столбца запроса CREATE таблицы.