MergeTree и другие движки семейства MergeTree (например, ReplacingMergeTree, AggregatingMergeTree) — наиболее широко используемые и самые надёжные движки таблиц в ClickHouse.
Движки таблиц семейства MergeTree рассчитаны на высокую скорость приёма данных и очень большие объёмы данных.
Операции вставки создают части таблицы, которые затем фоновый процесс объединяет с другими частями таблицы.
Основные возможности движков таблиц семейства MergeTree.
- Первичный ключ таблицы определяет порядок сортировки внутри каждой части таблицы (кластерный индекс). При этом первичный ключ ссылается не на отдельные строки, а на блоки по 8192 строк, называемые гранулами. Благодаря этому первичные ключи даже для очень больших наборов данных остаются достаточно компактными, чтобы помещаться в оперативной памяти, и при этом обеспечивают быстрый доступ к данным на диске.
- Таблицы можно разбивать на партиции с помощью произвольного выражения партиционирования. Отсечение партиций позволяет не читать партиции, если это допускает запрос.
- Данные могут реплицироваться между несколькими узлами кластера для высокой доступности, переключения при сбоях и обновлений без простоя. См. Репликация данных.
-
Движки таблиц
MergeTreeподдерживают различные виды статистики и методы сэмплирования, помогающие оптимизации запросов.
Несмотря на похожее название, движок Merge отличается от движков
*MergeTree.Создание таблиц
Секции запроса
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 включена, в команды CREATE TABLE неявно добавляется ORDER BY (). См. Выбор первичного ключа.
PARTITION BY
PARTITION BY — ключ партиционирования. Необязателен. В большинстве случаев ключ партиционирования не нужен, а если партиционирование всё же требуется, то, как правило, ключ партиционирования с детализацией мельче месяца тоже не нужен. Партиционирование не ускоряет запросы (в отличие от выражения ORDER BY). Никогда не используйте слишком мелкое партиционирование. Не разбивайте данные на партиции по идентификаторам или именам клиентов (вместо этого сделайте идентификатор или имя клиента первым столбцом в выражении ORDER BY).
Для партиционирования по месяцам используйте выражение toYYYYMM(date_column), где date_column — столбец с датой типа Date. Имена партиций здесь имеют формат "YYYYMM".
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 для столбцов и таблиц
НАСТРОЙКИ
CounterID и EventDate. Если при выборке данных указать предложение SAMPLE, ClickHouse вернёт равномерную псевдослучайную выборку данных для подмножества пользователей.
Настройку index_granularity можно опустить, поскольку 8192 — значение по умолчанию.
Хранение данных
(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. В этом случае имеет смысл указать ключ сортировки, который отличается от первичного ключа.
SELECT.
Вы можете создать таблицу без первичного ключа, используя синтаксис ORDER BY tuple(). В этом случае ClickHouse хранит данные в порядке их вставки. Если вы хотите сохранить порядок данных при вставке с помощью запросов INSERT ... SELECT, установите max_insert_threads = 1.
Чтобы выбирать данные в исходном порядке, используйте однопоточные запросы SELECT.
Выбор первичного ключа, отличающегося от ключа сортировки
GROUP BY и фильтрацией по измерениям. Поскольку SummingMergeTree и AggregatingMergeTree агрегируют строки с одинаковым значением ключа сортировки, логично включить в него все измерения. В результате выражение ключа представляет собой длинный список столбцов, и этот список приходится часто обновлять по мере добавления новых измерений.
В этом случае имеет смысл оставить в первичном ключе только несколько столбцов, которые обеспечат эффективное сканирование диапазонов, а остальные столбцы измерений добавить в кортеж ключа сортировки.
ALTER ключа сортировки — лёгкая операция, потому что, когда новый столбец одновременно добавляется в таблицу и в ключ сортировки, существующие части данных не нужно изменять. Поскольку старый ключ сортировки является префиксом нового ключа сортировки и в только что добавленном столбце ещё нет данных, в момент изменения таблицы данные уже отсортированы и по старому, и по новому ключу сортировки.
Использование индексов и партиций в запросах
SELECT ClickHouse анализирует, можно ли использовать индекс. Индекс может быть использован, если в условии WHERE/PREWHERE есть выражение (либо как один из элементов конъюнкции, либо целиком), представляющее собой операцию сравнения на равенство или неравенство, либо если в нём есть IN или LIKE с фиксированным префиксом для столбцов или выражений, входящих в первичный ключ или ключ партиционирования, а также для некоторых частично повторяющихся функций от этих столбцов или логических связей этих выражений.
Таким образом, можно быстро выполнять запросы по одному или нескольким диапазонам первичного ключа. В этом примере запросы будут выполняться быстро для конкретного тега отслеживания, для конкретного тега и диапазона дат, для конкретного тега и даты, для нескольких тегов в диапазоне дат и так далее.
Давайте рассмотрим движок, настроенный следующим образом:
Использование индекса для детерминированных выражений в первичных ключах
length(), toDate(), lower(), left(), cityHash64(), toUUID(); в отличие от now() или rand()). Если первичный ключ содержит детерминированные выражения, ClickHouse может применить их к константным значениям из запроса и использовать результат для построения условий по индексу первичного ключа. Это позволяет пропускать данные для таких предикатов, как =, IN и has.
Распространённый сценарий — сделать первичный ключ компактным (например, хранить хеш вместо длинной String), при этом сохранив возможность использовать индекс для предикатов по исходному столбцу.
Пример детерминированного (но не инъективного) первичного ключа:
length('alice') (и другие константы) один раз и использует значения длины, чтобы сузить диапазоны в индексе первичного ключа. Поскольку длина строки неинъективна, разные строки user_id могут иметь одинаковую длину, поэтому индекс может считывать лишние гранулы (ложноположительные срабатывания). При этом результат остаётся корректным, поскольку после чтения всё равно применяется исходный предикат (user_id = ..., IN и т. д.).
Если детерминированное выражение также инъективно (разные входные данные не могут давать один и тот же результат для используемых типов аргументов), ClickHouse также может эффективно использовать индекс для отрицательных форм: !=, NOT IN и NOT has(...). Например, reverse(p) и hex(p) инъективны для String.
Пример инъективного первичного ключа:
Использование индекса для частично-монотонных первичных ключей
Индексы пропуска данных
CREATE.
*MergeTree можно задавать индексы пропуска данных.
Эти индексы агрегируют информацию о заданном выражении по блокам, состоящим из granularity_value гранул (размер гранулы задаётся настройкой index_granularity в движке таблицы). Затем эти агрегаты используются в запросах SELECT, чтобы уменьшить объём данных, считываемых с диска, пропуская большие блоки данных, для которых условие where не может быть выполнено.
Предложение GRANULARITY можно опустить; значение granularity_value по умолчанию равно 1.
Пример
Типы индексов пропуска данных
MergeTree поддерживает следующие типы индексов пропуска данных.
Дополнительные сведения об использовании индексов пропуска данных для оптимизации производительности
см. в статье “Принципы работы индексов пропуска данных в ClickHouse”.
- индекс
MinMax - индекс
Set - индекс
bloom_filter - индекс
ngrambf_v1(Устарело) - индекс
tokenbf_v1(Устарело) - индекс
text - индекс
vector_similarity
Индекс пропуска данных MinMax
tuple, для каждого элемента кортежа хранятся минимальное и максимальное значения.)
Syntax
Set
max_rows уникальных значений указанного выражения.
max_rows = 0 означает “хранить все уникальные значения”.
Syntax
Bloom-фильтр
Syntax
false_positive_rate может принимать значение от 0 до 1 (по умолчанию — 0.025) и задаёт вероятность ложноположительного срабатывания (что увеличивает объём читаемых данных).
Поддерживаются следующие типы данных:
(U)Int*Float*EnumDateDateTimeStringFixedStringArrayLowCardinalityNullableUUIDMap
Тип данных JSON: индексация JSON-путейДля типа данных
JSON можно создать bloom-фильтр индекс по набору путей с помощью функции JSONAllPaths. Это позволяет пропускать гранулы, в которых отсутствует запрашиваемый JSON-путь. Подробности см. в разделе Индексы пропуска данных для JSON.N-граммный bloom-фильтр (Устарело)
Начиная с ClickHouse 26.2, когда индекс
text получил статус General Availability (GA), индекс ngrambf_v1 больше не рекомендуется использовать для полнотекстового поиска.Подробности см. на странице “Полнотекстовый поиск с помощью текстовых индексов”.Syntax
Этот индекс работает только со следующими типами данных:
Чтобы оценить параметры
ngrambf_v1, можно использовать следующие пользовательские функции (UDF).
UDFs for ngrambf_v1
total_number_of_all_gramsprobability_of_false_positives
4300 n-грамм, и вы ожидаете, что вероятность ложноположительных срабатываний будет меньше 0.0001.
Остальные параметры затем можно оценить, выполнив следующие запросы:
Токенный bloom-фильтр
Начиная с версии ClickHouse 26.2, в которой индекс
text стал общедоступным (GA), индекс tokenbf_v1 больше не рекомендуется для полнотекстового поиска.Подробнее см. на странице “Полнотекстовый поиск с помощью текстовых индексов”.Syntax
Bloom-фильтр для sparse grams
ngrambf_v1, но использует токены sparse grams вместо n-грамм.
Syntax
Текстовый индекс
Векторное сходство
Поддержка функций
WHERE содержат вызовы функций, работающих со столбцами. Если столбец входит в индекс, ClickHouse пытается использовать этот индекс при выполнении этих функций. ClickHouse поддерживает разные подмножества функций для использования индексов.
Индексы типа set могут использоваться всеми функциями. Другие типы индексов поддерживаются следующим образом:
Функции с константным аргументом, который меньше размера n-граммы, не могут использоваться
ngrambf_v1 для оптимизации запросов.
(*) Чтобы hasTokenCaseInsensitive и hasTokenCaseInsensitiveOrNull работали эффективно, индекс tokenbf_v1 должен быть создан по данным, приведённым к нижнему регистру, например INDEX idx (lower(str_col)) TYPE tokenbf_v1(512, 3, 0).
Bloom-фильтры могут давать ложноположительные срабатывания, поэтому индексы
ngrambf_v1, tokenbf_v1, sparse_grams и bloom_filter не могут использоваться для оптимизации запросов, в которых ожидается, что результат функции будет ложным.Например:- Могут быть оптимизированы:
s LIKE '%test%'NOT s NOT LIKE '%test%'s = 1NOT s != 1startsWith(s, 'test')
- Не могут быть оптимизированы:
NOT s LIKE '%test%'s NOT LIKE '%test%'NOT s = 1s != 1NOT startsWith(s, 'test')
Проекции
При использовании проекций следует также учитывать настройку force_optimize_projection.
SELECT с модификатором FINAL.
Запрос проекции
Индексы проекций
_part_offset, то есть SELECT _part_offset ORDER BY <index_expr>.
Синтаксис
Типы индексов
- basic: эквивалентен обычному индексу MergeTree по выражению.
Хранение проекций
MergeTree. Эта таблица создается на основе запроса, задающего определение проекции. Если есть секция GROUP BY, нижележащий движок хранения становится AggregatingMergeTree, а все агрегатные функции преобразуются в AggregateFunction. Если есть секция ORDER BY, таблица MergeTree использует ее как выражение первичного ключа. При слиянии часть проекции объединяется с помощью процедуры слияния соответствующего хранилища. Контрольная сумма части родительской таблицы объединяется с контрольной суммой части проекции. Остальные задачи обслуживания аналогичны индексам пропуска.
Анализ запроса
- Проверьте, можно ли использовать проекцию для выполнения данного запроса, то есть даст ли она тот же результат, что и запрос к базовой таблице.
- Выберите наилучший подходящий вариант, для которого требуется прочитать наименьшее число гранул.
- Конвейер запроса, использующий проекции, будет отличаться от того, который использует исходные части. Если в некоторых частях проекция отсутствует, можно добавить конвейер, который построит её на лету.
Одновременный доступ к данным
TTL для столбцов и таблиц
TTL можно задать для всей таблицы и для каждого отдельного столбца. TTL на уровне таблицы также может задавать логику автоматического перемещения данных между дисками и томами или повторного сжатия частей, для которых срок хранения всех данных уже истёк.
Выражения должны иметь тип данных Date, Date32, DateTime или DateTime64.
Синтаксис
Задание time-to-live для столбца:
interval, используйте операторы для работы с временными интервалами, например:
TTL для столбца
TTL нельзя использовать для столбцов ключа.
Примеры
Создание таблицы с TTL:
Добавление TTL к столбцу существующей таблицы
Изменение 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
Типы дисков
s3для S3 и MinIOgcsдля GCSblob_storage_diskдля Azure Blob Storagehdfsдля HDFSwebдля доступа только для чтения через вебcacheдля локального кэшированияs3_plainдля резервных копий в S3s3_plain_rewritableдля неизменяемых нереплицируемых таблиц в S3
Использование нескольких блочных устройств для хранения данных
Введение
MergeTree могут хранить данные на нескольких блочных устройствах. Например, это может быть полезно, когда данные определённой таблицы естественным образом делятся на «горячие» и «холодные». Самые свежие данные запрашиваются регулярно, но занимают сравнительно немного места. Напротив, исторические данные с длинным хвостом запрашиваются редко. Если доступно несколько дисков, «горячие» данные можно размещать на быстрых дисках (например, NVMe SSD или в памяти), а «холодные» — на относительно медленных (например, HDD).
Это применимо ко всем типам дисков, включая S3 и другие диски объектного хранилища. Например, вы можете распределить данные по нескольким S3 бакетам в пределах одного тома или создать многоуровневые политики, которые перемещают данные с локальных дисков в S3. Подробнее см. в разделе Использование S3-дисков с несколькими томами.
Часть — это минимальная перемещаемая единица для таблиц с движком MergeTree. Данные, относящиеся к одной части, хранятся на одном диске. Части могут перемещаться между дисками в фоновом режиме (в соответствии с пользовательскими настройками), а также с помощью запросов ALTER.
Термины
- Диск — блочное устройство, смонтированное в файловую систему.
- Диск по умолчанию — диск, соответствующий пути, указанному в настройке сервера path.
- Том — упорядоченный набор одинаковых дисков (аналогично JBOD).
- Политика хранения — набор томов и правил перемещения данных между ними.
storage_policy таблиц семейства движков MergeTree.
Конфигурация
<storage_configuration> в одном из файлов каталога config.d.
Структура конфигурации:
<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 move при INSERT части. По умолчанию (если параметр включен), если вставляется часть, которая уже подпадает под правило TTL move, она сразу записывается на том/диск, указанный в правиле перемещения. Это может существенно замедлить вставку, если том/диск пункта назначения медленный (например, S3). Если параметр отключен, уже подпадающая под TTL часть записывается на том по умолчанию, а затем сразу перемещается на TTL-том.load_balancing- политика балансировки дисков:round_robinилиleast_used.least_used_ttl_ms- настраивает тайм-аут (в миллисекундах) обновления доступного пространства на всех дисках (0- обновлять всегда,-1- никогда не обновлять, значение по умолчанию —60000). Обратите внимание: если диск может использоваться только ClickHouse и не подвержен изменению размера файловой системы в режиме online, можно использовать-1; во всех остальных случаях это не рекомендуется, так как со временем это приведет к некорректному распределению пространства.prefer_not_to_merge— этот параметр не следует использовать. Он отключает слияние частей на этом томе (это вредно и приводит к снижению производительности). Когда этот параметр включен (не делайте этого), слияние данных на этом томе запрещено (а это плохо). Это позволяет (хотя вам это не нужно) контролировать (если вам хочется что-то контролировать, вы, скорее всего, делаете что-то не так), как ClickHouse работает с медленными дисками (но ClickHouse знает лучше, поэтому, пожалуйста, не используйте этот параметр).volume_priority— определяет приоритет (порядок), в котором заполняются тома. Меньшее значение означает более высокий приоритет. Значения параметра должны быть натуральными числами и в совокупности покрывать диапазон от 1 до N (где N соответствует наименьшему приоритету) без пропуска чисел.- Если помечены все тома, приоритет назначается им в указанном порядке.
- Если помечены только некоторые тома, тома без метки получают наименьший приоритет, а между собой упорядочиваются в том порядке, в котором они заданы в config.
- Если не помечен ни один том, их приоритет определяется порядком, в котором они объявлены в конфигурации.
- Два тома не могут иметь одинаковое значение приоритета.
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.
Использование внешнего хранилища для хранения данных
S3, AzureBlobStorage и HDFS, используя диски типов s3, azure_blob_storage и hdfs соответственно. Подробнее см. в разделе настройка параметров внешнего хранилища.
Пример использования S3 в качестве внешнего хранилища с диском типа s3.
Конфигурация:
Использование S3-дисков с несколькими томами
При использовании
use_environment_credentials для аутентификации в S3 учетные данные окружения (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) используются всеми S3-дисками совместно. Использовать разные учетные данные окружения для разных дисков нельзя. Если для каждого S3-диска нужны свои учетные данные, вместо этого укажите явные настройки access_key_id и secret_access_key для каждого диска.table_disk = true с локальным для таблицы диском). См. refresh_parts_interval and table_disk.
конфигурация кэшаВ версиях ClickHouse с 22.3 по 22.7 используется другая конфигурация кэша; если вы используете одну из этих версий, см. раздел использование локального кэша.
Виртуальные столбцы
_part— Имя части._part_index— Последовательный индекс части в результате запроса._part_starting_offset— Накопительный номер начальной строки части в результате запроса._part_offset— Номер строки в части._part_granule_offset— Номер гранулы в части._partition_id— Имя партиции._part_uuid— Уникальный идентификатор части (если включена настройка MergeTreeassign_part_uuids)._part_data_version— Версия данных части (минимальный номер блока или версия мутации)._partition_value— Значения (кортеж) выраженияpartition by._sample_factor— Коэффициент выборки (из запроса)._block_number— Исходный номер блока для строки, назначенный при вставке; сохраняется при слияниях, когда включена настройкаenable_block_number_column._block_offset— Исходный номер строки в блоке, назначенный при вставке; сохраняется при слияниях, когда включена настройкаenable_block_offset_column._disk_name— Имя диска, используемого для хранения.
Статистика столбцов
CREATE для таблиц семейства *MergeTree*:
ALTER:
set use_statistics = 1.
Отсечение частей на основе статистики
use_statistics_for_part_pruning, для отсечения частей можно использовать статистику.
В настоящее время отсечение частей поддерживается только статистикой basic (и устаревшей статистикой minmax). Когда такая статистика определена для столбца, ClickHouse отслеживает минимальное и максимальное значения этого столбца в каждой части.
Отсечение частей позволяет пропускать чтение целых частей данных, если условие фильтра запроса не может соответствовать ни одной строке в такой части.
Пример:
Доступные типы статистики столбцов
-
basicКомпактный набор однозначных сводных характеристик, вычисляемых по столбцу. В зависимости от типа столбца заполняются следующие компоненты:-
для любого столбца, значения которого представлены числами (целые числа, числа с плавающей точкой,
Decimal*,Date*,DateTime*,Enum*,IPv4, …): минимальное и максимальное значения, которые позволяют оценивать селективность фильтра диапазона и выполнять отсечение частей; -
для столбцов
StringиFixedString: суммарная длина в байтах всех значений, отличных отNULL(на её основе можно вычислить среднюю длину строки); -
для столбцов
NullableиLowCardinality(Nullable): количество значенийNULL, которое оптимизатор использует, чтобы исключать строки сNULLиз оценок селективности. Одна статистикаbasicможет одновременно заполнять несколько таких компонентов — например, для столбцаNullable(UInt32)она отслеживает и числовые минимум/максимум, и количество значенийNULL. По сравнению сminmax,basicдополнительно работает со столбцамиString/FixedStringи может быть объявлена для обёртокNullableтипов вродеUUIDилиIPv6исключительно для отслеживания количества значенийNULL.
-
для любого столбца, значения которого представлены числами (целые числа, числа с плавающей точкой,
-
minmax(устарело)
Статистика
minmax устарела, и её больше нельзя создавать (CREATE TABLE ... STATISTICS(minmax) и ALTER TABLE ... ADD/MODIFY STATISTICS ... TYPE minmax возвращают ошибку). Существующие таблицы и части со статистикой minmax продолжают работать. Вместо неё используйте статистику basic.tdigest
-
uniqСкетчи BJKST, которые позволяют оценить количество различных значений в столбце. Внутри используетсяuniq. -
uniq_v2Аналогичноuniq, но внутри используетсяuniqCombined(12)(вариант HyperLogLog). Потребляет меньше памяти, чемuniq, и может строиться быстрее. -
countmin
Поддерживаемые типы данных
Для всего перечисленного выше также поддерживаются обертки
Nullable и LowCardinality(Nullable) указанных типов. Basic также можно объявлять для оберток Nullable типов вроде UUID или IPv6 исключительно для отслеживания количества NULL.
Поддерживаемые операции
Для
basic в столбцах String / FixedString статистика учитывает только суммарную
длину в байтах значений, отличных от NULL (используется для оценки средней длины строк), и количество значений NULL;
фильтры диапазона и отсечение частей на её основе не применяются.
Настройки на уровне столбцов
max_compress_block_size— Максимальный размер блоков несжатых данных перед сжатием при записи в таблицу.min_compress_block_size— Минимальный размер блоков несжатых данных, необходимый для сжатия перед записью следующей метки.
- Удалить
SETTINGSиз определения столбца:
- Измените параметр:
- Сбрасывает одну или несколько настроек, а также удаляет объявление настройки из выражения столбца в CREATE-запросе таблицы.