sending data 状态本质是mysql在收集并发送数据,常见于回表读取、结果整理或锁等待;需结合show processlist、explain、show profile及innodb_trx等定位真实瓶颈,而非直接kill。

Sending data 状态不是网络传输卡住,而是 MySQL 正在“收集 + 发送”数据——它可能刚查完索引拿到 ID,正回表读完整行;也可能在整理结果集、做排序或聚合;甚至可能被锁住动不了。直接 kill 进程治标不治本,得先定位真实瓶颈。
用 SHOW PROCESSLIST 快速确认是否真卡在 Sending data
执行 SHOW PROCESSLIST;,重点关注 State 列为 Sending data 且 Time 持续增长的线程:
- 如果 Time 几秒内就变,大概率是正常中间状态;
- 如果卡住 10 秒以上,尤其伴随 CPU 或 I/O 负载升高,就要深入了;
- 注意区分 Sending data 和 Locked、Updating —— 后两者说明是锁或写阻塞,前者更可能是读路径问题。
用 EXPLAIN 和 SHOW PROFILE 定位耗时环节
EXPLAIN 只能看执行计划是否走索引,但看不出 Sending data 具体花在哪。必须配合 SHOW PROFILE:
- 先开启: SET profiling = ON;
- 执行慢查询(确保是复现问题的那条);
- 查 SHOW PROFILES; 拿到 Query_ID;
- 再执行 SHOW PROFILE FOR QUERY N;(N 是 Query_ID),重点看 Sending data 和 Creating sort index 的耗时占比;
- 如果 Sending data 占比 >80%,基本可排除网络和客户端,聚焦在“回表读取”或“大字段拖累”上。
检查是否因大字段或低效返回导致回表开销爆炸
这是最常被忽略的点:
- Sending data 高耗时,往往是因为 SELECT 的列没被索引覆盖,MySQL 得根据索引 ID 一条条回主键 B+ 树读整行;
- 尤其当存在 VARCHAR(8000)、TEXT、BLOB 类型字段时,哪怕只查 10 行,每行都得加载几 KB 数据,I/O 和内存拷贝量剧增;
- 实测案例:去掉一个 description 字段,查询从 216 秒降到 15 秒;
- 解决办法:
• 改 SELECT * 为明确列出所需字段;
• 对高频查询字段建覆盖索引(INDEX (a,b,c) 包含所有 SELECT 列);
• 把大字段挪到单独的扩展表,主表只留 ID 和关键标识。
排查锁等待与 Event Scheduler 干扰
某些情况下 Sending data 是假象,实际进程被堵住了:
- 执行 SELECT * FROM information_schema.INNODB_TRX; 查是否有长事务未提交;
- 执行 SELECT * FROM information_schema.INNODB_LOCK_WAITS; 看是否被其他事务阻塞;
- 特别注意 MySQL Event Scheduler:如果后台事件(比如每分钟跑一次的 UPDATE)没结束,它可能长期持有 MDL 锁或行锁,导致后续查询卡在 Sending data 等锁释放;
- 查看 SHOW VARIABLES LIKE 'event_scheduler';,临时关掉 SET GLOBAL event_scheduler = OFF; 观察是否缓解。
真正难的不是识别 Sending data,而是判断它背后到底是回表、锁、大字段,还是 Event Scheduler 在后台偷偷拖垮整个实例——这些原因的表现几乎一样,但修复方式完全不同。











