























有些线上问题,表面上看只是 SQL 变慢,实际上背后却隐藏着数据库底层存储结构的问题。
前段时间,我们在生产环境就遇到过一次典型案例:
一张访问量并不算高的业务表,查询RT(响应时间)却突然飙升,甚至出现了大量 IO 等待。最开始大家都以为是索引失效、慢查询或者buffer pool不够,但最终定位下来,真正的问题居然是 —— InnoDB 溢出页(Overflow Page)。
这篇文章通过真实排查思路,聊聊这个问题是怎么出现的,又是如何一步步被定位出来的。
业务里有一张订单扩展表,大概结构如下:
CREATE TABLE order_ext (
id BIGINT PRIMARY KEY,
order_id BIGINT,
ext_info LONGTEXT,
create_time DATETIME,
KEY idx_order_id(order_id)
);
其中 ext_info 用来存储订单扩展信息,包括:
上线初期数据量不大,一切正常。
但随着业务增长,问题开始逐渐暴露:
order_id 查询越来越慢更奇怪的是:
SELECT id, order_id
FROM order_ext
WHERE order_id = ?;
这种只查普通字段、不查 LONGTEXT 的 SQL,也开始变慢。
这就有点反常了。
首先查看执行计划:
EXPLAIN SELECT id, order_id
FROM order_ext
WHERE order_id = 10001;
结果显示:
看起来没任何异常。
接着查看:
依旧没有发现明显问题。
直到后来,我们注意到一个现象:
这张表的单行记录异常大。
继续分析表结构后发现:
LONGTEXT
字段里存储了大量 JSON 数据。
有些记录甚至超过了几十 KB。
而 InnoDB 的数据页默认只有:
16KB
也就是说:
一行数据根本塞不进一个普通数据页。
这时候,InnoDB 就会启动一种机制:
溢出页(Overflow Page)
简单来说:
当一行数据太大,普通页放不下时,InnoDB 会把超长字段拆出去,单独存储到其他页中。
原始数据页里,只保留:
真正的大字段内容,则放在“溢出页”里。
大概可以理解成这样:

很多人会有一个误区:
“我又没查询 TEXT 字段,为什么也会慢?”
原因在于:
虽然 SQL 没查大字段,但:
更关键的是:
某些场景下,InnoDB仍然需要访问溢出页。
比如:
一旦大量随机 IO 打到磁盘,性能就会迅速恶化。
这部分稍微深入一点。
InnoDB 并不是所有 TEXT/BLOB 都直接放溢出页。
它会根据:
综合决定。
常见行格式包括:
其中:
会在数据页中保留:
768 字节前缀
剩余部分放到溢出页。
因此:
即使字段非常大,主页里仍然会保留部分内容。
这是 MySQL 5.7/8.0 更推荐的方式。
它会:
这样能让主页更“轻”。
很多线上库升级后性能改善,其实就和这个有关。
后来继续分析发现:
业务表存在几个典型问题。
最初:
{"status":"ok"}
后来逐渐变成:
{
"risk": {...},
"audit": {...},
"third_response": {...},
...
}
单条数据越来越大。
实际上:
业务查询只关心:
但每次回表时:
大字段依然跟着存储在同一行逻辑结构里。
导致热点数据缓存效率越来越差。
正常情况下:
16KB 页可以放很多记录。
但有大量大字段后:
一个页只能放几条记录。
buffer pool很快被“低效占用”。
最后,我们用了几个手段解决问题。
这是最有效的方法。
把:
ext_info LONGTEXT
拆到独立表:
order_ext_detail
主表只保留核心查询字段。
效果非常明显:
这也是线上最推荐的方案。
很多业务喜欢把所有数据直接塞JSON。
但实际上:
这类内容:
不要全部堆进MySQL。
检查表:
SHOW TABLE STATUS LIKE 'order_ext';
如果不是:
ROW_FORMAT=DYNAMIC
建议调整:
ALTER TABLE order_ext ROW_FORMAT=DYNAMIC;
这样可以减少主页占用。
比如:
SELECT *
非常容易把大字段一起带出来。
线上最好:
否则即使SQL看起来简单,也可能触发大量IO。
很多MySQL性能问题,本质并不是:
而是:
数据组织方式已经不适合当前业务规模。
尤其在业务快速发展后:
这些字段非常容易成为隐藏炸弹。
平时数据量小时没感觉。
一旦数据规模上来:
问题会集中爆发。
溢出页本身并不是问题。
真正的问题是:
大字段被无节制地放进核心业务表。
线上排查MySQL性能问题时,如果出现:
除了索引和SQL之外,也建议关注:
很多“查不出原因”的慢查询,最后根因都藏在这里。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。