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. Для значений NULL
в операторе ORDER BY
применяется принцип NULLS_LAST.
Выбор первичного ключа
Количество столбцов в первичном ключе не ограничено явно. В зависимости от структуры данных, вы можете включить больше или меньше столбцов в первичный ключ. Это может:
-
Улучшить производительность индекса.
Если первичный ключ — это
(a, b)
, добавление еще одного столбцаc
улучшит производительность, если выполнены следующие условия:- Существуют запросы с условием по столбцу
c
. - Часто встречаются длинные диапазоны данных (в несколько раз длиннее, чем
index_granularity
) с одинаковыми значениями(a, b)
. Другими словами, когда добавление еще одного столбца позволяет пропустить довольно длинные диапазоны данных.
- Существуют запросы с условием по столбцу
-
Улучшить сжатие данных.
ClickHouse сортирует данные по первичному ключу, поэтому чем выше согласованность, тем лучше сжатие.
-
Обеспечить дополнительную логику при слиянии частей данных в движках CollapsingMergeTree и SummingMergeTree.
В этом случае имеет смысл указать ключ сортировки, отличающийся от первичного ключа.
Длинный первичный ключ отрицательно повлияет на производительность вставок и использование памяти, но дополнительные столбцы в первичном ключе не влияют на производительность ClickHouse при SELECT
запросах.
Вы можете создать таблицу без первичного ключа, используя синтаксис ORDER BY tuple()
. В этом случае ClickHouse сохраняет данные в порядке вставки. Если вы хотите сохранить порядок данных при вставке данных через запросы INSERT ... SELECT
, установите max_insert_threads = 1.
Для выбора данных в исходном порядке используйте однопоточные SELECT
запросы.
Выбор первичного ключа, отличающегося от ключа сортировки
Возможно указать первичный ключ (выражение со значениями, которые записываются в файл индекса для каждой метки), который отличается от ключа сортировки (выражения для сортировки строк в частях данных). В этом случае кортеж выражений первичного ключа должен быть префиксом кортежа выражений ключа сортировки.
Эта функция полезна при использовании движков таблиц SummingMergeTree и
AggregatingMergeTree. В обычном случае при использовании этих движков таблица имеет два типа столбцов: размерности и меры. Типичные запросы агрегируют значения столбцов мер с произвольным GROUP BY
и фильтрацией по размерностям. Поскольку SummingMergeTree и AggregatingMergeTree агрегируют строки с одинаковым значением ключа сортировки, логично добавить все размерности в него. В результате выражение ключа состоит из длинного списка столбцов, и этот список необходимо часто обновлять с новыми размерностями.
В этом случае имеет смысл оставить только несколько столбцов в первичном ключе, которые обеспечат эффективные диапазонные сканирования, а остальные столбцы размерностей добавить в кортеж ключа сортировки.
ALTER ключа сортировки — это легковесная операция, так как при одновременном добавлении нового столбца в таблицу и в ключ сортировки, существующие части данных не нужно изменять. Поскольку старый ключ сортировки является префиксом нового ключа сортировки и в новом столбце нет данных, данные сортируются как по старому ключу сортировки, так и по новому в момент изменения таблицы.
Использование индексов и разделов в запросах
Для SELECT
запросов ClickHouse анализирует, может ли использоваться индекс. Индекс может использоваться, если в условии WHERE/PREWHERE
есть выражение (как один из элементов конъюнкции, или полностью), которое представляет собой операцию сравнения равенства или неравенства, или если оно содержит IN
или LIKE
с фиксированным префиксом на столбцах или выражениях, которые находятся в первичном ключе или ключе разделения, или на некоторых частично повторяющихся функциях этих столбцов, или логических отношениях этих выражений.
Таким образом, можно быстро выполнять запросы на один или несколько диапазонов первичного ключа. В этом примере запросы будут быстрыми при выполнении для определенного тегирования, для определенного тега и диапазона дат, для определенного тега и даты, для нескольких тегов с диапазоном дат и так далее.
Давайте рассмотрим движок, настроенный следующим образом:
В этом случае в запросах:
ClickHouse будет использовать индекс первичного ключа для отсечения недопустимых данных и ключ разделения на месячные части для отсечения разделов, которые находятся в недопустимых диапазонах дат.
Приведенные выше запросы показывают, что индекс используется даже для сложных выражений. Чтение из таблицы организовано так, что использование индекса не может быть медленнее полного сканирования.
В примере ниже индекс не может быть использован.
Чтобы проверить, может ли ClickHouse использовать индекс при выполнении запроса, используйте параметры force_index_by_date и force_primary_key.
Ключ для разделения по месяцам позволяет читать только те блоки данных, которые содержат даты из нужного диапазона. В этом случае блок данных может содержать данные для многих дат (до целого месяца). В пределах блока данные сортируются по первичному ключу, который может не содержать дату в качестве первого столбца. Из-за этого использование запроса с условием только по дате, не указывающим префикс первичного ключа, приведет к большему количеству прочитанных данных, чем для одной даты.
Использование индекса для частично-монотонных первичных ключей
Рассмотрим, например, дни месяца. Они образуют монотонную последовательность для одного месяца, но не монотонные для более длительных периодов. Это частично-монотонная последовательность. Если пользователь создает таблицу с частично-монотонным первичным ключом, ClickHouse создает разреженный индекс, как обычно. Когда пользователь выбирает данные из такой таблицы, ClickHouse анализирует условия запроса. Если пользователь хочет получить данные между двумя метками индекса, и обе эти метки попадают в один месяц, ClickHouse может использовать индекс в этом конкретном случае, поскольку он может вычислить расстояние между параметрами запроса и метками индекса.
ClickHouse не может использовать индекс, если значения первичного ключа в диапазоне параметров запроса не представляют монотонную последовательность. В этом случае ClickHouse использует метод полного сканирования.
ClickHouse использует эту логику не только для последовательностей дней месяца, но и для любого первичного ключа, представляющего частично-монотонную последовательность.
Индексы пропуска данных
Объявление индекса находится в секции столбцов запроса CREATE
.
Для таблиц из семейства *MergeTree
могут быть заданы индексы пропуска данных.
Эти индексы агрегируют некоторую информацию о заданном выражении на блоках, которые состоят из granularity_value
гранул (размер гранулы задается с помощью настройки index_granularity
в движке таблиц). Затем эти агрегаты используются в SELECT
запросах для уменьшения объема данных, которые нужно читать с диска, пропуская большие блоки данных, где не может быть выполнен where
запрос.
Оператор GRANULARITY
может быть опущен, значение по умолчанию granularity_value
составляет 1.
Пример
Индексы из примера могут быть использованы ClickHouse для уменьшения объема данных, читаемых с диска, в следующих запросах:
Индексы пропуска данных могут также быть созданы для составных столбцов:
Доступные типы индексов
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-грамм-фильтр Блума
Хранит фильтр Блума, который содержит все 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. Остальные параметры могут быть оценены путем выполнения следующих запросов:
Конечно, вы можете также использовать эти функции для оценки параметров по другим условиям. Функции ссылаются на содержимое здесь.
Токен-фильтр Блума
То же, что и 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
, то подлежащий движoк хранения становится 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
запроса. Это полезно для временного подключения диска, который, например, размещён по 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 или FixedString | |
---|---|---|
CountMin | ✔ | ✔ |
MinMax | ✔ | ✗ |
TDigest | ✔ | ✗ |
Uniq | ✔ | ✔ |
Поддерживаемые операции
Фильтры на равенство (==) | Фильтры диапазона (>, >=, <, <= ) | |
---|---|---|
CountMin | ✔ | ✗ |
MinMax | ✗ | ✔ |
TDigest | ✗ | ✔ |
Uniq | ✔ | ✗ |
Настройки на уровне столбцов
Некоторые настройки MergeTree могут быть переопределены на уровне столбцов:
max_compress_block_size
— Максимальный размер блоков несжатых данных перед сжатием для записи в таблицу.min_compress_block_size
— Минимальный размер блоков несжатых данных, необходимых для сжатия при записи следующей метки.
Пример:
Настройки уровня столбцов можно изменить или удалить с помощью ALTER MODIFY COLUMN, например:
- Удалить
SETTINGS
из объявления столбца:
- Изменить настройку:
- Сбросить одну или несколько настроек, также удаляет объявление настройки в выражении столбца запроса CREATE таблицы.