2000万行是三层b+树在典型配置下的容量临界点,非硬性上限;按16kb页、bigint主键(8字节)+4字节指针、每行约1kb估算,三层容量为1280×1280×15≈2457万行,“2000万”为取整经验数。

2000万行不是硬性上限,而是三层 B+Tree 在典型数据分布下的容量临界点;超过它,B+Tree 很可能升到四层,但真正影响性能的不是“多一次IO”,而是高并发下 SMO(结构修改操作)引发的锁争用。
为什么三层 B+Tree 对应约 2457 万行?
这个数字来自 InnoDB 默认页大小(16KB)和常见字段宽度的估算:
- 非叶子节点:主键
bigint(8 字节) + 页指针(4 字节) ≈ 12 字节/条 → 每页存约1280条索引项 - 叶子节点:假设平均每行记录约
1KB→ 每页存约15行 - 三层结构总容量 =
1280 × 1280 × 15 ≈ 24,576,000行
“2000万”是取整后的经验数,方便记忆和落地。实际值取决于 row_format、utf8mb4 字段长度、是否含大字段(TEXT/BLOB)等——这些都会压缩单页有效载荷,提前触发树增高。
B+Tree 从 3 层变 4 层,查询真会慢很多吗?
在纯 SSD 环境下,3 次 vs 4 次随机 IO 的延迟差异已不显著(现代 NVMe 延迟常低于 100μs)。但以下情况会让“第 4 层”变得敏感:
- 查询未命中 Buffer Pool,必须走磁盘:此时 IO 次数直接线性影响响应时间
- 二级索引回表路径变长:先查二级索引页(可能已 4 层),再查聚簇索引(又可能 4 层),放大延迟
- 范围扫描(
WHERE created_at BETWEEN ...)需遍历多个叶子页:树深度增加会提高页间跳转开销,尤其当叶子页物理不连续时
注意:EXPLAIN 显示的 type: range 或 type: index 并不反映树深度,只反映访问方式;真实深度需用 SELECT COUNT(*) FROM information_schema.INNODB_SYS_INDEXES WHERE TABLE_NAME = 'your_table' 结合 stat_n_diff_key_vals 间接推测。
比 IO 更致命的是 SMO 导致的写入阻塞
很多人盯着“B+Tree 深度”,却忽略了 InnoDB 写入时真正的瓶颈:SMO(Split/Merge)操作必须加 SX 锁,从根节点一路锁到叶子节点。这意味着:
- 哪怕只是插入一条新记录,只要触发页分裂,就会短暂阻塞其他所有写入请求
- 单表越大,活跃数据页越分散,Buffer Pool 中热页比例越低 → 更多 SMO 发生在磁盘页上,耗时更长
- 高并发写入场景下,SMO 成为串行化热点,TPS 不再随 CPU/IO 提升而线性增长
这就是为什么一个 1500 万行但写入密集的订单表,可能比一个 3000 万行但只读为主的日志表更早出问题——SMO 频率与数据分布、更新模式强相关,和绝对行数无直接线性关系。
真正该盯的不是“有没有到 2000 万”,而是 innodb_row_lock_waits 是否持续上升、SHOW ENGINE INNODB STATUS 里是否有大量 LOCK WAIT 记录、以及慢日志中写入语句的 Rows_examined 是否异常偏高。这些信号比行数更早暴露 SMO 压力。











