MergeTree
Движок MergeTree
, а также другие движки этого семейства (*MergeTree
) — это наиболее функциональные движки таблиц ClickHouse.
Основная идея, заложенная в основу движков семейства MergeTree
следующая. Когда у вас есть огромное количество данных, которые должны быть вставлены в таблицу, вы должны быстро записать и х по частям, а затем объединить части по некоторым правилам в фоновом режиме. Этот метод намного эффективнее, чем постоянная перезапись данных в хранилище при вставке.
Основные возможности:
-
Хранит данные, отсортированные по первичному ключу. Это позволяет создавать разреженный индекс небольшого объёма, который позволяет быстрее находить данные.
-
Позволяет оперировать партициями, если задан ключ партиционирования. ClickHouse поддерживает отдельные операции с партициями, которые работают эффективнее, чем общие операции с этим же результатом над этими же данными. Также, ClickHouse автоматически отсекает данные по партициям там, где ключ партиционирования указан в запросе. Это также увеличивает эффективность выполнения запросов.
-
Поддерживает репликацию данных. Для этого используется семейство таблиц
ReplicatedMergeTree
. Подробнее читайте в разделе Репликация данных. -
Поддерживает сэмплирование данных. При необходимости можно задать способ сэмпл ирования данных в таблице.
Движок Merge не относится к семейству *MergeTree
.
Создание таблицы
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
...
INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr
[DELETE|TO DISK 'xxx'|TO VOLUME 'xxx' [, ...] ]
[WHERE conditions]
[GROUP BY key_expr [SET v1 = aggr_func(v1) [, v2 = aggr_func(v2) ...]] ] ]
[SETTINGS name=value, ...]
Описание параметров смотрите в описании запроса CREATE.
Секции запроса
-
ENGINE
— имя и параметры движка.ENGINE = MergeTree()
.MergeTree
не имеет параметров. -
ORDER BY
— ключ сортировки.Кортеж столбцов или произвольных выражений. Пример:
ORDER BY (CounterID, EventDate)
.ClickHouse использует ключ сортировки в качестве первичного ключа, если первичный ключ не задан в секции
PRIMARY KEY
.Чтобы отключить сортировку, используйте синтаксис
ORDER BY tuple()
. Смотрите выбор первичного ключа. -
PARTITION BY
— ключ партиционирования. Необязательный параметр.Для партиционирования по месяцам используйте выражение
toYYYYMM(date_column)
, гдеdate_column
— столбец с датой типа Date. В этом случае имена партиций имеют формат"YYYYMM"
. -
PRIMARY KEY
— первичный ключ, если он отличается от ключа сортировки. Необязательный параметр.По умолчанию первичный ключ совпадает с ключом сортировки (который задаётся секцией
ORDER BY
.) Поэтому в большинстве случаев секциюPRIMARY KEY
отдельно указывать не нужно. -
SAMPLE BY
— выражение для сэмплирования. Необязательный параметр.Если используется выражение для сэмплирования, то первичный ключ должен содержать его. Результат выражения для сэмплирования должен быть беззнаковым целым числом. Пример:
SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))
. -
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
(необязательные):index_granularity
— максимальное количество строк данных между засечками индекса. По умолчанию — 8192. Смотрите Хранение данных.index_granularity_bytes
— максимальный размер гранул данных в байтах. По умолчанию — 10Mb. Чтобы ограничить размер гранул только количеством строк, установите значение 0 (не рекомендовано). Смотрите Хранение данных.min_index_granularity_bytes
— минимально допустимый размер гранул данных в байтах. Значение по умолчанию — 1024b. Для обеспечения защиты от случайного создания таблиц с очень низ ким значениемindex_granularity_bytes
. Смотрите Хранение данных.enable_mixed_granularity_parts
— включает или выключает переход к ограничению размера гранул с помощью настройкиindex_granularity_bytes
. Настройкаindex_granularity_bytes
улучшает производительность ClickHouse при выборке данных из таблиц с большими (десятки и сотни мегабайтов) строками. Если у вас есть таблицы с большими строками, можно включить эту настройку, чтобы повысить эффективность запросовSELECT
.use_minimalistic_part_header_in_zookeeper
— Способ хранения заголовков кусков данных в ZooKeeper. Еслиuse_minimalistic_part_header_in_zookeeper = 1
, то ZooKeeper хранит меньше данных. Подробнее читайте в описании настройки в разделе "Конфигурационные параметры сервера".min_merge_bytes_to_use_direct_io
— минимальный объём данных при слиянии, необходимый для прямого (небуферизованного) чтения/записи (direct I/O) на диск. При слиянии частей данных ClickHouse вычисляет общий объём хранения всех данных, подлежащих слиянию. Если общий объём хранения всех данных для чтения превышаетmin_bytes_to_use_direct_io
байт, тогда ClickHouse использует флагO_DIRECT
при чтении данных с диска. Еслиmin_merge_bytes_to_use_direct_io = 0
, тогда прямой ввод-вывод отключен. Значение по умолчанию:10 * 1024 * 1024 * 1024
байтов.merge_with_ttl_timeout
— минимальное время в секундах перед повторным слиянием для удаления данных с истекшим TTL. По умолчанию:14400
секунд (4 часа).merge_with_recompression_ttl_timeout
— минимальное время в секундах перед повторным слиянием для повторного сжатия данных с истекшим TTL. По умолчанию:14400
секунд (4 часа).try_fetch_recompressed_part_timeout
— время ожидания (в секундах) перед началом слияния с повторным сжатием. В течение этого времени ClickHouse пытается извлечь сжатую часть из реплики, которая назначила это слияние. Значение по умолчанию:7200
секунд (2 часа).write_final_mark
— включает или отключает запись последней засечки индекса в конце куска данных, указывающей за последний байт. По умолчанию — 1. Не отключайте её.merge_max_block_size
— максимальное количество строк в блоке для операций слияния. Значение по умолчанию: 8192.storage_policy
— политика хранения данных. Смотрите Хранение данных таблицы на нескольких блочных устройствах.min_bytes_for_wide_part
,min_rows_for_wide_part
— минимальное количество байт/строк в куске данных для хранения в форматеWide
. Можно задать одну или обе настройки или не задавать ни одной. Подробнее см. в разделе Хранение данных.max_parts_in_total
— максимальное количество кусков во всех партициях.max_compress_block_size
— максимальный размер блоков несжатых данных перед сжатием для записи в таблицу. Вы также можете задать этот параметр в глобальных настройках (смотрите max_compress_block_size). Настройка, которая задается при создании таблицы, имеет более высокий приоритет, чем глобальная.min_compress_block_size
— минимальный размер блоков несжатых данных, необходимых для сжатия при записи следующей засечки. Вы также можете задать этот параметр в глобальных настройках (смотрите min_compress_block_size). Настройка, которая задается при создании таблицы, имеет более высокий приоритет, чем глобальная.max_partitions_to_read
— Ограничивает максимальное число партиций для чтения в одном запросе. Также возможно указать настройку max_partitions_to_read в глобальных настройках.
Пример задания секций
ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate, intHash32(UserID)) SAMPLE BY intHash32(UserID) SETTINGS index_granularity=8192
В примере мы устанавливаем партиционирование по месяцам.
Также мы задаем выражение для сэмплирования в виде хэша по идентификатору посетителя. Это позволяет псевдослучайным образом перемешать данные в таблице для каждого CounterID
и EventDate
. Если при выборке данных задать секцию SAMPLE, то ClickHouse вернёт равномерно-псевдослучайную выборку данных для подмножества посетителей.
index_granularity
можно было не указывать, поскольку 8192 — это значение по умолчанию.
Устаревший способ создания таблицы
Не используйте этот способ в новых проектах и по возможности переведите старые проекты на способ, описанный выше.
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE [=] MergeTree(date-column [, sampling_expression], (primary, key), index_granularity)
Параметры MergeTree()
date-column
— имя столбца с типом Date. На основе этого столбца ClickHouse автоматически создаёт партиции по месяцам. Имена партиций имеют формат"YYYYMM"
.sampling_expression
— выражение для сэмплирования.(primary, key)
— первичный ключ. Тип — Tuple()index_granularity
— гранулярность индекса. Число строк данных между «засечками» индекса. Для большинства задач подходит значение 8192.
Пример
MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)
Движок MergeTree
сконфигурирован таким же образом, как и в примере выше для основного способа конфигурирования движка.
Хранение данных
Таблица состоит из кусков данных (data parts), отсортированных по первичному ключу.
При вставке в таблицу создаются отдельные куски данных, каждый из которых лексикографически отсортирован по первичному ключу. Например, если первичный ключ — (CounterID, Date)
, то данные в куске будут лежать в порядке CounterID
, а для каждого CounterID
в порядке Date
.
Данные, относящиеся к разным партициям, разбиваются на разные куски. В фоновом режиме ClickHouse выполняет слияния (merge) кусков данных для более эффективного хранения. Куски, относящиеся к разным партициям не объединяются. Механизм слияния не гарантирует, что все строки с одинаковым первичным ключом окажутся в одном куске.
Куски данных могут храниться в формате 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
в том случае, когда размер единственной строки в грануле превышает значение настройки. В этом случае, размер гранулы равен размеру строки.