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)
Bloom Filter
Хранит фильтр Блума для указанных колонок. Необязательный параметр 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 тип данных.
Синтаксис
Установка времени жизни для колонки:
Чтобы определить 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
реализует подход 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
.
Когда том переполняется, данные перемещаются на следующий. Порядок перечисления дисков также важен, так как данные хранятся на них по очереди.
При создании таблицы можно применить одну из настроенных политик хранения к ней:
Политика хранения по умолчанию предполагает использование только одного тома, который состоит только из одного диска, указанного в <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
— Номер строки в части._partition_id
— Имя партиции._part_uuid
— Уникальный идентификатор части (если включена настройка MergeTreeassign_part_uuids
)._part_data_version
— Версия данных части (либо минимальный номер блока, либо версия мутации)._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 или FixedString | |
---|---|---|
CountMin | ✔ | ✔ |
MinMax | ✔ | ✗ |
TDigest | ✔ | ✗ |
Uniq | ✔ | ✔ |
Поддерживаемые операции
Фильтры равенства (==) | Диапазонные фильтры (>, >=, <, <= ) | |
---|---|---|
CountMin | ✔ | ✗ |
MinMax | ✗ | ✔ |
TDigest | ✗ | ✔ |
Uniq | ✔ | ✗ |
Настройки на уровне колонок
Некоторые настройки MergeTree могут быть переопределены на уровне колонок:
max_compress_block_size
— Максимальный размер блоков несжатых данных перед сжатием для записи в таблицу.min_compress_block_size
— Минимальный размер блоков несжатых данных, необходимый для сжатия при записи следующей метки.
Пример:
Настройки на уровне колонок могут быть изменены или удалены с помощью ALTER MODIFY COLUMN, например:
- Удаление
SETTINGS
из объявления колонки:
- Изменение настройки:
- Сброс одной или нескольких настроек, также удаляет объявление настройки в выражении колонки запроса CREATE таблицы.