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. Для значений 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 | ✔ | ✔ | ✔ | ✔ | ✗ | ✔ |
matches | ✗ | ✗ | ✔ | ✔ | ✗ | ✔ |
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
запроса. Это полезно для временного прикрепления диска, который, например, размещён по 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
), и максимальный размер части, которая может быть сохранена на этом томе, составляет 1GB. Все части размером больше 1GB будут храниться непосредственно на томе 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 таблицы.