TimescaleDB Compression: Hypercore and Columnar Storage
TimescaleDB 透過利用 hypercore 引擎,針對時序數據實現了高達 98% 的壓縮率。與通用型壓縮不同,hypercore 採用了一種混合行-列式方法,利用針對時序數據數學特性(例如單調性和重複性)量身定制的專用演算法。
Hypercore vs. PostgreSQL TOAST
TimescaleDB 的壓縮功能是 PostgreSQL 內建 TOAST (The Oversized-Attribute Storage Technique) 的補充而非替代品。雖然 TOAST 管理超過特定閾值的單個大型值(例如長字串或 JSONB),但 hypercore 優化的是 跨行模式 (cross-row patterns)。
| Feature | TOAST (vanilla PostgreSQL) | TimescaleDB hypercore |
|---|---|---|
| Design Goal | 單個值 > 2 KB | 時序數據中的跨行模式 |
| Trigger | 行超過 TOAST_TUPLE_THRESHOLD |
每個 chunk 的策略 (例如,早於 7 天) |
| Supported Types | 僅限變長類型 (text, jsonb, 等) |
所有數據類型 |
| Algorithms | pglz, lz4 |
Delta, Delta-of-Delta, Simple-8b, RLE, XOR-based, Dictionary |
| Granularity | 每個值 | 每個 batch (~1000 rows) |
| Data Structure | 將值視為不透明的位元組 | 利用數值結構和重複性 |
| Sensor Floats Ratio | ~1.0× | 10-20× |
| Timestamp Ratio | ~1.0× | 50-100× |
| Text Ratio | 2-3× | 5-10× |
How Columnar Compression Works
Hypercore 將較舊的數據 chunk 從行式格式(針對快速 INSERTs 優化)轉換為列式格式。在此過程中,行被分組為最多 1,000 行的 batch。每個 batch 在壓縮後的表格中儲存為單一列,其中列 (columns) 以陣列的形式表示。
Specialized Compression Algorithms
TimescaleDB 根據列的數據類型選擇壓縮演算法,以實現效率最大化:
- Integers, Timestamps, and Booleans: 使用 delta encoding (儲存值之間的差異)、delta-of-delta (儲存差異的變化,對於定期間隔來說為 0)、simple-8b,以及 run-length encoding (RLE)。
- Floats (e.g., temperature/vibration): 採用 XOR-based compression (基於 Gorilla 演算法)。透過對相鄰的浮點數進行 XOR 運算,引擎僅儲存重要的位元,忽略長串的零。
- JSONB: 使用兩層方法:首先使用重複值的字典 (dictionary);若無重複值,則退回到 PostgreSQL TOAST。
- Strings and Other Types: 使用 dictionary compression,其中字典索引本身會使用 simple-8b 和 RLE 進一步壓縮。
Example: Delta and Run-Length Encoding
對於在許多行中重複出現的 machine_id,RLE 會將該值儲存一次並附帶一個計數器(例如,MACHINE_001 × 5),而不是重複五次該字串。對於定期間隔的時間戳,delta-of-delta 編碼可以將每個值的儲存需求降低到接近 0 位元組。
Optimizing Compression with segmentby and orderby
兩個參數對於決定如何將行分組為 batch 並有效地進行壓縮至關重要:
segmentby: 定義了在一個 batch 中共享的值的列 (column)(例如,machine_id)。該值在每個 batch 中僅儲存一次。查詢規劃器會使用此元數據來跳過不符合WHERE子句的整個 batch。orderby: 定義了 batch 內的排序順序(通常為time DESC)。按時間排序可以最大化 delta 和 delta-of-delta 編碼的效率,因為相鄰的值更有可能相似。
Configuration Example:
ALTER TABLE iot_sensor_data SET (
timescaledb.orderby = 'time DESC',
timescaledb.segmentby = 'machine_id'
);
Best Practice: 每個 segment 應包含每個 chunk 的至少 100 行,且每個 chunk 中具有 100–10,000 個唯一的 segmentby 值是最佳範圍。
Impact on Query Performance
對於大多數時序工作負載,壓縮 增加 了查詢速度,透過將 I/O 需求降低 10–20×。
Performance Gains
- Range scans 隨時間進行的聚合查詢 (
SUM,AVG,MAX)。 - Queries filtering on the
segmentbycolumn. 查詢過濾濾器應用於segmentby列。 - Sequential scans 進行大範圍的掃描。
Performance Trade-offs
- Point lookups 單個行之類的點查詢可能較慢。
- UPDATE/DELETE 在壓縮後的 chunk 上進行操作需要經過「解壓縮–修改–重新壓縮」的循環。
Real-World Benchmark
在一個使用 MQTT 傳感器數據的生產環境測試中,透過 id 和窄時間範圍進行點讀取,從行存儲 (rowstore) 轉換到列存儲 (columnstore) chunk 時,執行時間展現了 28× 的加速 (10.2 ms 降至 0.36 ms) 且 42.8× 的壓縮率 (308 MB 降至 7.2 MB)。
Why Columnstore is Faster
- Sparse MinMax Index: TimescaleDB 自動在
(segmentby_col, _ts_meta_min_1, _ts_meta_max_1)上建立索引。這允許引擎消除整個 batch,而無需讀取實際數據。 - Native Filtering: 因為具有相同
id的行在物理上被分組,引擎可以立即定位到正確的 segment,而不需要在(id, time)上使用大型 B-tree 索引。
- Vectorized Execution: 運算是在 1,000 行的 batch 中進行處理,而不是逐行處理,從而降低了 CPU 開銷。
Summary
TimescaleDB 使用 Hypercore 引擎,透過將行式 chunk 轉換為使用 delta encoding 和 Gorilla XOR 等專用演算法的混合列式格式,在時序數據上實現了高達 98% 的壓縮率。
Title
TimescaleDB Compression: Hypercore and Columnar Storage