Bảng MergeTree lưu dữ liệu thành các part bất biến: mỗi lần INSERT tạo một part mới, đã sắp xếp theo ORDER BY; nền tảng chạy merge gộp part nhỏ thành part lớn. Bốn quyết định khi tạo bảng ảnh hưởng tới tốc độ query và dung lượng nhiều nhất: ORDER BY, PRIMARY KEY, PARTITION BY, TTL.
Dữ liệu đi qua bảng như thế nào
flowchart LR I["INSERT batch"] --> P1["Part mới (đã sort theo ORDER BY)"] P1 --> M["Merge nền"] M --> P2["Part lớn trong partition"] P2 -->|"TTL hết hạn"| D["Xoá dòng / drop part"] I -->|"trigger"| MV["Materialized view"] MV --> AGG["Bảng tổng hợp (SummingMergeTree)"] Q[SELECT] -->|"primary index bỏ qua granule"| P2
Thành phần
| Mệnh đề | Vai trò | Cách chọn |
|---|---|---|
ORDER BY |
Thứ tự lưu trên disk, cũng là primary key mặc định | Cột hay lọc bằng = và cardinality thấp đứng trước, thời gian đứng sau: (source, name, time) |
PRIMARY KEY |
Index thưa (sparse): mỗi granule (mặc định 8192 dòng) một entry, nằm trong RAM | Bỏ qua nếu giống ORDER BY; chỉ khai báo khi muốn index là tiền tố ngắn hơn của ORDER BY |
PARTITION BY |
Chia part theo thư mục logic; merge chỉ diễn ra trong cùng partition | Thô: theo ngày toDate(t) hoặc tháng toYYYYMM(t). Không partition theo thiết bị/giờ (gây TOO_MANY_PARTS) |
TTL |
Tự xoá dòng (hoặc chuyển volume, gộp dòng) khi hết hạn | TTL time + INTERVAL 90 DAY; kết hợp ttl_only_drop_parts = 1 để drop cả part thay vì viết lại |
CODEC / kiểu dữ liệu |
Nén theo cột | LowCardinality(String) cho tên thiết bị/interface, Delta/DoubleDelta cho counter và thời gian |
Partition không phải index. Query nhanh là nhờ điều kiện WHERE khớp tiền tố ORDER BY (primary index) và khoảng thời gian (partition pruning). Kiểm tra bằng EXPLAIN indexes = 1 SELECT ....
Bảng counter interface
Cùng schema với phần còn lại của section (source, name, in_octets...):
CREATE DATABASE IF NOT EXISTS telemetry;
CREATE TABLE telemetry.interfaces
(
time DateTime CODEC(DoubleDelta, ZSTD),
source LowCardinality(String),
name LowCardinality(String),
in_octets UInt64 CODEC(Delta, ZSTD),
out_octets UInt64 CODEC(Delta, ZSTD),
in_errors UInt64 CODEC(Delta, ZSTD)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(time)
ORDER BY (source, name, time)
TTL time + INTERVAL 90 DAY
SETTINGS ttl_only_drop_parts = 1;- Query
WHERE source = 'pe1-hni' AND time > now() - INTERVAL 1 HOURchỉ đọc vài granule. - Query chỉ lọc theo
name(cột thứ hai) vẫn chạy nhưng kém hiệu quả hơn. Cần lọc nhiều theo cột khác thì thêm projection hoặc data skipping index, đừng đổiORDER BYvội. ORDER BYkhông đổi được sau khi tạo (chỉ thêm cột mới vào cuối). Sai thì tạo bảng mới vàINSERT INTO ... SELECT.
TTL
-- Đổi TTL bảng có sẵn. Mặc định (materialize_ttl_after_modify = 1) lệnh này
-- còn chạy MATERIALIZE TTL trên toàn bộ dữ liệu cũ: nặng IO với bảng lớn
ALTER TABLE telemetry.interfaces MODIFY TTL time + INTERVAL 30 DAY;
-- TTL theo cột: xoá nội dung message sau 7 ngày, giữ dòng
ALTER TABLE logs.syslog MODIFY COLUMN message String TTL toDateTime(timestamp) + INTERVAL 7 DAY;
-- Ép áp TTL cho dữ liệu cũ khi đã tắt materialize_ttl_after_modify
ALTER TABLE telemetry.interfaces MATERIALIZE TTL;TTL được xử lý lúc merge, nên dữ liệu hết hạn có thể còn thêm một thời gian (điều khiển bởi merge_with_ttl_timeout). Biểu thức TTL phải trả về Date hoặc DateTime: cột DateTime64 thì bọc toDateTime(...).
Materialized view: bảng tổng hợp
Materialized view (MV) trong ClickHouse là trigger lúc INSERT: mỗi batch ghi vào bảng nguồn được chạy qua SELECT của MV, kết quả ghi vào bảng đích. Ví dụ đếm syslog theo phút từ bảng logs.syslog của pipeline Vector:
CREATE TABLE logs.syslog_1m
(
t DateTime,
source LowCardinality(String),
mnemonic LowCardinality(String),
cnt UInt64
)
ENGINE = SummingMergeTree
ORDER BY (source, mnemonic, t)
TTL t + INTERVAL 1 YEAR;
CREATE MATERIALIZED VIEW logs.syslog_1m_mv TO logs.syslog_1m AS
SELECT toStartOfMinute(timestamp) AS t, source, mnemonic, count() AS cnt
FROM logs.syslog
GROUP BY t, source, mnemonic;
-- Backfill dữ liệu đã có trước khi tạo MV
INSERT INTO logs.syslog_1m
SELECT toStartOfMinute(timestamp) AS t, source, mnemonic, count() AS cnt
FROM logs.syslog
GROUP BY t, source, mnemonic;
-- Query: luôn sum() lại vì merge gộp dòng không tức thời
SELECT t, source, sum(cnt) AS n
FROM logs.syslog_1m
WHERE t > now() - INTERVAL 1 DAY
GROUP BY t, source ORDER BY t;Với giá trị không cộng dồn được (max, last, quantile) dùng AggregatingMergeTree:
CREATE TABLE telemetry.interfaces_5m
(
t DateTime,
source LowCardinality(String),
name LowCardinality(String),
in_octets_max SimpleAggregateFunction(max, UInt64),
out_octets_max SimpleAggregateFunction(max, UInt64)
)
ENGINE = AggregatingMergeTree
ORDER BY (source, name, t)
TTL t + INTERVAL 2 YEAR;
CREATE MATERIALIZED VIEW telemetry.interfaces_5m_mv TO telemetry.interfaces_5m AS
SELECT toStartOfFiveMinutes(time) AS t, source, name,
max(in_octets) AS in_octets_max, max(out_octets) AS out_octets_max
FROM telemetry.interfaces
GROUP BY t, source, name;Counter tăng dần nên max mỗi 5 phút tương đương giá trị cuối kỳ. Đặt alias khác tên cột nguồn (in_octets_max), vì max(in_octets) AS in_octets có thể bị ClickHouse thay alias vào chính đối số và báo lỗi aggregate lồng nhau; tính bps từ bảng này giống bảng raw (xem ClickHouse SQL cheatsheet). Hàm phức tạp hơn (quantile, uniq) thì dùng kiểu AggregateFunction(...) với -State khi ghi và -Merge khi đọc.
Lưu ý về MV:
- Chỉ thấy dữ liệu INSERT mới vào bảng ở
FROM; không tự backfill (tránhPOPULATE, dễ mất dữ liệu insert trong lúc tạo). - Lỗi trong
SELECTcủa MV làm INSERT vào bảng nguồn thất bại. - Dùng cú pháp
TO bảng_đíchđể có thể sửa/xoá MV mà không mất dữ liệu tổng hợp.
Khi nào dùng
| Nhu cầu | Lựa chọn |
|---|---|
| Log/flow/counter lưu lâu, query SQL tuỳ ý | MergeTree + TTL |
| Dashboard dài ngày chạy chậm trên bảng raw | MV ghi vào SummingMergeTree / AggregatingMergeTree |
| Giữ raw ngắn, bản tổng hợp dài | TTL khác nhau cho bảng raw và bảng đích |
Lọc nhiều theo cột không nằm đầu ORDER BY |
Projection hoặc skipping index (bloom_filter, minmax) |
| Cần bỏ trùng bản ghi gửi lặp | ReplacingMergeTree (khử trùng khi merge, query cần FINAL nếu muốn chính xác ngay) |
Lỗi vận hành (TOO_MANY_PARTS, disk đầy, mutation kẹt) xem ClickHouse xử lý sự cố.