Индексы и сжатие - Индексы

This commit is contained in:
Bonifatsiy
2026-05-04 08:09:54 +04:00
parent 209cce48b2
commit 1de11c1d5e
@@ -0,0 +1,166 @@
-- Индексы и сжатие - Индексы --
-- #1
/*
3. Посмотри, сколько блоков было пропущено (в `system.query_log`, `rows_read`, `rows`).
Не посмотрю, так как нет доступа system.query_log, rows_read, rows (ACCESS_DENIED)
4. Что будет, если `ORDER BY log_id`, а не `ts`?
ORDER BY log_id → данные физически отсортированы по log_id. Значения ts расположены хаотично относительно физической сортировки.
Индекс minmax по ts будет почти бесполезен. Minmax индекс будет иметь широкие диапазоны
*/
DROP TABLE IF EXISTS dsolovianov.logs ON CLUSTER clickhouse_cluster SYNC;
CREATE TABLE dsolovianov.logs
ON CLUSTER clickhouse_cluster
(
log_id UInt64,
ts DateTime
)
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/dsolovianov/logs',
'{replica}'
)
ORDER BY ts
PARTITION BY toYYYYMM(ts)
PRIMARY KEY (ts);
INSERT INTO dsolovianov.logs (log_id, ts) VALUES
(1, '2024-06-01 10:00:00'),
(2, '2024-06-01 11:00:00'),
(3, '2024-06-02 12:00:00'),
(4, '2024-06-03 13:00:00'),
(5, '2024-06-04 14:00:00');
-- 1. Добавляем minmax индекс:
ALTER TABLE dsolovianov.logs ADD INDEX idx_ts ts TYPE minmax GRANULARITY 2;
-- 2. Сделай запрос: `SELECT * FROM logs WHERE ts BETWEEN '2024-06-02' AND '2024-06-03'`
SELECT *
FROM dsolovianov.logs
WHERE ts
BETWEEN '2024-06-02' AND '2024-06-03';
-- Раз нет доступа, но можно предположить, что вот такой запрос сработает:
SELECT query, read_rows, result_rows
FROM system.query_log
WHERE query LIKE '%logs%'
ORDER BY event_time DESC
LIMIT 1;
-- #2
/*
1. Создай таблицу с `ORDER BY id`, добавь индекс:
```sql
ALTER TABLE clicks ADD INDEX idx_country country TYPE set(1000) GRANULARITY 2;
```
3. Посмотри `EXPLAIN` — индекс используется?
Данные отсортированы по id, а не по country. Значения country распределены хаотически относительно физического порядка.
4. Как будет вести себя индекс, если `country` имеет 10M уникальных значений?
Будет создано 10M партиций, что убьёт производительность.
**/
DROP TABLE IF EXISTS dsolovianov.clicks ON CLUSTER clickhouse_cluster SYNC;
CREATE TABLE dsolovianov.clicks
ON CLUSTER clickhouse_cluster
(
id UInt64,
country String
)
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/dsolovianov/clicks',
'{replica}'
)
ORDER BY id
PARTITION BY country
PRIMARY KEY (id);
INSERT INTO dsolovianov.clicks (id, country) VALUES
(1, 'RU'),
(2, 'US'),
(3, 'RU'),
(4, 'DE'),
(5, 'RU');
ALTER TABLE dsolovianov.clicks ON CLUSTER clickhouse_cluster
ADD INDEX idx_country country TYPE set(1000) GRANULARITY 2;
-- 2. Выполни запрос `SELECT * FROM clicks WHERE country = 'RU'`.
EXPLAIN indexes = 1
SELECT * FROM dsolovianov.clicks WHERE country = 'RU';
EXPLAIN
SELECT * FROM dsolovianov.clicks WHERE country = 'RU';
/*
Expression ((Project names + Projection))
Expression ((WHERE + Change column names to column identifiers))
ReadFromMergeTree (dsolovianov.clicks)
Indexes:
MinMax
Keys:
country
Condition: (country in ['RU', 'RU'])
Parts: 1/3
Granules: 1/3
Partition
Keys:
country
Condition: (country in ['RU', 'RU'])
Parts: 1/1
Granules: 1/1
PrimaryKey
Condition: true
Parts: 1/1
Granules: 1/1
Skip
Name: idx_country
Description: set GRANULARITY 2
Parts: 1/1
Granules: 1/1
Ranges: 1
*/
-- #3
DROP TABLE IF EXISTS dsolovianov.users ON CLUSTER clickhouse_cluster SYNC;
CREATE TABLE dsolovianov.users
ON CLUSTER clickhouse_cluster
(
id UInt64,
email String
)
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/dsolovianov/users',
'{replica}'
)
ORDER BY id
PRIMARY KEY (id);
INSERT INTO dsolovianov.users (id, email) VALUES
(1, 'alice@mail.com'),
(2, 'bob@mail.com'),
(3, 'charlie@mail.com'),
(4, 'dave@mail.com'),
(5, 'eve@example.com');
ALTER TABLE dsolovianov.users ADD INDEX idx_email email TYPE bloom_filter(0.01) GRANULARITY 2;
EXPLAIN indexes = 1
SELECT * FROM users WHERE email = 'alice@mail.com';
-- Bloom filter может пропустить некоторые гранулы, но не все, ибо данные не отсортированы по email и индексные блоки покрывают случайные email'ы
EXPLAIN indexes = 1
SELECT * FROM users WHERE email LIKE '%mail%';
EXPLAIN indexes = 1
SELECT * FROM users WHERE email LIKE 'alice%';
/*
Bloom filter не поддерживает частичные совпадения (LIKE '..%', LIKE '%..', LIKE '%..%'). Из-за этого ClickHouse не может пропустить гранулы.
Клику становится сложно вычислить хэш для проверки, если подходящих значений по LIKE будет больше одного. Нет гарантии, что данные на выходе будут корректные.
*/