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.
Пример настройки секций
В примере мы задаем партиционирование по месяцу.
Мы также задаем выражение для выборки в виде хеш-значения по ID пользователя. Это позволяет вам псевдослучайным образом распределить данные в таблице для каждого 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 для сокращения объема данных, которые нужно прочитать с диска, в следующих запросах:
Индексы пропуска данных также могут быть созданы для составных столбцов:
Типы индексов пропуска
Движок таблицы 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*
Enum
Date
DateTime
String
FixedString
Array
LowCardinality
Nullable
UUID
Map
N-gram фильтр Блума
Для каждой индекса гранулы хранится фильтр Блума для n-грамм заданных столбцов.
Параметр | Описание |
---|---|
n | Размер n-граммы |
size_of_bloom_filter_in_bytes | Размер фильтра Блума в байтах. Здесь можно использовать большое значение, например, 256 или 512 , так как оно может быть хорошо сжато). |
number_of_hash_functions | Количество функций хеширования, используемых в фильтре Блума. |
random_seed | Сид для функций хеширования фильтра Блума. |
Этот индекс работает только с следующими типами данных:
Чтобы оценить параметры ngrambf_v1
, вы можете использовать следующие пользовательские функции (UDF).
Чтобы использовать эти функции, вам нужно указать как минимум два параметра:
total_number_of_all_grams
probability_of_false_positives
Например, в грануле имеются 4300
n-грамм, и вы ожидаете, что ложные срабатывания будут менее 0.0001
.
Остальные параметры затем можно оценить, выполнив следующие запросы:
Конечно, вы также можете использовать эти функции для оценки параметров для других условий. Эти функции ссылаются на калькулятор фильтра Блума здесь.
Token bloom filter
Фильтр токенов Блума такой же, как ngrambf_v1
, но вместо n-грамм хранит токены (последовательности, разделенные символами, не являющимися алфавитно-цифровыми).
Векторное сходство
Поддерживает приближенный поиск ближайших соседей, см. здесь для подробностей.
Текст (экспериментальный)
Поддержка полнотекстового поиска, см. здесь для подробностей.
Поддержка функций
Условия в операторе WHERE
содержат вызовы функций, которые работают со столбцами. Если столбец является частью индекса, ClickHouse пытается использовать этот индекс при выполнении функций. ClickHouse поддерживает различные подсходные группы функций для использования индексов.
Индексы типа set
могут использоваться всеми функциями. Другие типы индексов поддерживаются следующим образом:
Функция (оператор) / Индекс | первичный ключ | minmax | ngrambf_v1 | tokenbf_v1 | bloom_filter | text |
---|---|---|---|---|---|---|
equals (=, ==) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
notEquals(!=, <>) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
like | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
notLike | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
match | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
startsWith | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
endsWith | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
multiSearchAny | ✗ | ✗ | ✔ | ✗ | ✗ | ✗ |
in | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
notIn | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
less (< ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
greater (> ) | ✔ | ✔ | ✗ | ✗ | ✗ | ✗ |
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
и 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, 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
запроса. Это полезно
для анализа 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
реализует круговую стратегию. Таким образом, эта политика определяет только один объем (single
), части данных хранятся на всех его дисках в круговом порядке. Такая политика может быть весьма полезной, если в системе смонтировано несколько аналогичных дисков, но RAID не настроен. Имеет смысл помнить, что каждый отдельный жесткий диск не надежен, и вы можете захотеть компенсировать это с помощью фактора репликации 3 или более.
Если в системе доступны разные виды дисков, вместо этого можно использовать политику moving_from_ssd_to_hdd
. Объем hot
состоит из SSD-диска (fast_ssd
), и максимальный размер части, который может храниться на этом объеме, составляет 1 ГБ. Все части размером более 1 ГБ будут храниться непосредственно на объеме cold
, который содержит жесткий диск 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 or FixedString | |
---|---|---|
CountMin | ✔ | ✔ |
MinMax | ✔ | ✗ |
TDigest | ✔ | ✗ |
Uniq | ✔ | ✔ |
Поддерживаемые операции
Фильтры равенства (==) | Диапазонные фильтры (>, >=, <, <= ) | |
---|---|---|
CountMin | ✔ | ✗ |
MinMax | ✗ | ✔ |
TDigest | ✗ | ✔ |
Uniq | ✔ | ✗ |
Настройки на уровне колонок
Некоторые настройки MergeTree могут быть переопределены на уровне колонки:
max_compress_block_size
— Максимальный размер блоков некомпримированных данных перед их сжатием для записи в таблицу.min_compress_block_size
— Минимальный размер блоков некомпримированных данных, необходимых для сжатия при записи следующей метки.
Пример:
Настройки на уровне колонок могут быть изменены или удалены с помощью ALTER MODIFY COLUMN, например:
- Удалить
SETTINGS
из объявления колонки:
- Изменить настройку:
- Сбросить одну или несколько настроек, также удаляет декларацию настройки в выражении колонки запроса CREATE таблицы.