应使用 sys.sql_expression_dependencies 查存储过程引用的表,因其记录显式静态依赖;但动态sql、临时表、未用三段式名的跨库引用均无法捕获。

查存储过程调用哪些表:用 sys.dm_exec_describe_first_result_set 不够,得看 sys.sql_expression_dependencies
SQL Server 里想快速知道一个存储过程读写了哪些表,sys.dm_exec_describe_first_result_set 只能猜返回结果结构,不反映实际引用。真正靠谱的是 sys.sql_expression_dependencies,它记录了对象间显式声明的依赖(比如 SELECT * FROM Orders 这种硬编码引用)。
但注意:动态 SQL(如 EXEC('SELECT * FROM ' + @tbl))不会出现在这个视图里;临时表、表变量也不会被记录;还有跨数据库引用,如果没用三段式名(db.schema.object),可能只存 object 名,分不清是哪个库的。
- 查指定存储过程依赖的所有对象:
SELECT referenced_entity_name, referenced_schema_name, referenced_database_name FROM sys.sql_expression_dependencies WHERE referencing_id = OBJECT_ID('dbo.usp_GetOrderSummary'); - 加
is_ambiguous = 0过滤掉解析失败的引用(比如名字冲突、权限不足导致无法解析) - 如果
referenced_database_name是NULL,说明引用在当前库;如果是空字符串,可能是用了双段名(schema.table)但没指定库,SQL Server 默认按当前库处理
查谁在调用这个存储过程:不能只靠 sysdepends,优先用 sys.dm_exec_describe_first_result_set 反向推
sysdepends 已过时,且在 SQL Server 2005+ 中不保证完整——特别是 ALTER 后未重编译的对象,依赖关系可能滞后。sys.sql_expression_dependencies 是单向的(从“调用方”指向“被调用方”),所以要反查“谁调用了我”,得把当前存储过程作为 referenced_id 去搜。
- 查所有调用
usp_GetOrderSummary的对象:SELECT OBJECT_NAME(referencing_id) AS caller_name, o.type_desc AS caller_type FROM sys.sql_expression_dependencies d JOIN sys.objects o ON d.referencing_id = o.object_id WHERE d.referenced_id = OBJECT_ID('dbo.usp_GetOrderSummary'); - 结果里
caller_type可能是SQL_STORED_PROCEDURE、VIEW、SQL_TRIGGER,甚至SQL_INLINE_TABLE_VALUED_FUNCTION - 如果查不到,先确认该调用是否用了动态 SQL 或拼接对象名;再检查执行权限——没有 VIEW DEFINITION 权限的对象,依赖不会被记录
跨数据库/跨服务器依赖查不出来?必须用三段式或四段式引用名
SQL Server 的依赖跟踪只对显式、静态、可解析的引用生效。如果你在存储过程中写的是 SELECT * FROM OtherDB.dbo.Customers,那 OtherDB 会出现在 referenced_database_name 字段;但如果写成 SELECT * FROM Customers,哪怕当前上下文是 OtherDB,依赖里 referenced_database_name 仍是 NULL。
- 跨服务器链接(Linked Server)引用,如
REMOTESVR.OtherDB.dbo.Customers,会被识别为四段式,referenced_server_name字段才有值(需查sys.sql_expression_dependencies全字段) - 别用
USE OtherDB切库后再写两段名——这种切换不影响依赖解析,依然算当前库下的引用 - 视图或函数中用
EXEC sp_executesql调远程表?那不属于静态依赖,查不到
修改表结构后存储过程失效?依赖视图不会自动更新,得手动验证
sys.sql_expression_dependencies 是创建/修改时快照下来的,不是实时监控。删了一个列,依赖视图里还留着旧记录;改了表名但没改存储过程里的引用,依赖关系也不会自动断开或报错——直到你真去执行,才抛 Invalid column name 或 Invalid object name。
- 上线前批量验证:用
sys.procedures关联sys.sql_expression_dependencies,找出所有引用某张表的存储过程,再用sys.dm_exec_describe_first_result_set检查它们是否还能成功解析(不执行,只做元数据预检) - 避免依赖断裂的实操习惯:所有表/列引用尽量用三段式;改表前先
SELECT * FROM sys.sql_expression_dependencies WHERE referenced_entity_name = 'xxx'锁定影响范围 - SQL Server 2016+ 支持
sys.dm_exec_describe_first_result_set_for_object,传入object_id可直接验某个存储过程的返回结构是否仍合法
依赖关系不是魔法,它是编译期快照 + 静态文本分析的结果。动态性、权限、命名习惯,任何一个环节松动,查询结果就不可信。动手前先确认你的引用是不是真的“静态可见”。










