151просмотров
76.3%от подписчиков
30 декабря 2025 г.
Score: 166
Всем привет!
Сегодня углубимся в детали ключей, партиций и дополнительных индексов — всё, что нужно для максимальной производительности. Order Key vs Primary Key
Ранее я упоминал: если не указать PRIMARY KEY явно, ClickHouse использует ключи сортировки (ORDER BY) как первичные ключи. Но вы можете задать PRIMARY KEY отдельно — он должен быть подмножеством ORDER BY.
CREATE TABLE ecommerce_events
(
customer_id UInt32,
action_type String,
event_date Date,
product_id UInt32,
session_token String
)
ENGINE = MergeTree
PRIMARY KEY (event_date, customer_id) -- Для индекса
ORDER BY (event_date, customer_id, action_type, product_id); -- Для сортировки
Что здесь происходит:
— event_date и customer_id — используются и для индекса, и для сортировки
— action_type и product_id — только для сортировки (помогают в ORDER BY запросах)
— session_token — вообще не участвует в сортировке
Зачем это нужно?
Если вы часто используете ORDER BY в запросах, включение этих столбцов в ORDER BY таблицы ускоряет выполнение — ClickHouse не будет тратить время на дополнительную сортировку. Partition Key — разбиваем данные
Партиционирование в ClickHouse — это логическое разделение данных на части. По умолчанию все данные в одной партиции, но вы можете изменить это:
CREATE TABLE server_logs_partitioned
( server_id UInt16, log_message String, log_timestamp DateTime
)
ENGINE = MergeTree
PARTITION BY toDate(log_timestamp) ORDER BY (log_timestamp, server_id);
Что даёт партиционирование:
— Быстрое удаление старых данных — можно удалить целую партицию
— Оптимизация запросов — ClickHouse читает только нужные партиции
— Управление данными — перемещение, копирование партиций
Важно:
Партиционирование — не для ускорения запросов! Skip Index — когда ORDER BY не помогает:
Что делать, если нужно искать по столбцу, которого нет в ORDER BY? Например, найти все логи с определённым типом ошибки:
-- Добавляем ngram bloom filter для поиска подстрок
ALTER TABLE server_logs ADD INDEX error_idx log_message TYPE ngrambf_v1(3, 256, 2, 0) GRANULARITY 2; -- Применяем индекс к существующим данным
ALTER TABLE server_logs MATERIALIZE INDEX error_idx;
Типы Skip Index:
— bloom_filter — для точного совпадения строк
— minmax — для диапазонов (даты, числа)
— ngrambf_v1 — для поиска подстрок
— tokenbf_v1 — для поиска отдельных слов Case Study: оптимизация метрик IoT-устройств
Допустим, у нас есть данные с 50K IoT-устройств. Мы хотим:
1. Быстро искать метрики по времени и device_id
2. Фильтровать по типу сенсора
3. Искать по статусу ошибки
CREATE TABLE iot_metrics
( device_id UInt32, sensor_type String, metric_time DateTime, value Float32, error_flag UInt8
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(metric_time) -- Для архивации старых данных
PRIMARY KEY (metric_time, device_id) -- Основные фильтры
ORDER BY (metric_time, device_id, sensor_type) -- Сортировка + фильтры
SETTINGS index_granularity = 8192; -- Добавляем skip index для поиска ошибок
ALTER TABLE iot_metrics ADD INDEX error_sk error_flag TYPE minmax GRANULARITY 1;
Результат:
— По времени+устройству — мгновенно (первичный ключ)
— По типу сенсора — быстро (часть ORDER BY)
— По ошибкам — эффективно (skip index)
— Архивация данных — DROP PARTITION для старых месяцев Главные правила проектирования:
1.ORDER BY — сначала столбцы для самых частых фильтров
2.PRIMARY KEY — подмножество ORDER BY (обычно первые 2-3 столбца)
3.PARTITION BY — только для управления данными, не для скорости
4.Skip Index — для столбцов вне ORDER BY, но с фильтрами Что дальше?
В следующем посте мы проведём детальное сравнение производительности ClickHouse и MySQL на практических примерах #ClickHouse #БазыДанных #Производительность #Индексы #Партиционирование #Оптимизация #MySQL