跳转到内容

存储格式与查询

不需要数据库服务。现代分析栈的最小组合是:Parquet 分区存储 + DuckDB/Polars 直接查询——零运维、版本可控、读写快一到两个数量级。

格式优点缺点适用
CSV万能、可读慢 10–100 倍、无类型、体积大只做交换格式,不做工作格式
HDF5单文件、MATLAB 友好并发写差、目录级分区难已逐步被 Parquet 取代
Parquet列式、压缩、谓词下推、分区不可读、需按目录组织默认选择
Arrow内存列式、零拷贝是传输/内存格式而非落盘格式进程间交换

时序数据按 year=/month= 分区最实用:

data/
market/
daily/
year=2024/month=01/part-000.parquet
year=2024/month=02/part-000.parquet
fundamental/
announcements/
year=2024/part-000.parquet
meta/
symbols.parquet # 证券主表
corporate_actions.parquet # 复权因子

分区列不要用高基数列(如股票代码做顶层分区会产生几千个目录);查询时用谓词下推只扫描需要的月份。

duckdb-query.py
import duckdb
con = duckdb.connect() # 无需服务,直接查询文件
# 只扫描 2024 年 1 月的分区,谓词下推生效
df = con.execute("""
SELECT symbol, date, close, volume
FROM read_parquet('data/market/daily/year=2024/month=01/*.parquet')
WHERE symbol LIKE '6005%'
ORDER BY date
""").df()
# 也可以把整张表注册后用 SQL 做复权、对齐等管道步骤
con.register("raw_daily", df_raw)

Polars 的等价工作流:pl.scan_parquet(...) 惰性扫描 + filter 谓词下推 + collect,与 DuckDB 二选一即可。

  • 落盘数据是不可变的:修正用新分区覆盖写入 + 版本号,不原地改,与复现性的数据快照配合;
  • schema 显式声明(列名、类型、时区),跨年不漂移;
  • 大于单机的 tick 数据才考虑 ClickHouse 等列式数据库服务。
  • 原始数据按日期分区存 Parquet,查询走 DuckDB/Polars;
  • 复权因子、公告日等维表单列存放,与行情按 as-of 对齐;
  • CSV 只在交付或交换时使用。
  • Parquet + 分区 + 谓词下推,扫描速度比 CSV 快一到两个数量级
  • DuckDB 可直接 SQL 查询 Parquet 目录,无需数据库服务
  • 时序数据按 year=/month= 分区最实用,顶层分区避免高基数列