MergeTree
Движок MergeTree
и другие движки семейства MergeTree
(например, ReplacingMergeTree
, AggregatingMergeTree
) являются самыми часто используемыми и надежными движками таблиц в ClickHouse.
Движки таблиц семейства MergeTree
предназначены для высоких скоростей приема данных и огромных объемов данных. Операции вставки создают части таблицы, которые объединяются фоновым процессом с другими частями таблицы.
Основные характеристики движков таблиц семейства MergeTree
.
-
Первичный ключ таблицы определяет порядок сортировки внутри каждой части таблицы (кластерный индекс). Первичный ключ также не ссылается на отдельные строки, а на блоки из 8192 строк, называемые гранулами. Это делает первичные ключи огромных наборов данных достаточно маленькими для того, чтобы оставаться в загруженной основной памяти, при этом обеспечивая быстрый доступ к данным на диске.
-
Таблицы могут быть разделены на партиции с использованием произвольного выражения партиционирования. Удаление партиций обеспечивает, что партиции пропускаются при чтении, когда это допускается запросом.
-
Данные могут быть реплицированы на нескольких узлах кластера для высокой доступности, аварийного восстановления и обновлений без простоя. Смотрите Репликация данных.
-
Движки таблиц
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 tuple()
будет имплицитно добавлен к операторам 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. Принцип NULLS_LAST применяется для значений NULL
в предложении ORDER BY
.
Выбор первичного ключа
Количество столбцов в первичном ключе не ограничено. В зависимости от структуры данных вы можете включать большее или меньшее количество столбцов в первичный ключ. Это может:
-
Улучшить производительность индекса.
Если первичный ключ —
(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 для уменьшения объёма считываемых данных с диска в следующих запросах:
Индексы пропуска данных также могут быть созданы на составных столбцах:
Доступные типы индексов
MinMax
Хранит крайние значения указанного выражения (если выражение — это tuple
, тогда хранит крайние значения для каждого элемента tuple
), использует сохраняемую информацию для пропуска блоков данных, как первичный ключ.
Синтаксис: minmax
Set
Хранит уникальные значения указанного выражения (не более чем max_rows
строк, max_rows=0
означает "без ограничений"). Использует значения, чтобы проверить, выполняется ли WHERE
-выражение для блока данных.
Синтаксис: set(max_rows)
Фильтр Блума
Хранит фильтр Блума для указанных столбцов. Необязательный параметр false_positive
с возможными значениями от 0 до 1 указывает вероятность получения ложноположительного ответа от фильтра. Значение по умолчанию: 0.025. Поддерживаемые типы данных: Int*
, UInt*
, Float*
, Enum
, Date
, DateTime
, String
, FixedString
, Array
, LowCardinality
, Nullable
, UUID
и Map
. Для типа данных Map
клиент может указать, должен ли индекс быть создан для ключей или значений с помощью функций mapKeys или mapValues.
Синтаксис: bloom_filter([false_positive])
N-gram Bloom Filter
Хранит фильтр Блума, который содержит все n-граммы из блока данных. Работает только с типами данных: String, FixedString и Map. Может использоваться для оптимизации выражений EQUALS
, LIKE
и IN
.
Синтаксис: ngrambf_v1(n, size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
n
— размер n-граммы,size_of_bloom_filter_in_bytes
— размер фильтра Блума в байтах (вы можете использовать большие значения здесь, например, 256 или 512, потому что они могут быть хорошо сжаты).number_of_hash_functions
— количество хеш-функций, используемых в фильтре Блума.random_seed
— начальное значение для хеш-функций фильтра Блума.
Пользователи могут создать UDF для оценки наборов параметров ngrambf_v1
. Запросы следующие:
Для использования этих функций нужно указать как минимум два параметра. Например, если в грануле 4300 n-грамм и мы ожидаем ложноположительных ответов менее 0.0001. Другие параметры могут быть оценены, выполняя следующие запросы:
Конечно, вы также можете использовать эти функции для оценки параметров при других условиях. Функции имеют отношение к содержимому здесь.
Token Bloom Filter
То же самое, что и ngrambf_v1
, но хранит токены вместо n-грамм. Токены — это последовательности, разделённые не алфавитными символами.
Синтаксис: tokenbf_v1(size_of_bloom_filter_in_bytes, number_of_hash_functions, random_seed)
Специальные цели
- Экспериментальный индекс для поддержки поиска по приближенному ближайшему соседу. Смотрите здесь для получения подробной информации.
- Экспериментальный полнотекстовый индекс для поддержки полнотекстового поиска. Смотрите здесь для получения подробной информации.
Поддержка функций
Условия в предложении WHERE
содержат вызовы функций, которые работают с колонками. Если колонка является частью индекса, ClickHouse пытается использовать этот индекс при выполнении функций. ClickHouse поддерживает различные подмножества функций для использования индексов.
Индексы типа set
могут быть использованы всеми функциями. Другие типы индексов поддерживаются следующим образом:
Функция (оператор) / Индекс | первичный ключ | minmax | ngrambf_v1 | tokenbf_v1 | bloom_filter | full_text |
---|---|---|---|---|---|---|
equals (=, ==) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
notEquals(!=, <>) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
like | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
notLike | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
match | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
startsWith | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
endsWith | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
multiSearchAny | ✗ | ✗ | ✔ | ✗ | ✗ | ✔ |
in | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
notIn | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
less (< ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
greater (> ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
lessOrEquals (<= ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
greaterOrEquals (>= ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
empty | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
notEmpty | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
has | ✗ | ✗ | ✔ | ✔ | ✔ | ✔ |
hasAny | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ |
hasAll | ✗ | ✗ | ✔ | ✔ | ✔ | ✗ |
hasToken | ✗ | ✗ | ✗ | ✔ | ✗ | ✔ |
hasTokenOrNull | ✗ | ✗ | ✗ | ✔ | ✗ | ✔ |
hasTokenCaseInsensitive (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ |
hasTokenCaseInsensitiveOrNull (*) | ✗ | ✗ | ✗ | ✔ | ✗ | ✗ |
Функции с константным аргументом, размер которого меньше, чем размер ngram, не могут использоваться ngrambf_v1
для оптимизации запросов.
(*) Для эффективной работы hasTokenCaseInsensitive
и hasTokenCaseInsensitiveOrNull
индекс tokenbf_v1
должен быть создан на данных в нижнем регистре, например INDEX idx (lower(str_col)) TYPE tokenbf_v1(512, 3, 0)
.
Фильтры Блума могут иметь ложные позитивные совпадения, поэтому индексы ngrambf_v1
, tokenbf_v1
и bloom_filter
не могут использоваться для оптимизации запросов, в которых ожидается, что результат функции будет ложным.
Например:
- Может быть оптимизировано:
s LIKE '%test%'
NOT s NOT LIKE '%test%'
s = 1
NOT s != 1
startsWith(s, 'test')
- Не может быть оптимизировано:
NOT s LIKE '%test%'
s NOT LIKE '%test%'
NOT s = 1
s != 1
NOT startsWith(s, 'test')
Проекции
Проекции похожи на материализованные представления, но определены на уровне частей. Это обеспечивает гарантии согласованности вместе с автоматическим использованием в запросах.
При реализации проекций вы также должны учитывать настройку force_optimize_projection.
Проекции не поддерживаются в операторах SELECT
с модификатором FINAL.
Запрос проекции
Запрос проекции — это то, что определяет проекцию. Он неявно выбирает данные из родительской таблицы. Синтаксис
Проекции могут быть изменены или удалены с помощью оператора ALTER.
Хранение проекции
Проекции хранятся внутри директории частей. Это похоже на индекс, но содержит подкаталог, который хранит часть анонимной таблицы MergeTree
. Таблица создается на основании запроса определения проекции. Если есть предложение GROUP BY
, основной движок хранения становится AggregatingMergeTree, и все агрегатные функции преобразуются в AggregateFunction
. Если есть предложение ORDER BY
, таблица MergeTree
использует его как выражение своего первичного ключа. Во время процесса слияния часть проекции объединяется с помощью процедуры слияния своего хранилища. Контрольная сумма части родительской таблицы комбинируется с частью проекции. Другие операции обслуживания аналогичны операциям с индексами пропуска.
Анализ запроса
- Проверьте, можно ли использовать проекцию для ответа на данный запрос, то есть, генерирует ли она такой же ответ, как и запрос базовой таблицы.
- Выберите наилучшее подходящее соответствие, которое содержит наименьшее количество гранул для чтения.
- Конвейер запросов, который использует проекции, будет отличаться от конвейера, который использует оригинальные части. Если проекция отсутствует в некоторых частях, мы можем добавить конвейер для "проекции" ее в реальном времени.
Конкурентный доступ к данным
Для конкурентного доступа к таблице мы используем многоверсионность. То есть, когда таблица одновременно читается и обновляется, данные считываются из набора частей, которые актуальны на момент запроса. Долгих блокировок нет. Вставки не мешают операциям чтения.
Чтение из таблицы автоматически параллелизуется.
TTL для колонок и таблиц
Определяет срок жизни значений.
Условие TTL
может быть установлено для всей таблицы и для каждой отдельной колонки. Уровень TTL
таблицы также может задавать логику автоматического перемещения данных между дисками и томами или сжатия частей, в которых все данные истекли.
Выражения должны оцениваться как Date или DateTime тип данных.
Синтаксис
Установка времени жизни для колонки:
Для определения интервала
используйте операторы временного интервала, например:
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
запроса. Это полезно
для анализа ad-hoc, чтобы временно подключить диск, который, например, размещается по 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 при ВСТАВКЕ части данных. По умолчанию (если включено) если мы вставляем часть данных, которая уже истекла по правилу перемещения 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 (самый низкий приоритет).- Если все тома имеют теги, они имеют приоритет в заданном порядке.
- Если только некоторые тома имеют теги, те, у которых нет тегов, имеют наименьший приоритет, и они располагаются в порядке, в котором они определены в конфигурации.
- Если никакие тома не имеют тегов, их приоритет устанавливается соответственно их порядку, в котором они были объявлены в конфигурации.
- Два тома не могут иметь одно и то же значение приоритета.
Примеры конфигурации:
В данном примере политика hdd_in_order
реализует подход round-robin. Таким образом, эта политика определяет только один том (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
— Последовательный индекс части в результате запроса._partition_id
— Имя партиции._part_uuid
— Уникальный идентификатор части (если включена настройка MergeTreeassign_part_uuids
)._partition_value
— Значения (кортеж) выраженияpartition by
._sample_factor
— Фактор выборки (из запроса)._block_number
— Номер блока строки, сохраняется при слиянии, когдаallow_experimental_block_number_column
установлен в true.
Статистика колонок
Объявление статистики находится в разделе колонок запроса 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 or FixedString | |
---|---|---|
CountMin | ✔ | ✔ |
MinMax | ✔ | ✗ |
TDigest | ✔ | ✗ |
Uniq | ✔ | ✔ |
Поддерживаемые операции
Фильтры равенства (==) | Диапазонные фильтры (>, >=, <, <= ) | |
---|---|---|
CountMin | ✔ | ✗ |
MinMax | ✗ | ✔ |
TDigest | ✗ | ✔ |
Uniq | ✔ | ✗ |
Параметры на уровне колонок
Некоторые настройки MergeTree могут быть переопределены на уровне колонок:
max_compress_block_size
— Максимальный размер блоков несжатых данных перед сжатием для записи в таблицу.min_compress_block_size
— Минимальный размер блоков несжатых данных, требуемый для сжатия при записи следующей метки.
Пример:
Параметры на уровне колонок могут быть изменены или удалены с помощью ALTER MODIFY COLUMN, например:
- Удалить
SETTINGS
из объявления колонки:
- Изменить настройку:
- Сбросить одну или несколько настроек, также удаляет объявление настройки в выражении колонки запроса CREATE таблицы.