多年全市场分钟线放在一堆 Parquet 文件里,怎样让查询只读取需要的那一小部分?

分区与数据湖

约 9 分钟5 道自测更新于 2026-10-27

一句话记住分区让查询先按目录裁剪,行组让查询再在文件内跳块;分区字段要匹配查询习惯,过度分区会制造小文件灾难。

01学完你能做到

设计基础的行情分区方案;区分分区裁剪与文件内行组跳块;解释数据湖和表格式的作用;识别高基数分区、小文件、版本缺失和目录并发写入问题。

02这课解决什么问题

多年全市场分钟线放在一堆 Parquet 文件里,怎样让查询只读取需要的那一小部分?分区解决目录级筛选,数据湖和表格式解决文件组织、追加、修改与版本管理。

03分区是什么

分区按字段值把数据放进不同目录。常见 Hive 风格目录是:

bars_1m/trade_date=2026-09-15/part-000.parquet

查询带有 trade_date 条件时,引擎可以先进行分区裁剪,只打开匹配目录;进入文件后,还可能使用 Parquet 行组的统计继续跳块。这是两层不同的优化。

行情最常见的过滤条件通常包括交易日和证券代码,但不应仅凭经验决定分区。代码取值很多,直接按“日期 × 代码”分区,容易产生大量小文件。常见方案是按日期分区、文件内按代码排序或分桶,再配合行组跳块。

04数据湖与表格式

数据湖是把原始和加工后的数据以 Parquet 等开放格式放到对象存储上,由多个计算引擎共同读取。它适合存放全量历史,但不自动提供在线低延迟查询。

Iceberg、Delta Lake 和 Hudi 等表格式在文件之上增加元数据,记录当前表由哪些文件组成,并提供不同程度的原子提交、schema 演进、版本回溯和并发写能力。具体能力要看实现、版本和部署配置,不能把“用了 Parquet”直接等同于“有事务表”。

05一个分区实验

下面是教学代码,bdate_range 只产生工作日,不自动排除交易所节假日;真实系统应使用适用市场的交易日历。

import pandas as pd
import pyarrow as pa
import pyarrow.parquet as pq
import pyarrow.dataset as ds

rows = pd.DataFrame({
    "trade_date": ["2026-09-15", "2026-09-15", "2026-09-16"],
    "code": ["000001.SZ", "600000.SH", "000001.SZ"],
    "close": [10.0, 12.0, 10.2],
})
pq.write_to_dataset(
    pa.Table.from_pandas(rows, preserve_index=False),
    "lake/bars_1m", partition_cols=["trade_date"]
)
dataset = ds.dataset("lake/bars_1m", format="parquet", partitioning="hive")
filtered = dataset.to_table(
    filter=ds.field("trade_date") == "2026-09-15",
    columns=["code", "close"],
).to_pandas()
print(filtered)

分区字段格式必须统一,例如 2026-09-01 和 2026-9-1 不能混用。分区规模应结合实际文件大小、查询模式、对象存储请求和下游引擎测试,不能把某个经验文件大小当成固定规则。

06常见误区

  1. 按股票代码、订单号等高基数字段分区,导致小文件爆炸。
  2. 只按月份分区,但查询主要按单只股票多年回溯,结果仍要扫描很多分区。
  3. 只用目录直接覆盖文件,失败或并发写入时可能暴露不完整数据。
  4. 修正历史数据没有版本,无法复现之前使用的那一版数据。
  5. 认为数据湖可以替代数据库;低延迟点查和高并发小查询通常需要数据库或缓存。

07延伸阅读

08一分钟讲给别人

试着用自己的话讲一遍分区就是把数据按日期这样的字段放进不同文件夹,查某天时先只开对应目录。但别分太细,按股票代码再分一层会产生大量小文件。数据湖把开放格式文件放到对象存储,表格式再负责版本和并发管理,让一堆文件更像一张可维护的表。

想一想

5 道自测

先在心里答一遍,再展开对照。能说清理由,比答对数字更重要。

  1. 01Hive 风格分区目录通常怎样命名?

  2. 02分区裁剪和行组跳块有什么区别?

  3. 03为什么不建议直接按股票代码分区?

  4. 04表格式比单纯目录多解决了哪些问题?

  5. 05为什么历史修正需要版本信息?

已看 0/5 题

练动手练习

任务:用 DuckDB 或 PyArrow 读取按 trade_date 分区的 Parquet 目录,比较带日期过滤和不带过滤时的扫描范围;再设计一份按日期分区、文件内按代码排序的目录方案,并写出版本字段。

完成这一课

完成这一课

读完讲义、看完自测答案,这一课就算学完了。

  • 读完讲义
  • 看完全部自测

本课为投资者教育内容,案例数字均为示意,不构成任何投资建议,也不承诺收益。规则和费率会变,实际操作前请以交易所、监管机构和产品的最新公告为准。