
我把 TiDB 从 MySQL 兼容层切到 HTAP 引擎后复杂报表查询从 23 秒压到 1.2 秒说实话之前我一直把 TiDB 当能水平扩展的 MySQL来用。行存、事务、兼容 MySQL 协议业务迁移几乎不用改代码。直到上个月财务对账报表在月底被产品经理截图发到群里一条 SQL 跑了 23 秒页面一直转圈。我才意识到 TiDB 真正的杀手锏不是兼容 MySQL而是它旁边那个叫 TiFlash 的 HTAP 列存引擎。问题现场行存跑宽表聚合就是在硬扛我们有一张orders订单表大概 1.2 亿行字段 40 多个。财务要拉一份按省份 品类 支付渠道的汇总报表SQL 看起来人畜无害SELECTprovince,category,pay_channel,COUNT(*)ASorder_cnt,SUM(amount)AStotal_amount,AVG(amount)ASavg_amountFROMordersWHEREorder_dateBETWEEN2026-06-01AND2026-06-30GROUPBYprovince,category,pay_channelORDERBYtotal_amountDESCLIMIT200;这条语句在 TiDB 的 TiKV 行存引擎上执行 Explain 一拉全表扫描 临时排序23 秒。我加过联合索引也试过covering index但宽表聚合扫描的数据量太大索引回表反而更慢。这就是行存引擎的物理限制它擅长点查和短范围查不擅长扫一堆列做 GROUP BY。TiDB 其实早就给了答案同一套数据在 TiFlash 里存一份列存副本复杂分析查询直接走列存 MPP 并行计算。切换过程比我想象中少改很多代码我们的 TiDB 集群是 7.5 版本 TiFlash 节点已经部署好了。如果没部署用 TiUP 也很简单# 已有 TiUP 环境scale-out tiup-cluster topology.yaml--roletiflash真正要做的就三步。1. 给表加 TiFlash 副本ALTERTABLEordersSETTIFLASH REPLICA1;这条语句执行后TiDB 会通过 Raft 把 TiKV 上的数据异步复制到 TiFlash。因为是 Learner 角色不影响 OLTP 写入的性能。可以用下面 SQL 看同步进度SELECT*FROMinformation_schema.tiflash_replicaWHERETABLE_SCHEMAdb1ANDTABLE_NAMEorders;等AVAILABLE变成1就可以开始测查询了。我这张 1.2 亿行的表大概 10 分钟后副本同步完成。2. 让优化器选择 TiFlashTiDB 的优化器会自动根据代价模型决定走 TiKV 还是 TiFlash。如果它没选对可以用 Hint 强制走 TiFlashSELECT/* read_from_storage(tiflash[orders]) */...FROMordersWHERE...GROUPBY...;但我一般先用EXPLAIN看执行计划EXPLAINANALYZESELECTprovince,category,pay_channel,...FROMordersWHEREorder_dateBETWEEN...GROUPBY...;如果看到ExchangeSender/ExchangeReceiver和Projection_前面带有tiflash_task说明 MPP 模式已经生效。这种模式下聚合会在 TiFlash 节点本地做然后通过网络汇总而不是把所有原始行拉到 TiDB Server 再算。3. 改写几个拖慢查询的写法原 SQL 里有个LIMIT 200加ORDER BY total_amount DESC。在 TiFlash 里如果让聚合和排序都下推到列存节点效果最好。我顺便把order_date上的表达式做了简化SELECT/* read_from_storage(tiflash[orders]) */province,category,pay_channel,COUNT(*)ASorder_cnt,SUM(amount)AStotal_amount,ROUND(AVG(amount),2)ASavg_amountFROMordersWHEREorder_date2026-06-01ANDorder_date2026-07-01GROUPBYprovince,category,pay_channelORDERBYtotal_amountDESCLIMIT200;改完后 Explain 里出现了ExchangeType: HashPartition说明 GROUP BY 被拆到多个 TiFlash 节点并行聚合。这才是 HTAP 该有的样子。效果不是快一点是快一个数量级同一个查询、同一张表、同一个业务高峰指标TiKV 行存TiFlash 列存 MPP变化平均查询耗时23.1 s1.2 s-95 %P9928.4 s1.5 s-95 %TiDB Server CPU78 %11 %-86 %扫描行数回传1.2 亿行聚合后约 2 万行巨量下降财务同学说报表页面从泡杯咖啡回来变成了秒开。踩坑记录别只改引擎不改用法TiFlash 不是实时副本默认异步复制延迟通常 1 秒以内。如果你的报表要求必须读到刚刚写入的数据需要用AS OF TIMESTAMP或者在写入后强制同步否则会出现短暂不一致。某些函数 TiFlash 不支持比如部分 JSON 函数、空间函数、某些自定义字符集函数。如果 Optimizer 自动选择 TiFlash 后报错可以用read_from_storage(tikv[table])Hint 强制回退。优化器偶尔会选错引擎小表或高选择性点查TiKV 反而更快。别一看到 TiFlash 就想把所有 SQL 都塞过去。我一般只对扫描行数 50 万、聚合列多的报表 SQL 加 Hint。TiFlash 会占用额外磁盘和内存列存压缩比通常比行存高但内存用于缓存和 MPP 计算。我们给 TiFlash 节点单独配了 64 GB 内存和 NVMe SSD避免和 TiKV 抢资源。MPP 不是所有场景都生效如果 SQL 里混用了 TiFlash 不支持的函数整个 MPP 计划会被拆掉退化成单机执行。上线前必须用EXPLAIN确认ExchangeSender存在。写在最后TiDB 的 HTAP 不是魔法。它只是在同一个集群里塞进了两套存储引擎TiKV 继续扛 OLTPTiFlash 扛 OLAP。真正的收益来自把合适的查询路由到合适的引擎。如果你的 TiDB 集群里也有人抱怨报表怎么这么慢别急着加机器先拉一条 EXPLAIN 看看。也许问题不是 SQL 写得烂而是它跑错了引擎。下一步我准备把几张日志宽表也迁到 TiFlash把审计类查询再统一收拢。到时候再写一篇踩坑实录。