clickhouse、timescaledb、parquet 在1min bar上压缩比例对比
我的市场数据存在 clickhouse 里, 不过 clickhouse 的连接驱动总是很麻烦, 而且 ORM 基本不支持 ch, 导致我行情数据存在 ch 里, 其他数据放到 sqlite/postgresql 里. 因而我一直想把行情数据换为「经典」的选择, 最近看到了tukuaiai/tradecat宣传得很好, 我就看了实现, 用的是 postgresql+timescaledb, 一看就非常经典.
于是我就简单测试了一下我最关注的压缩性能, 毕竟能在一块SSD里保存全市场数据还是很重要的. 剧透, timescaledb 压缩后大小甚至能到 clickhouse 的三倍.
我的 clickhouse 表结构是:
CREATE TABLE default.FUTURES_um_klines_BTCUSDT
(
`open_time` UInt64 CODEC(DoubleDelta),
`close_time` UInt64 CODEC(DoubleDelta),
`open` Float64 CODEC(Gorilla(8), ZSTD(1)),
`high` Float64 CODEC(Gorilla(8), ZSTD(1)),
`low` Float64 CODEC(Gorilla(8), ZSTD(1)),
`close` Float64 CODEC(Gorilla(8), ZSTD(1)),
`volume` Float64 CODEC(ZSTD(1)),
`quote_volume` Float64 CODEC(ZSTD(1)),
`count` UInt32 CODEC(Delta(4), ZSTD(1)),
`taker_buy_volume` Float64 CODEC(ZSTD(1)),
`taker_buy_quote_volume` Float64 CODEC(ZSTD(1))
)
ENGINE = ReplacingMergeTree
ORDER BY open_time
SETTINGS index_granularity = 4096;2024/06/01-2025/12/31 的 BTCUSDT Futures(Binance) 数据合计 32MiB, 压缩前 66MiB, 将数据读出后, 用 polars 默认参数写出为 parquet 后, 文件 35MiB.
pg 下的创建表语句是:
CREATE TABLE market_data.futures_um_klines_btcusdt_no_ms (
open_time bigint NOT NULL,
close_time bigint NOT NULL,
open double precision NOT NULL,
high double precision NOT NULL,
low double precision NOT NULL,
close double precision NOT NULL,
volume double precision NOT NULL,
quote_volume double precision,
count integer,
taker_buy_volume double precision,
taker_buy_quote_volume double precision
);
CREATE INDEX futures_um_klines_btcusdt_no_ms_dt_idx
ON market_data.futures_um_klines_btcusdt_no_ms USING btree (dt DESC);
SELECT create_hypertable(
'market_data.futures_um_klines_btcusdt',
'open_time',
chunk_time_interval => 86400000,
if_not_exists => TRUE
);然后通过数_timescaledb_catalog.compression_chunk_size的方式计算 pg 表的大小, 得到 chunk_index_size=4592 kiB, compressed_chunk_size=94 MiB
这个数据非常吓人, 因为未压缩的 csv 也就 114MiB, 我试着删去open_time/close_time 两个字段, 压缩前的大小变小了一些, 但压缩后还是 94MiB, 那么应该可以说明压缩机制正常发挥作用. 另外, 我也检查了一下pgdata目录, 已经 1003 MiB 了.
这样的话, postgresql+timescaledb 压缩后大小基本是 ch 的三倍大小, 膨胀比例是五倍, 暂时还没有必要切换过去.
不过, 如果你去问 LLM, ch 中用我上面的表结构怎么样, 他们基本都会说不行, parts 太多, 元数据代价太大种种, 但是根据我的测试, 代价实际上非常小, 有机会我再写文章聊聊吧.
做个总结:
| 储存方式 | 最近一年半 BTCUSDT 数据占用空间/MiB |
|---|---|
| clickhouse(压缩前) | 66 |
| clickhouse(压缩后) | 33 |
| parquet | 35 |
| csv | 114 |
| csv.zst | 37 |
| timescaledb | 94 |