1. 课程导入

在金融交易、量化投研与行情分发系统中,行情数据是最典型的高吞吐、强时序、低延迟场景之一。无论是股票 Level-1/Level-2 快照、逐笔委托与成交,还是期货、期权、数字货币的盘口与深度数据,都具有“写入密集、查询实时、维度丰富、时间敏感”的共同特征。本课程围绕 ClickHouse 这一列式实时分析数据库,系统讲解行情数据的建模、入库与实时聚合,帮助你把“能存、能查、能算得快”真正落地到生产环境。

一、行情数据场景:为什么它比普通业务数据更难处理

行情数据通常以“快照 + 增量”的方式持续产生。以 A 股 Level-2 为例,单市场每日逐笔成交与委托可达数亿条,盘口快照按 3 秒或更细粒度切片,叠加多交易所、多品种、多合约后,日增数据量轻松达到 TB 级。它同时具备以下难点:

  • 写入吞吐极高:开盘与收盘时段瞬时峰值可达每秒数十万到数百万行,要求写入链路具备批量、异步、可回压能力。
  • 查询模式多样:既有点查最新盘口,也有区间扫描、K 线聚合、因子计算、历史回放与实时监控。
  • 时间维度强:几乎所有查询都带时间范围,且要求按交易所时间、本地时间、业务日期多口径对齐。
  • 乱序与重复:网络抖动、采集重连、多源合并会导致数据乱序、重复、缺失,需要幂等与去重策略。
  • 实时性要求高:监控、风控、策略信号往往要求秒级甚至亚秒级可见。

传统方案中,关系型数据库在写入吞吐和聚合扫描上容易成为瓶颈;HBase 等 KV 存储擅长点查但弱于多维聚合;Kafka 适合缓冲但不适合长期分析与回放。ClickHouse 的出现,恰好补上了“高吞吐写入 + 实时聚合 + 低成本存储”这一关键环节。

二、ClickHouse 的核心优势与原理要点

ClickHouse 是面向 OLAP 的列式数据库,其性能来自一整套协同设计,而不是单一技巧。理解这些原理,才能做出正确的建模与参数选择。

  • 列式存储:同一列数据连续存放,聚合查询只读取必要列,I/O 大幅减少,压缩率显著提升。
  • 向量化执行:按块(Block)批量处理,配合 SIMD 指令,单核吞吐远高于逐行处理。
  • 稀疏主键索引:按 ORDER BY 建立稀疏索引,快速定位 granule,适合时间范围扫描。
  • MergeTree 家族:支持分区、排序键、TTL、副本、物化视图与后台合并,天然适配时序数据。
  • 多样引擎:ReplacingMergeTree 去重、SummingMergeTree 预聚合、AggregatingMergeTree 存中间态,覆盖行情常见需求。
  • 实时写入:通过 Kafka 表引擎、Buffer、异步插入与批量攒批,实现高吞吐低延迟入库。
ClickHouse 不是“万能数据库”。它擅长批量写入与聚合分析,不擅长高频单行更新、复杂事务与点查低延迟。行情场景应扬长避短:写入走批量,更新走去重合并,点查用物化视图或外部缓存兜底。

三、核心方法流程:从数据源到实时聚合

本课程将行情链路拆解为“采集—缓冲—建模—入库—聚合—服务”六个阶段,每一阶段都有明确的工程取舍。

  1. 采集:从交易所网关、行情源或文件回放获取原始报文,解析为结构化字段。
  2. 缓冲:使用 Kafka/Pulsar 削峰填谷,保证上游抖动不影响数据库稳定性。
  3. 建模:确定表引擎、分区键、排序键、字段类型与编码,决定后续查询性能上限。
  4. 入库:批量写入、异步插入、幂等去重,控制 part 数量与合并压力。
  5. 聚合:用物化视图或 AggregatingMergeTree 预计算 K 线、盘口统计与指标。
  6. 服务:面向查询 API、监控看板与策略回测提供稳定低延迟读取。

下面是一段典型的建表与写入示例,体现行情快照表的基本建模思路:

CREATE TABLE market.snapshot
(
    exchange   LowCardinality(String),
    symbol     LowCardinality(String),
    ts         DateTime64(3, 'Asia/Shanghai'),
    last_price Decimal64(4),
    volume     UInt64,
    bid1       Decimal64(4),
    ask1       Decimal64(4)
)
ENGINE = ReplacingMergeTree
PARTITION BY toYYYYMMDD(ts)
ORDER BY (exchange, symbol, ts)
TTL ts + INTERVAL 90 DAY;

INSERT INTO market.snapshot
SELECT * FROM market.snapshot_kafka;

该示例中,PARTITION BY toYYYYMMDD(ts) 控制分区粒度,ORDER BY (exchange, symbol, ts) 支撑按标的与时间的高效扫描,ReplacingMergeTree 用于处理重复快照,TTL 控制冷数据生命周期。

四、案例场景:一个实时行情聚合看板

假设我们需要为多交易所、多品种构建一个实时行情看板,展示最新价、涨跌幅、分钟 K 线与成交量排行。数据流如下:行情网关 → Kafka → ClickHouse Kafka 引擎表 → 物化视图 → 聚合结果表 → 查询 API。写入侧按秒级批量落盘,聚合侧用 AggregatingMergeTree 维护分钟级 OHLC 与成交量,查询侧直接读取预聚合结果,避免每次扫描原始逐笔。

阶段关键对象典型参数/策略目标
采集行情网关、解析器多源合并、字段标准化结构化、低延迟
缓冲Kafka Topic分区数、副本数、保留时长削峰、可回放
建模MergeTree 表分区键、排序键、编码查询性能上限
入库Kafka 引擎、异步插入批量大小、并发度高吞吐、低 part
聚合物化视图、AggregatingMergeTree聚合粒度、TTL实时指标
服务查询 API、看板缓存、限流稳定低延迟

五、常见误区与复盘

初学者最容易犯的错误是“先写数据,再想模型”。行情表一旦按错误排序键建立,后续查询会频繁全表扫描;分区过细会导致 part 爆炸,分区过粗又影响 TTL 与冷热分离。建议先明确查询模式,再反推 ORDER BY 与分区键。
  • 误区一:单行插入。ClickHouse 每次插入都会生成 part,高频单行写入会拖垮合并线程,必须批量攒批。
  • 误区二:滥用 Nullable。Nullable 列带来额外存储与判断开销,行情字段应尽量用默认值或枚举替代。
  • 误区三:忽视乱序。多源合并与重连会产生乱序,需在排序键与去重策略中显式处理。
  • 误区四:把 ClickHouse 当 KV 用。高频点查应通过物化视图、Redis 缓存或外部索引解决。

本课程的学习目标可以归纳为三点:第一,掌握行情数据的建模方法,能独立设计快照表、逐笔表与聚合表;第二,掌握高吞吐入库链路,能配置 Kafka 引擎、异步插入与幂等去重;第三,掌握实时聚合与查询优化,能用物化视图与 AggregatingMergeTree 支撑生产级看板与策略服务。整体课程将按“场景认知—建模—入库—聚合—优化—实战”的主线推进,每一章都配有可运行的 SQL 与配置示例。

行情数据链路:采集 → 缓冲 → 建模 → 入库 → 聚合 → 服务 行情网关 Level-1/2 快照 Kafka 缓冲 削峰 · 可回放 MergeTree 建模 分区 · 排序键 批量入库 异步 · 幂等 实时聚合 物化视图 · Aggregating 关键参数与策略 分区键:toYYYYMMDD(ts) | 排序键:(exchange, symbol, ts) | 引擎:ReplacingMergeTree / AggregatingMergeTree 写入:批量攒批、异步插入、Kafka 引擎 | 聚合:分钟 OHLC、成交量排行 | 服务:查询 API + 缓存 常见误区 单行插入 · 滥用 Nullable 忽视乱序 · 当 KV 点查 学习目标 建模 · 高吞吐入库 实时聚合 · 查询优化 课程主线 场景 → 建模 → 入库 → 聚合 → 优化 → 实战

当你完成本章学习,应当能够清晰描述行情数据从产生到消费的完整链路,理解 ClickHouse 在该链路中承担的角色,并知道后续每一章要解决的具体问题。接下来,我们将从行情数据的字段体系与查询模式出发,进入建模的第一站。