sys.dm_exec_describe_first_result_set是SQL Server 2012+中更可靠的依赖分析工具,能识别动态SQL外的依赖,但无法解析EXEC(@sql)中的动态对象名;拆分存储过程须加事务、规范命名、慎用动态SQL、补授权、防参数嗅探与嵌套过深,并验证隐式契约。

查清依赖关系用 sys.dm_exec_describe_first_result_set
SQL Server 2012+ 里,sys.dm_exec_describe_first_result_set 是比 sp_depends 更靠谱的依赖分析工具——后者不识别动态 SQL、跨库引用和延迟名称解析。直接查它能暴露被调用对象是否真在运行时存在。
- 执行前先确认当前数据库上下文,否则返回空或错库结果
- 对含
EXEC(@sql)的存储过程,该 DMV 只能解析静态部分,动态拼接的表/列名不会出现在referenced_entity_name - 示例:查询
usp_GetOrderSummary依赖哪些表:SELECT referenced_entity_name, referenced_schema_name, referenced_database_name FROM sys.dm_exec_describe_first_result_set(N'EXEC usp_GetOrderSummary', NULL, 0) WHERE referenced_id IS NOT NULL;
拆分前必须加事务包装 + 回滚开关
存储过程不是函数,不能直接“提取方法”。拆成多个新过程后,原逻辑若涉及多步数据变更(比如先删临时表、再插新数据、最后更新状态),一旦中间出错,旧过程没事务控制就可能留下脏数据。
- 老过程里没
BEGIN TRAN?拆之前得补上,且所有子过程内部不再开新事务(避免嵌套事务陷阱) - 子过程命名要带业务语义,别叫
usp_Part1这种,推荐usp_CalculateOrderTax、usp_ValidateCustomerCredit - 参数传递别偷懒全塞
@xml或@json:SQL Server 解析 JSON 性能差,XML 更重;优先用表值参数(READONLY)或明确字段列表
动态 SQL 拆分后容易丢权限
原过程里用 EXEC(@sql) 执行的语句,权限是“调用者上下文”;拆成独立过程后,若新过程没显式授权,就会报 The EXECUTE permission was denied on the object。
- 检查原过程是否用
WITH EXECUTE AS:如果是,每个子过程也得加相同子句,否则执行身份丢失 - 用
EXECUTE AS OWNER比EXECUTE AS CALLER更稳,但要求过程所有者对目标表有足够权限 - 部署脚本里记得补授权:
GRANT EXECUTE ON usp_CalculateOrderTax TO [app_role];
性能退化常发生在参数嗅探 + 多层嵌套调用
拆分后看起来模块清晰了,但 SQL Server 对嵌套过程的执行计划缓存更保守——尤其当子过程被不同参数反复调用时,容易复用低效计划。
- 子过程中加
OPTION (RECOMPILE)不是万能解,只适合参数值差异极大、执行频率不高的场景;高频调用建议用OPTIMIZE FOR - 避免三层以上调用链:A → B → C → D。第四层开始,语句树深度增加,优化器可能放弃某些转换规则
- 用
sys.dm_exec_query_stats对比拆分前后total_logical_reads和execution_count,别只看平均耗时

















