4. 分区核心概念

在 Tick 数据场景中,分区不是简单的“按天建表”,而是决定数据如何被定位、裁剪、并发写入与冷热迁移的底层结构。理解分区,核心要回答三个问题:按什么切、切多细、切完对读写有什么代价。本节围绕分区定义、分区键选择、时间分区与哈希分区、粒度权衡,以及分区对查询与写入的影响展开。

一、分区定义:把一张大表拆成可裁剪的数据单元

分区是将逻辑上的一张表,按某种规则拆分为多个物理存储单元。对查询引擎而言,分区裁剪(Partition Pruning)是最重要的收益:当 WHERE 条件命中分区键时,引擎只扫描相关分区,而不是全表。对 Tick 数据来说,这意味着查询某只股票某天的逐笔成交,不必扫描全部历史数据。

分区通常包含两层含义:分区键决定数据进入哪个分区;分区粒度决定每个分区的大小与数量。二者共同影响元数据压力、文件数量、写入放大和查询延迟。

分区不是索引。分区解决“扫哪些数据块”,索引解决“在块内如何快速定位行”。Tick 场景通常需要两者配合:时间分区做粗裁剪,索引做细定位。

二、分区键选择:时间优先,业务维度辅助

分区键应满足三个条件:高频出现在查询条件中、基数可控、数据分布均匀。Tick 数据最典型的查询模式是“某标的 + 某时间段”,因此时间几乎是必选分区键。常见组合包括:

  • 单键:按 trade_date 分区,简单直接,适合日频查询与 T+1 归档。
  • 复合键:按 trade_date + exchange 或 trade_date + symbol_bucket 分区,适合交易所分片或标的数量极大的场景。
  • 哈希辅助:对 symbol 做哈希分桶,避免单一热门标的写入过热。

选择分区键时,要避免“低基数但查询不常用”的字段,例如 side(买卖方向)只有两个值,分区后每个分区仍然巨大,裁剪收益低。也要避免“高基数且随机”的字段,例如 order_id,会导致分区数量爆炸。

三、时间分区与哈希分区:两种切分逻辑

时间分区按时间范围切分,天然契合 Tick 数据的时序特征。优点是范围查询裁剪效果好、冷热分层清晰、归档删除方便。缺点是如果按天分区,热门标的当天的数据量仍可能很大;如果按小时分区,分区数量会迅速膨胀。

哈希分区按分区键的哈希值取模或分桶,目的是把数据均匀打散到多个分区,提升写入并发、避免热点。缺点是范围查询无法裁剪,查询某时间段仍需扫描多个哈希分区。因此哈希分区通常不单独用于时间范围查询,而是作为时间分区下的二级分片。

-- 时间分区示例:按交易日分区
CREATE TABLE tick_trade (
  trade_date DATE,
  symbol     VARCHAR(16),
  ts         TIMESTAMP,
  price      DECIMAL(18,4),
  volume     BIGINT
)
PARTITION BY RANGE (trade_date);

-- 哈希分片示例:在时间分区内按 symbol 哈希分桶
PARTITION BY HASH (symbol) PARTITIONS 16;

四、分区粒度权衡:太粗与太细都危险

分区粒度是实战中最容易踩坑的地方。粒度太粗,单分区数据量过大,查询裁剪后仍需扫描海量数据,冷热迁移也只能整块搬移;粒度太细,分区数量爆炸,元数据压力、小文件问题和写入开销都会上升。

粒度 典型表现 风险 适用场景
按年/月 分区少,单分区大 查询裁剪弱,迁移笨重 历史归档、低频访问
按天 分区数量适中 热门标的单日仍可能过大 多数 Tick 日频查询
按小时 分区数量多,裁剪更细 小文件、元数据压力上升 高频查询、实时写入
按分钟 分区极多 写入与元数据开销显著 仅特殊实时场景
经验法则:先按天分区,再根据单分区数据量决定是否加二级哈希分片。若单日单分区超过数十 GB,优先考虑二级分片,而不是继续缩小时间粒度。

五、分区对查询与写入的影响

对查询的影响:分区裁剪能显著减少扫描量,但前提是查询条件必须包含分区键。如果查询只写 symbol 而不写 trade_date,时间分区无法裁剪,性能可能退化。此外,跨分区查询会带来额外的调度与合并开销,分区越多,规划阶段越重。

对写入的影响:分区影响写入并发与文件布局。时间分区下,同一时间段的数据集中写入同一分区,容易形成写入热点;哈希分区可以把写入打散到多个分片,提升并发。但分区过多会导致每个分区产生大量小文件,增加 compaction 与元数据负担。

-- 查询命中分区键,可裁剪
SELECT * FROM tick_trade
WHERE trade_date = '2025-03-14' AND symbol = '600519';

-- 未命中分区键,无法裁剪
SELECT * FROM tick_trade
WHERE symbol = '600519';

六、误区与复盘

  • 误区一:分区越多越好。分区数量与元数据、小文件、写入开销正相关,过度分区会拖慢整体性能。
  • 误区二:哈希分区能替代时间分区。哈希分区擅长打散写入,但不擅长范围裁剪,Tick 查询仍需要时间维度。
  • 误区三:分区键选 symbol 就够了。symbol 基数高且分布不均,单独分区容易导致热点与分区爆炸。
  • 复盘要点:先明确查询模式,再选分区键;先按天分区,再评估二级分片;定期检查分区数量、单分区大小与小文件比例。
Tick 数据分区:时间分区 + 哈希二级分片 逻辑表 tick_trade trade_date symbol ts / price / volume 时间分区(按天) 2025-03-13 2025-03-14 2025-03-15 范围裁剪:只扫目标日期 哈希二级分片 bucket 0 bucket 1 bucket 2 bucket N 打散写入:避免单点过热

总结来看,Tick 数据分区的正确姿势是:时间分区做粗裁剪,哈希分片做写入打散,粒度按单分区数据量动态调整。分区键必须服务于查询模式,分区粒度必须平衡裁剪收益与元数据成本。只有把分区、索引与冷热分层放在一起设计,才能在 Tick 数据规模增长时保持查询稳定与写入可控。