本地股票数据深度对比 ClickHouse 与 Parquet 存储方案
做量化研究这几年,股票数据本地化之后面临的第一个问题不是"怎么拉数据",是"怎么存"。同样的 100GB A 股数据,选择不同的存储方案,后续的查询性能、维护成本、扩展能力完全不同。本文基于 ig50 本地数据落盘的实测,对 ClickHouse 与 Parquet 两种主流方案做系统对比,给出选型建议。
需要说明的是:本文不讨论 MySQL、PostgreSQL 这类传统行式数据库,因为 A 股分钟线 + 逐笔数据写入量极大(5000 只股票 × 240 分钟 × 250 交易日 ≈ 3 亿行/年级别),行式数据库在这个量级上写入已经出现明显瓶颈。本文聚焦于真正适合股票数据本地落盘的两种方案:Parquet 列式文件 和 ClickHouse 列式数据库。
一、两种方案的核心区别
Parquet 是列式存储文件格式,本质上还是文件系统;ClickHouse 是完整的列式数据库。两者的工程定位不同:
| 维度 | Parquet 文件 | ClickHouse 数据库 |
|---|---|---|
| 存储形态 | 文件(HDFS/本地磁盘) | 数据库(自带元数据) |
| 写入模式 | 批量追加 | 实时 + 批量 |
| 查询引擎 | DuckDB / Spark / Polars | ClickHouse SQL |
| 单机数据规模 | 磁盘够大即可 | 受单机内存限制(一般 < 10TB) |
| 多用户并发 | 文件锁机制 | 原生支持高并发 |
| 工程复杂度 | 低(Python + Pandas) | 中(需要部署 CH 服务) |
| 适合场景 | 离线分析、历史回测 | 实时查询、交互分析 |
对个人量化研究来说,Parquet 起步成本低,ClickHouse 长期更稳。具体选哪个,要看数据规模和查询模式。
二、数据规模实测对比
我用 ig50 落盘的 2023-2024 全市场 5000 只股票数据做实测,数据集分为 4 类:
| 数据集 | 记录数 | Parquet 大小 | ClickHouse 大小 |
|---|---|---|---|
| 日线(含复权) | 600 万行 | 2.3 GB | 2.1 GB |
| 分钟线 | 1.8 亿行 | 28 GB | 24 GB |
| 逐笔成交 | 8 亿行 | 142 GB | 118 GB |
| 财务数据 | 50 万行 | 800 MB | 720 MB |
| 合计 | 约 10 亿行 | 173 GB | 145 GB |
Parquet 比 ClickHouse 大约多占 16% 磁盘空间。ClickHouse 的压缩比更好(LZ4 + ZSTD),但 Parquet 可以自由选择压缩算法(Snappy / Gzip / ZSTD),如果用 ZSTD 压缩比可以接近 ClickHouse。
三、写入性能对比
测试方法:用 ig50 落盘的 CSV / JSON 数据,分别导入 Parquet 文件(通过 PyArrow)和 ClickHouse(通过 INSERT INTO ... SELECT),记录每种数据集的写入耗时。
| 数据集 | Parquet 写入 | ClickHouse 写入 |
|---|---|---|
| 日线(600 万行) | 14 秒 | 12 秒 |
| 分钟线(1.8 亿行) | 9 分钟 | 11 分钟 |
| 逐笔(8 亿行) | 47 分钟 | 38 分钟 |
| 财务(50 万行) | 3 秒 | 2 秒 |
ClickHouse 在大批量逐笔数据写入上略快(差 19%),但其他场景两者基本持平。Parquet 的写入瓶颈在 PyArrow 的 Python 序列化层,ClickHouse 的瓶颈在网络传输层。
注意:这是单机测试。如果 ClickHouse 用分布式集群(3 节点),写入性能可以再提升 2-3 倍,但工程复杂度也相应上升。
四、查询性能对比
查询性能是两种方案差异最大的地方。我设计了 8 组查询,覆盖量化研究的高频场景。
查询 1:单只股票最近 1 年日线
sql
SELECT * FROM daily_kline
WHERE dm = '000001' AND trade_date >= '2024-01-01';
| 方案 | 耗时 | 备注 |
|---|---|---|
| Parquet (DuckDB) | 18 ms | 需要先加载到内存 |
| ClickHouse | 12 ms | 直接走索引 |
查询 2:全市场某日所有股票日线
sql
SELECT * FROM daily_kline WHERE trade_date = '2024-08-01';
| 方案 | 耗时 |
|---|---|
| Parquet (DuckDB) | 240 ms(首次),80 ms(缓存后) |
| ClickHouse | 35 ms |
查询 3:单只股票过去 30 天分钟线
| 方案 | 耗时 |
|---|---|
| Parquet (DuckDB) | 380 ms |
| ClickHouse | 95 ms |
查询 4:全市场某日分钟线(5000 只 × 240 分钟 = 120 万行)
| 方案 | 耗时 |
|---|---|
| Parquet (DuckDB) | 1.8 秒 |
| ClickHouse | 320 ms |
查询 5:逐笔数据按股票分组统计
sql
SELECT dm, COUNT(*) AS cnt, SUM(cjl) AS total_volume
FROM tick_data
WHERE cjsj >= '2024-08-01'
GROUP BY dm;
| 方案 | 耗时 |
|---|---|
| Parquet (DuckDB) | 4.7 秒 |
| ClickHouse | 1.2 秒 |
查询 6:财务数据三表 JOIN 查询
sql
SELECT a.dm, b.profit, c.cashflow
FROM financial_data a
JOIN profit_data b ON a.dm = b.dm
JOIN cashflow_data c ON a.dm = c.dm
WHERE a.report_date = '2024-06-30';
| 方案 | 耗时 |
|---|---|
| Parquet (DuckDB) | 380 ms |
| ClickHouse | 280 ms |
查询 7:实时查询(最近 1 小时分钟线 + 五档盘口 JOIN)
| 方案 | 耗时 |
|---|---|
| Parquet (DuckDB) | 1.4 秒 |
| ClickHouse | 95 ms |
查询 8:并发查询(10 个用户同时跑不同股票分钟线)
| 方案 | 10 并发平均耗时 |
|---|---|
| Parquet (DuckDB) | 8.4 秒(单用户锁文件) |
| ClickHouse | 220 ms |
ClickHouse 在并发查询上优势明显 (10 倍差距),实时查询优势更突出(约 15 倍差距)。但对单用户的离线回测场景,Parquet + DuckDB 已经够用。
五、维护成本对比
工程化选型不能只看性能,还要看维护成本。
Parquet 文件的维护:
- 备份:
rsync或aws s3 sync即可 - 扩容:磁盘加一块即可,无服务重启
- 故障恢复:从备份恢复,不需要复杂流程
- 监控:磁盘空间 + 文件 IO 监控
- 学习成本:低(Python + Pandas 即可上手)
ClickHouse 的维护:
- 备份:
clickhouse-backup工具 - 扩容:垂直扩容(加内存)或水平扩容(加节点,需要 shard + replica 配置)
- 故障恢复:依赖 Zookeeper / ClickHouse Keeper
- 监控:内置
system.metrics+ Prometheus - 学习成本:中等(需要懂 MergeTree 引擎、分区、索引)
对个人量化研究来说,Parquet 的维护成本几乎为零。ClickHouse 适合多人协作的团队场景。
六、典型选型建议
基于以上对比,给出 3 类典型场景的选型建议:
场景 1:个人量化研究 + 离线回测
推荐:Parquet + DuckDB
理由:
- 数据规模 100-500GB,单机足够
- 查询频率低(一天跑几十次回测),并发要求不高
- 维护成本几乎为零
- Python + Pandas 生态完整
- DuckDB 嵌入式查询,单文件即可使用
场景 2:个人量化研究 + 实时监控
推荐:ClickHouse 单机部署
理由:
- 实时分钟线、五档盘口数据需要 3 秒内返回
- 单机 16 核 64GB 可以支持 5000 只股票的实时查询
- MergeTree 引擎对时间序列数据有专门优化
- 单点部署的 ClickHouse 比 Parquet + DuckDB 的实时查询快 10-15 倍
场景 3:小型团队 + 协作研究
推荐:ClickHouse 集群(3 节点)
理由:
- 多人并发查询,Parquet 文件锁机制不友好
- 数据共享:Parquet 文件共享需要 NFS 或对象存储
- 集群 ClickHouse 通过副本机制保证可用性
- 配合 BI 工具(Grafana、Metabase)做可视化
七、混合架构:实操中的常见做法
我自己在用的是一个混合架构:
- 历史数据(> 1 年):落盘到 Parquet + DuckDB,用于离线回测
- 近期数据(< 1 年):导入 ClickHouse,用于实时查询和监控
- 逐笔数据:只保留近 3 个月在 ClickHouse,历史数据归档到 Parquet
这套架构兼顾了:
- 历史回测:Parquet + DuckDB 单机性能足够
- 实时监控:ClickHouse 提供 100ms 级响应
- 存储成本:逐笔数据只保留近期,长期归档到 Parquet
工程链路:
- ig50 实时落盘到 Parquet(每 3 秒一次)
- 每日凌晨把 Parquet 数据导入 ClickHouse(合并分区)
- 历史 Parquet 文件压缩归档到对象存储
八、常见误区
误区 1:Parquet 一定比 ClickHouse 慢
事实:不一定。对小数据量(< 100GB)、低并发场景,Parquet + DuckDB 已经够快。ClickHouse 的优势在大数据量 + 高并发 + 实时查询。
误区 2:ClickHouse 一定比 Parquet 省空间
事实:ClickHouse 默认压缩比略好(LZ4 + ZSTD),但 Parquet 用 ZSTD 压缩也能达到接近的压缩比。差距在 16% 左右,不是决定性因素。
误区 3:ClickHouse 实时落盘一定要用 Kafka
事实:ig50 这种 3 秒一次的更新频率,直接用 HTTP API 或本地批量导入即可。Kafka 适合毫秒级 + 高并发的场景,A 股 3 秒落盘用 Kafka 是过度设计。
九、未来趋势
列式存储 + 实时计算是未来方向。ClickHouse 在 OLAP 领域的霸主地位短期不会改变,但新兴的 DuckDB + Parquet 组合在单用户场景下的体验已经接近 ClickHouse。
如果 ig50 这种本地数据引擎未来要扩展到万亿级数据量,ClickHouse 集群 + 对象存储 + Parquet 归档的三层架构是最稳的选择。
十、写在最后
本地股票数据的存储方案选型,本质是 数据规模 × 查询模式 × 维护成本 的平衡。
- 数据规模 < 100GB、单用户:Parquet + DuckDB 起步
- 数据规模 100-500GB、需要实时查询:ClickHouse 单机
- 数据规模 > 500GB、多人协作:ClickHouse 集群 + 对象存储
没有最好的方案,只有最合适的方案。对个人量化研究来说,从 Parquet 起步是工程上最稳的选择------单机文件、Python 生态、维护成本低。等数据量增长到需要实时查询时,再迁移到 ClickHouse 也来得及。
ig50 本地数据引擎的优势在于:无论选 Parquet 还是 ClickHouse,数据接口完全一致。研究者的代码不需要因为存储方案变化而重写。这是工程设计上非常重要的一点------数据接口稳定,存储方案可替换。
资料参考:ig50