SQL Server中开启存储过程执行计划捕获需手动启用:先在查询窗口执行SET STATISTICS XML ON,再运行存储过程即可获取实际执行计划;注意避免动态SQL干扰、慎用生产环境,并推荐结合Extended Events(如sp_statement_completed+duration>1秒过滤)与缓存重用率分析(查sys.dm_exec_cached_plans等)定位根本问题。

SQL Server 中如何开启存储过程执行计划捕获
想看到存储过程里哪句 SQL 拖慢了整体,最直接的方式是拿到实际执行计划。但默认情况下,SQL Server 不自动保存或展示它——得手动打开开关。
关键不是“查执行计划”,而是让 SQL Server 在运行时把计划生成出来并可被你抓取。常见错误是只在 SSMS 里点“显示实际执行计划”,却没意识到:如果存储过程里有 SET NOCOUNT ON、动态 SQL 或嵌套调用,这个按钮可能根本捕获不到完整路径。
- 在查询窗口顶部加
SET STATISTICS XML ON,再执行存储过程,结果面板会多出一个“执行计划”标签页 - 避免在存储过程中用
EXEC(@sql)拼接语句,除非你同时开启SET STATISTICS XML ON并确保 @sql 是确定的(否则计划缓存不生效,每次都是新编译) - 生产环境慎用
SET STATISTICS XML ON,它会让每条语句都生成 XML 计划,增加 CPU 和网络开销;临时排查可用,别长期开着
用 Extended Events 抓取长时间运行的存储过程调用
SSMS 点几下只能看单次执行,真要监控线上行为,得靠轻量、可控的跟踪机制。Extended Events(XEvents)比 SQL Trace 更低开销,也比 Profiler 更稳定。
重点不是“建个 session 就完事”,而是选对事件和过滤条件。很多人建完发现日志爆炸,其实只是没加 duration 过滤或漏掉了 database_name 限定。
- 核心事件选
sp_statement_completed(精准到每条语句)或rpc_completed(只捕获存储过程级调用) - 必须加
WHERE [duration] > 1000000(单位微秒,即 >1 秒),否则会记录所有毫秒级调用,磁盘很快写满 - 用
query_hash字段聚合相似语句,能快速识别是某个逻辑反复变慢,而不是单次抖动
为什么 SQL Server 的“缓存计划重用率”比执行时间更值得盯
很多 DBA 一上来就看“哪个 SP 耗时最长”,结果优化完发现没改善——因为问题不在代码本身,而在计划没重用,每次都在编译。
典型表现是:同一个存储过程,参数不同,执行时间从 50ms 跳到 8s,sys.dm_exec_query_stats 里能看到大量相同 plan_handle 但不同 sql_handle 的记录。
- 检查是否用了局部变量代替参数(如
DECLARE @id INT = @input_id再用 @id 查询),这会导致参数化失效 - 留意
OPTION (RECOMPILE)是不是被误加在高频 SP 里,它强制每次编译,适合数据分布极不均的场景,但不适合常规 OLTP - 用
sys.dm_exec_cached_plans+sys.dm_exec_sql_text关联查缓存中同一 SP 的不同计划数量,>5 个就该警惕
MySQL 存储过程没法直接看执行计划?用 slow log + performance_schema 补位
MySQL 的存储过程不支持像 SQL Server 那样直接输出语句级执行计划,EXPLAIN 对 CALL proc_name() 也没用。得换思路:不盯“过程”,盯“过程干的事”。
最容易忽略的是 slow log 默认不记录存储过程内部的语句——它只记顶层 CALL,而真正慢的可能是里面一条 UPDATE。
- 启动 MySQL 时加参数
--log-slow-verbosity=full,并确认long_query_time=0(临时全记录),才能捕获过程内每条语句 -
performance_schema.events_statements_history_long表里,NESTING_EVENT_TYPE = 'STATEMENT'且NESTING_EVENT_ID指向上层CALL,可还原调用栈 - 注意
performance_schema默认关闭部分消费者(如events_statements_history_long),需提前UPDATE setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_statements_history_long'
真正卡住人的,往往不是“怎么查执行计划”,而是没意识到:存储过程的性能问题,一半在计划生成逻辑(参数嗅探、重编译),一半在监控链路断点(比如 slow log 没开 verbosity,XEvent 没设 duration 过滤)。这些地方一漏,后面所有分析都是在猜。


















