真正卡住的不是存储过程本身,而是内部某条sql因索引失效、统计信息过期或隐式转换导致性能骤降;需用explain结合时间打点和行数诊断精准定位瓶颈。

CALL 执行时间变长,不是存储过程“变老了”,而是它内部某条 SQL 正在悄悄失效——90% 的慢速增长都源于索引失效、统计信息过期或隐式类型转换,而不是逻辑本身。
为什么 EXPLAIN 显示走索引,但实际执行还是慢?
EXPLAIN 的 type 是 ref 或 range,不代表真实执行时一定用上索引。常见干扰项:
-
WHERE col = @var中的用户变量会让优化器放弃选择性估算,强制退化为全表扫描;换成WHERE col = ?预编译调用,或用PREPARE ... EXECUTE动态拼接,才能触发准确计划 - 列是
utf8_unicode_ci,而传入字符串显式指定COLLATE utf8mb4_unicode_ci,MySQL 拒绝复用索引,必须逐行转码比对 -
rows字段显示 1000,但实际扫描 50 万行?说明统计信息严重滞后,运行ANALYZE TABLE table_name;强制刷新
怎么定位到底是哪条 SQL 在拖后腿?
别只看 CALL proc_name() 总耗时——它掩盖了内部执行分布。真实瓶颈往往藏在循环或条件分支里:
- 在每条关键
SELECT/UPDATE前加SELECT NOW(), 'before query_x';,对比时间戳间隔 - 用
GET DIAGNOSTICS @rowcount = ROW_COUNT();捕获上一条语句影响行数,再配合SLEEP(0.001)粗略估算单步耗时 - 禁用所有
INSERT INTO ... SELECT和临时表语句,逐个打开测试,观察耗时跳变点
临时表和 JSON 处理为何不报错却极慢?
这两类操作在 EXPLAIN 里几乎不显形,但 I/O 和 CPU 开销巨大:
-
CREATE TEMPORARY TABLE默认受tmp_table_size限制,超限即落盘;临时设SET SESSION tmp_table_size = 268435456;测试是否改善 -
JSON_EXTRACT(json_col, '$.status')在 WHERE 中过滤,比普通字段慢 3–5 倍;应提前冗余status VARCHAR(20)并建索引 - 循环中多次
INSERT INTO temp SELECT ...,不如攒成单条INSERT INTO temp VALUES (), (), ()
EXPLAIN + 时间打点 + 行数诊断。











