TiDB 会尽量把业务负载分布到不同的计算与存储节点,但负载均衡并不能消除所有访问模式带来的倾斜。如果大量请求集中在少数节点或 Region 上,局部资源就会先耗尽,形成热点。处理热点的目的,是让系统已有资源更充分地参与工作,改善吞吐与延迟。性能问题是否真的来自热点,仍需要先用监控确认。
本文基于 PingCAP 及 TiDB 文档贡献者的中文文档完整核查整理,以官方 release-8.5 文档源文件为依据,核对日期为 2026 年 10 月 5 日。官网页面读取失败,改用官方仓库完整源文。版本提醒:CPU 热点调度在 v8.5.7 才引入,不能套用到更早的 v8.5 补丁版本。

先理解表和索引为什么会变热
原文从 TiDB 键值编码解释热点。TiDB 为表分配 TableID,为索引分配 IndexID,为每行分配 RowID;表 ID 在集群中唯一,索引 ID 和行 ID 在表内唯一。原文用整数 RowID 模型说明常见情况:记录的 Key 包含表 ID、记录前缀和 RowID,Value 保存列值。
Key: tablePrefix{TableID}_recordPrefixSep{RowID}
Value: [col1, col2, col3, col4]
tablePrefix 与 recordPrefixSep 是区分键空间的字符串常量。对于唯一索引,原文给出的简化编码是把索引列值放进 Key,把 RowID 放进 Value:
Key: tablePrefix{TableID}_indexPrefixSep{IndexID}_indexedColumnsValue
Value: rowID
非唯一索引允许多行具有相同索引值,还需要把 RowID 接到 Key 后,以区分记录:
Key: tablePrefix{TableID}_indexPrefixSep{IndexID}_indexedColumnsValue_rowID
Value: null
编者说明:这是用于解释热点的简化编码,不能把所有聚簇主键形态都理解成一个整数 RowID。选择方案时,必须确认是否有聚簇主键、是否使用隐式 RowID,以及具体索引结构。
同一表的记录位于以 TableID 开头的键范围内,按行键顺序排列。如果 RowID 递增,新记录持续追加到键范围末端。即使末端 Region 因体积增长而分裂,后续写入仍追随最新的末端 Region,热点会随之移动,而不会自动成为均匀写入。
自增整数主键是典型场景。使用隐式自增 RowID 的表也可能出现同类问题。索引有独立的写热点:例如按时间单调增长的索引列,或集中插入大量重复索引值。打散记录行键,不等于二级索引的键分布也改变了。
新建表或分区的写热点、只读场景周期性出现的读热点,还可能与 Region 合并有关。原文提供使用表属性控制 Region 合并的补充入口,应先核对具体场景,再调整表属性。
先确认热点,再用 Dashboard 缩小范围
性能下降并不必然意味着热点,也可能由多个因素叠加。写热点可从 TiKV-Trouble-Shooting 的 Hot Write 区域入手,观察 Raftstore CPU 是否有个别 TiKV 显著高于其他节点。读热点则查看 TiKV-Details 的 Thread_CPU,比较各节点的 coprocessor CPU。
确认节点负载不均后,打开 TiDB Dashboard 的流量可视化。热力图横轴是时间,纵轴是表和索引对应的键范围,颜色越亮表示流量越大;工具栏可切换读写流量。
- 写流量中的明亮斜线或阶梯,常对应递增键写入随着 Region 分裂向末端移动,需要结合表结构确认。
- 读流量中的明亮横线,常见于持续被大量访问的小表。
- 鼠标移到亮色块上,可查看对应表或索引,再把监控现象与实际查询关联。
原文八张 Dashboard 示例图展示了定位及调整前后的热力图。本稿采用独立示意图讲解机制,没有把原文示例当作本次测量结果;原图可在文末官方源文查看。
隐式 RowID 的写热点:SHARD_ROW_ID_BITS
没有主键,或使用 NONCLUSTERED 主键的表,可使用 TiDB 自动分配的隐式 64 位整数 RowID。大量插入时,递增 RowID 会使写入集中在单个 Region。SHARD_ROW_ID_BITS 改变 RowID 的生成方式,把新行键分散到多个范围,缓解这一热点。
| 设置 | 原文中的分片数含义 |
|---|---|
SHARD_ROW_ID_BITS = 0 |
默认,1 个分片 |
SHARD_ROW_ID_BITS = 4 |
16 个分片 |
SHARD_ROW_ID_BITS = 6 |
64 个分片 |
下列建表与修改语法是两个不同场景,不要求连续执行:
-- 在隔离测试库创建演示表
CREATE TABLE t (c INT) SHARD_ROW_ID_BITS = 4;
-- 对已有且符合条件的表调整配置
ALTER TABLE t SHARD_ROW_ID_BITS = 4;
编辑差异:原稿行内“CREATE TABLE:”和“ALTER TABLE:”是说明标签,本稿改为注释和干净 SQL,避免被误作语句执行。代码未执行。
该值可以动态修改,但只影响之后新写入的数据,不会自动重排历史数据。CLUSTERED 主键直接作为行键,不能用此选项改变其生成方式;NONCLUSTERED 主键使用隐式 RowID 时才符合此处条件。
编者补充:分片数不是节点数,也不是立刻存在的 Region 数。是否需要预分裂、历史数据如何分布、写入是否集中在二级索引,都应结合容量与负载核验。示例中的 4 或 6 不是通用推荐值。
自增主键的写热点:AUTO_RANDOM
如果主键只用于保证唯一性,不承载顺序等业务含义,可考虑以 AUTO_RANDOM 代替 AUTO_INCREMENT。TiDB 会生成更离散、在可用空间耗尽前不重复的主键,让插入进入不同键范围。
CREATE TABLE t (
a BIGINT PRIMARY KEY AUTO_RANDOM,
b VARCHAR(255)
);
INSERT INTO t (b) VALUES ('foo');
SELECT * FROM t;
SELECT LAST_INSERT_ID();
新主键不再自增。可用 LAST_INSERT_ID() 取得本会话上次分配的主键。本稿以单引号表示字符串,避免启用 ANSI_QUOTES 时双引号被解释为标识符。
原文勘误:源文插入 "foo",所列结果的 b 列却显示 b,前后不一致。本稿在文末照录该结果表并标明原文错误,不伪造运行输出;随机主键数值也不应当作可重复结果。改造已有表还应核对 AUTO_RANDOM 限制,不能把新建表语法理解为所有现有主键均可无缝转换。
读热点:缓存、副本读取、CPU 调度与 MVCC
对于大量读取的小表,原文推荐考虑 Coprocessor Cache。它在 TiDB 实例侧缓存下推给 TiKV 的计算结果,减少重复计算。效果取决于查询和缓存适用条件,不代表所有读取都会命中缓存。
另一类问题是热点 TiKV 处理不及时、读请求排队,但其他 TiKV 尚有资源。原文说明 v7.1.0 引入负载自适应副本读取:当 leader 预估排队时间超过 tidb_load_based_replica_read_threshold 时,TiDB 优先从 follower 读取。原文链接又把该变量标为“从 v7.0.0 引入”;功能描述版本与变量引入版本并非同一说法,部署时应按实际版本核对。
原文报告某些读热点场景吞吐量可提升 70%~200%。这是原文效果陈述,不是本次实测,也不是对任意硬件、负载和副本布局的保证。应同时观察吞吐、尾延迟、CPU 与网络开销。
从 v8.5.7 起,PD 可依据 TiKV 在 Store 心跳中上报的热点 Region 读 CPU 使用情况进行调度。它可以识别 QPS、字节量看似均衡,而计算开销仍不均衡的场景,例如不同节点处理不同负载模式。
- 支持上报读 CPU 时,
balance-hot-region-scheduler默认read-priorities为cpu,byte。 - 不支持时回退到
query,byte;若也不支持 query 维度,再回退到byte,key。 - 查看或调整的官方入口是
pd-ctl scheduler config balance-hot-region-scheduler。本文没有运行调度变更。
读热点还可能来自多版本扫描。GC 历史版本保留过长,或频繁更新、删除,会导致扫描大量 MVCC 版本。原文针对此类情况指向 TiKV MVCC 内存引擎,不应只反复调整主键分布。
用相同指标验证改变
编者补充:调整前保留表结构、索引、热点时间段、SQL 负载、CPU、QPS 和延迟基线;调整后在可比较负载下复查。表结构与调度变更应有容量评估和回退方案。本次只做静态审核,没有连接 TiDB、执行 SQL、修改 PD 或复现性能数字。
进一步资料:高并发写入最佳实践、Split Region、SHARD_ROW_ID_BITS、聚簇索引。
来源、作者与许可
原文:TiDB 热点问题处理;本次完整读取:官方 release-8.5 源文件。作者归属:PingCAP 及 TiDB 文档贡献者。未完纪调整了结构、代码注释、字符串引号和不一致的输出展示,并加入已标识的审核说明。
该分支 LICENSE 为 CC BY-SA 3.0 Unported,本篇改编正文与原创示意图按同一许可提供,保留署名、来源和修改说明;按原样提供,不作保证,也不暗示 PingCAP 背书。
原文历史输出及勘误
为完整保留源文,下面照录其两张结果表。第一表b列为b,与源文INSERT的foo不一致;这里保留错误并指出,不是修复后的实测输出。随机ID1073741825仅为原文示例。
+------------+---+ | a | b | +------------+---+ | 1073741825 | b | +------------+---+ +------------------+ | LAST_INSERT_ID() | +------------------+ | 1073741825 | +------------------+
原文 Dashboard 热力图
以下八幅为PingCAP官方release-8.5文档原图,图像未修改;中文图注由未完纪补充。它们是源文历史示例,并非本次测试。图片按CC BY-SA 3.0 Unported随文提供。




















暂无评论内容