卡在“Sending data”不是网络问题,而是MySQL正从存储引擎读取、组装数据,耗时主因是回表、大字段加载或Buffer Pool不足;需用SHOW FULL PROCESSLIST和SHOW PROFILE精确定位,并检查覆盖索引与innodb_buffer_pool_size配置。

卡在 Sending data 不是网络问题,而是 MySQL 正在从存储引擎读取、组装并准备返回数据——真正耗时的环节往往藏在“回表”“大字段加载”或“Buffer Pool 不足”里。
用 SHOW FULL PROCESSLIST 快速确认是不是真卡住
别只看 SHOW PROCESSLIST,它默认截断 SQL 到 100 字符,关键 WHERE 条件可能被砍掉。必须加 FULL:
SHOW FULL PROCESSLIST;
重点关注三列:
-
State是Sending data且Time持续上涨(>10 秒); -
Command是Query,不是Sleep或Connect; -
Info列里有没有SELECT *、LIMIT偏移很大、或明显没走索引的 JOIN。
如果 Time 几秒内就跳变,大概率只是中间状态;如果卡住不动又伴随 iostat -x 1 显示 %util 接近 100%,说明 I/O 真在扛不住。
用 SHOW PROFILE 精确定位 Sending data 耗在哪一环
EXPLAIN 只告诉你“计划怎么走”,看不出 Sending data 里实际花了多少时间在磁盘读、内存拷贝或行构造上。必须用 SHOW PROFILE:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 先开启:
SET profiling = ON; - 复现那条慢 SQL(确保是同一个会话);
- 查
SHOW PROFILES;拿到对应Query_ID; - 再执行:
SHOW PROFILE FOR QUERY N;(N 是你看到的 ID)
重点看两行:
-
Sending data占比 >80%:基本排除网络,聚焦回表、大字段、Buffer Pool 不够; -
Creating sort index或Coping to tmp table高:说明ORDER BY/GROUP BY没走索引,或结果集太大撑爆内存。
检查是否因回表 + 大字段导致 I/O 爆炸
这是最常被忽略的点:Sending data 高耗时,90% 以上是因为 MySQL 找到索引 ID 后,还得一条条回主键 B+ 树把整行捞出来——尤其当 SELECT 包含 TEXT、BLOB 或超长 VARCHAR 时,哪怕只返回 10 行,每行几 KB,I/O 和内存压力就上来了。
- 查执行计划:
EXPLAIN看Extra是否有Using where; Using index(覆盖索引),还是只有Using where(要回表); - 临时验证:把
SELECT *改成只选 2–3 个关键字段,再跑一次SHOW PROFILE,如果Sending data时间骤降,就是这个原因; - 长期解法:
ALTER TABLE t ADD INDEX idx_cover (a,b,c),确保索引包含所有 SELECT 列;或者把大字段拆到扩展表,主表只留 ID 和标识字段。
别漏掉 innodb_buffer_pool_size 这个硬门槛
即使索引和 SQL 都没问题,如果 innodb_buffer_pool_size 设置太小(比如默认的 32M 或 128M),而你要查的表远大于这个值,MySQL 就得反复刷盘读页——Sending data 时间会直接和磁盘 I/O 绑定。
- 查当前值:
SHOW VARIABLES LIKE 'innodb_buffer_pool_size'; - 估算需覆盖的热数据量:用
SELECT table_schema, table_name, round(((data_length + index_length) / 1024 / 1024), 2) AS MB FROM information_schema.TABLES WHERE table_schema = 'your_db' ORDER BY MB DESC; - 调大原则:物理内存的 50%–75%,但别超过可用内存,否则触发 swap 更慢;
- 改完必须重启 MySQL 生效,不能动态 SET。
很多线上事故里,Sending data 从 3 秒降到 0.3 秒,就靠这一项调整——但它掩盖了 SQL 和索引的问题,所以优先级排在回表和覆盖索引之后。

















