MySQL 单表行数真相:2000 万限制是伪命题吗?
在数据库设计讨论中,"单表不能超过 2000 万行" 这句话出现的频率极高。很多架构师甚至将其作为硬性红线。但作为一名在一线摸爬滚打多年的工程师,我想说:这其实是一个被过度简化的经验值,而非绝对真理。
今天我们就来聊聊这个误区背后的真实逻辑,看看什么情况下真的需要拆分,什么情况下完全可以放心大胆地存。
MySQL 单表行数的三大核心误区
一、误区 1:混淆'行数'与'性能'(最常见、最致命)
1.1 为什么混淆'行数'与'性能'如此普遍?
- 习惯使然:早期 MySQL 版本或硬件条件下,大表确实慢,导致大家形成了条件反射。
- 缺乏数据支撑:很多人没做过压力测试,直接引用网上的旧闻。
- 认知偏差:认为'行数越多,性能越差',忽略了索引和查询优化才是关键。
实际上,如果查询走对了索引,百万级甚至千万级的数据量,响应时间依然可以控制在毫秒级。反之,如果没有索引,哪怕只有一万行,全表扫描也能把 CPU 打满。
1.2 代码示例:如何判断是否真的慢?
不要盲目猜,用 EXPLAIN 说话。下面是一个典型的慢查询排查思路:
-- 开启慢查询日志,定位耗时 SQL
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
-- 分析执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 123456;
重点看 type 字段。如果是 ALL,说明走了全表扫描,这时候行数多了才真会慢;如果是 ref 或 range,说明索引生效了,行数再多影响也有限。
二、误区 2:硬件瓶颈就是行数瓶颈
很多人觉得服务器内存不够、磁盘 IO 慢,是因为表太大了。其实不然。
InnoDB 引擎的页大小固定为 16KB。只要你的热点数据能放进 Buffer Pool(缓冲池),读取速度就和行数关系不大。真正的问题往往在于:
- Buffer Pool 命中率下降:数据量远超内存容量,频繁发生磁盘 IO。
- 主键膨胀:自增 ID 过长或者 UUID 做主键,导致索引树变高,IO 次数增加。
所以,与其担心行数,不如先检查你的 innodb_buffer_pool_size 配置是否合理。
三、误区 3:分库分表是万能药
看到大表就切分,这是很多初级架构师的通病。分库分表带来的复杂度是指数级上升的:
- 事务一致性难保证
- 跨库 Join 几乎不可用
- 运维成本激增
什么时候该分? 只有当单表超过 5000 万行,且业务场景明确无法通过索引优化解决时,再考虑分片。在此之前,优先尝试优化索引、读写分离或归档历史数据。


