必须用set statistics xml on实际执行存储过程获取真实执行计划,而非估计计划;重点关注actualrows与estimaterows偏差、table spool/sort节点及缓存重用率,结合extended events和dmv定位参数嗅探、隐式转换等根本问题。

SQL存储过程的执行流水线不是一条“黑盒路径”,而是由数据库引擎分层拆解、逐级推进的过程。想定位慢、查异常、调性能,必须知道每个环节干了什么、卡在哪、怎么验证。
SQL Server里看执行计划:从SET STATISTICS XML ON开始
存储过程不像单条SQL能直接用EXPLAIN,得先让它吐出实际执行计划。最稳的方式是打开统计开关再执行:
-
SET STATISTICS XML ON后运行EXEC usp_myproc @param = 123,结果面板会多出一个“Execution plan”标签页 - 别信“估计执行计划”——它不走真实数据路径,尤其涉及临时表、参数嗅探时偏差极大
- 重点关注
<relop></relop>节点里的ActualRowsvsEstimateRows,差距超5倍基本说明统计信息过期或参数值导致计划偏差 - 如果看到
Table Spool (Eager)或Sort出现在高频路径上,大概率是缺少索引或ORDER BY没走覆盖索引
MySQL中查SHOW PROFILES和performance_schema
MySQL没有原生存储过程执行计划视图,得靠时间切片+事件追踪双管齐下:
- 先开
SET profiling = 1,再执行存储过程,然后SHOW PROFILES列出各阶段耗时 - 挑出最慢的Query ID,用
SHOW PROFILE FOR QUERY n看CPU、block io、context switches等细分开销 - 真正要深挖,得查
performance_schema.events_statements_history_long,过滤sql_text LIKE '%usp_%',确认是否被隐式转换、锁等待或临时表写磁盘拖慢 - 注意:
performance_schema默认可能关闭部分instrument,需提前启用setup_instruments里的statement/sp/%和wait/io/file/%
PostgreSQL用EXPLAIN (ANALYZE, BUFFERS)抓真实行为
PostgreSQL对存储过程支持有限(本质是函数调用),但只要过程内含SQL,就能用EXPLAIN穿透进去:
- 直接对过程内关键查询加
EXPLAIN (ANALYZE, BUFFERS),比如EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM tmp_calc WHERE status = 'done'; - 关注
Shared Hit/Read比例,若Read占比高,说明缓存没打满或数据局部性差 - 临时表
CREATE TEMP TABLE t1 ON COMMIT DROP后没建索引?执行计划里会出现Seq Scan on t1——这是典型信号 - 避免在
EXPLAIN里嵌套调用其他函数,否则输出会截断;拆成独立语句测更准
所有数据库都绕不开的共性瓶颈点
流水线里最常被忽略的不是语法或索引,而是中间状态管理:
- 临时表字段含NULL?后续
JOIN或WHERE col = @val会漏数据——一律改用IS NULL或COALESCE(col, '')显式处理 - SQL Server里用
##temp?并发调用时A过程写的行,B过程SELECT *可能读到——必须换#temp并确认连接未复用 - MySQL临时表用了
BLOB字段?引擎自动退化为MyISAM,触发磁盘临时表——换成VARCHAR(1000)或拆字段 - PostgreSQL临时表忘了
ON COMMIT DROP?第二次执行报relation "t1" already exists——不是语法错,是生命周期失控
执行流水线真正的复杂点不在某一层,而在层与层之间传递的状态:参数值如何影响计划选择、临时表何时物化、事务边界怎样切割日志写入。这些细节不会出现在文档目录里,只藏在ActualRows和Shared Read的数字背后。











