Пользовательский ключ разделения
В большинстве случаев вам не нужен ключ разделения, а в большинстве других случаев вам не нужен ключ разделения более детализированный, чем по месяцам.
Никогда не используйте слишком детализированное разделение. Не разделяйте ваши данные по идентификаторам клиентов или именам. Вместо этого укажите идентификатор клиента или имя в первом столбце выражения ORDER BY.
Разделение доступно для таблиц семейства MergeTree, включая реплицированные таблицы и материализованные представления.
Разделение — это логическое объединение записей в таблице по заданному критерию. Вы можете установить разделение по произвольным критериям, таким как месяц, день или тип события. Каждое разделение хранится отдельно, чтобы упростить манипуляции с этими данными. При доступе к данным ClickHouse использует наименьший набор разделов. Разделения улучшают производительность запросов, содержащих ключ разделения, потому что ClickHouse будет фильтровать по этому разделению перед выбором частей и гранул внутри него.
Разделение указывается в предложении PARTITION BY expr
при создании таблицы. Ключ разделения может быть любым выражением из столбцов таблицы. Например, чтобы указать разделение по месяцам, используйте выражение toYYYYMM(date_column)
:
Ключ разделения также может быть кортежем выражений (аналогично первичному ключу). Например:
В этом примере мы устанавливаем разделение по типам событий, которые произошли в текущую неделю.
По умолчанию разделение по плавающей точке не поддерживается. Чтобы использовать его, включите настройку allow_floating_point_partition_key.
При вставке новых данных в таблицу эти данные хранятся как отдельная часть (чанк), отсортированная по первичному ключу. Через 10-15 минут после вставки части одного и того же разделения сливаются в целую часть.
Слияние работает только для частей данных, которые имеют одинаковое значение для выражения разделения. Это означает, что не следует создавать чрезмерно детализированные разделения (более чем около тысячи разделений). В противном случае запрос SELECT
выполняется плохо из-за неоправданно большого числа файлов в файловой системе и открытых дескрипторов файлов.
Используйте таблицу system.parts, чтобы просмотреть части таблицы и разделы. Например, предположим, что у нас есть таблица visits
с разделением по месяцам. Выполним запрос SELECT
к таблице system.parts
:
Столбец partition
содержит названия разделов. В этом примере есть два раздела: 201901
и 201902
. Вы можете использовать это значение столбца, чтобы указать имя раздела в запросах ALTER ... PARTITION.
Столбец name
содержит названия частей данных раздела. Вы можете использовать этот столбец, чтобы указать имя части в запросе ALTER ATTACH PART.
Разберем название части: 201901_1_9_2_11
:
201901
— это имя раздела.1
— это минимальный номер блока данных.9
— это максимальный номер блока данных.2
— это уровень чанка (глубина слияния, из которой он сформирован).11
— это версия мутации (если часть мутировала).
Части таблиц старого типа имеют название: 20190117_20190123_2_2_0
(минимальная дата - максимальная дата - минимальный номер блока - максимальный номер блока - уровень).
Столбец active
показывает статус части. 1
— активна; 0
— неактивна. Неактивные части, например, это исходные части, оставшиеся после слияния в более крупную часть. Поврежденные части данных также отображаются как неактивные.
Как видно из примера, существует несколько раздельных частей одного и того же раздела (например, 201901_1_3_1
и 201901_1_9_2
). Это означает, что эти части еще не слиты. ClickHouse периодически сливает вставленные части данных, примерно через 15 минут после вставки. Кроме того, вы можете выполнить несогласованное слияние, используя запрос OPTIMIZE. Пример:
Неактивные части будут удалены примерно через 10 минут после слияния.
Другой способ просмотреть набор частей и разделов - это перейти в директорию таблицы: /var/lib/clickhouse/data/<database>/<table>/
. Например:
Папки '201901_1_1_0', '201901_1_7_1' и так далее — это директории частей. Каждая часть относится к соответствующему разделу и содержит данные только за определенный месяц (таблица в этом примере имеет разделение по месяцам).
Директория detached
содержит части, которые были отделены от таблицы с помощью запроса DETACH. Поврежденные части также перемещаются в эту директорию, вместо того чтобы быть удаленными. Сервер не использует части из директории detached
. Вы можете добавлять, удалять или изменять данные в этой директории в любое время — сервер не узнает об этом, пока вы не выполните запрос ATTACH.
Обратите внимание, что на работающем сервере вы не можете вручную изменять набор частей или их данные в файловой системе, так как сервер об этом не узнает. Для нереплицированных таблиц вы можете делать это, когда сервер остановлен, но этого не рекомендуется. Для реплицированных таблиц набор частей не может быть изменен в любом случае.
ClickHouse позволяет вам выполнять операции с разделами: удалять их, копировать из одной таблицы в другую или создавать резервные копии. Смотрите список всех операций в разделе Манипуляции с разделами и частями.
Оптимизация GROUP BY с использованием ключа разделения
Для некоторых комбинаций ключа разделения таблицы и ключа группировки запроса может быть возможным выполнять агрегацию для каждого раздела независимо. Тогда нам не придется сливать частично агрегированные данные из всех потоков выполнения в конце, потому что у нас есть гарантия, что каждое значение ключа группировки не может появляться в рабочих наборах двух разных потоков.
Типичный пример:
Производительность такого запроса сильно зависит от структуры таблицы. Поэтому оптимизация не включена по умолчанию.
Ключевые факторы для хорошей производительности:
- количество разделов, участвующих в запросе, должно быть достаточно большим (более
max_threads / 2
), иначе запрос будет недостаточно загружать машину - разделы не должны быть слишком маленькими, чтобы пакетная обработка не перешла в обработку строк по одной
- разделы должны быть сопоставимы по размеру, чтобы все потоки выполняли примерно одинаковое количество работы
Рекомендуется применять какую-либо хеш-функцию к столбцам в предложении partition by
, чтобы равномерно распределить данные между разделами.
Соответствующие настройки:
allow_aggregate_partitions_independently
- управляет включением использования оптимизацииforce_aggregate_partitions_independently
- принудительно включает ее использование, когда это применимо с точки зрения корректности, но отключается внутренней логикой, которая оценивает ее целесообразностьmax_number_of_partitions_for_independent_aggregation
- жесткий предел на максимальное количество разделов, которое может иметь таблица