sending data并非仅指网络发送,而是涵盖从存储引擎读取数据、组装结果集到发送客户端的全过程;真正瓶颈常在回表查大字段、无效行扫描或结果集膨胀。

为什么Sending data不等于“正在发数据”
这个状态名有严重误导性——Sending data 实际涵盖“从存储引擎读取行数据 + 组装结果集 + 发送给客户端”全过程。真正卡住的,往往不是网络发送,而是前面两步:反复回表查大字段、扫描大量无效行、或结果集膨胀到内存扛不住。
用SHOW FULL PROCESSLIST快速抓活口
直接执行:
mysql -e "SHOW FULL PROCESSLIST" | grep "Sending data"重点关注三项:
-
Time值持续上涨(比如 > 30 秒还在涨),基本可判定卡在数据收集环节 -
Info字段看 SQL 是否含SELECT *、大TEXT/VARCHAR字段、没WHERE或LIMIT - 同一张表多个线程都卡在
Sending data?先排除该表被锁(查Waiting for table metadata lock)
EXPLAIN看不出问题,就用SHOW PROFILE切片时间
EXPLAIN 只告诉你“怎么走索引”,不告诉你“每步花多久”。开启性能剖析后执行慢查询:
SET profiling = ON;- 跑那条卡住的
SELECT -
SHOW PROFILES;找到对应Query_ID -
SHOW PROFILE FOR QUERY <code>xxx; 看Sending data行的耗时占比
如果这一项占总耗时 90%+,且 Handler_read_* 计数极高,说明是回表太狠或扫描行数爆炸。
最容易被忽略的三个坑
很多团队查半天索引、调缓冲池,却栽在这三处:
- 字段设计过大:
description是VARCHAR(8000),哪怕只查 10 行,每行都带这 8KB,内存拷贝和网络打包就拖垮整条链路 - 没设
LIMIT的分页查询:SELECT * FROM log WHERE status=1 ORDER BY id DESC在千万级表上,MySQL 得先排完全部结果再截前 20 条 - 客户端不拉取完结果就断连:MySQL 还得继续生成剩余数据,线程卡在
Sending data直到超时或被 kill
真要定位到具体哪列惹的祸,得结合 SHOW PROFILE 和字段类型逐个注释测试——别信“应该没问题”的直觉。











