如何找出哪个存储过程正在使用 SQL Server 中特定表的特定列?
Posted
技术标签:
【中文标题】如何找出哪个存储过程正在使用 SQL Server 中特定表的特定列?【英文标题】:How to find out which stored procedure is using the specific column of a specific table in SQL Server? 【发布时间】:2021-12-30 16:42:04 【问题描述】:假设我有两张桌子:
CREATE TABLE Customers
(
Id BIGINT IDENTITY(1,1) PRIMARY KEY,
FullName varchar(100) NOT NULL,
);
CREATE TABLE Employees
(
Id BIGINT IDENTITY(1,1) PRIMARY KEY,
FullName varchar(100) NOT NULL,
);
如果我在任何存储过程中使用了Customers
表的FullName
列,那么我想通过搜索ColumnName = 'FullName'
和TableName = 'Customers'
来获取所有这些存储过程名称。
我不需要使用Employees
表中的FullName
列的那些存储过程名称。
是否可以在 SQL Server 中为此编写脚本?
注意:在我的搜索条件中,我想使用列名和表名进行搜索。
【问题讨论】:
【参考方案1】:您不需要使用已弃用的sys.sql_dependencies
,可以使用较新的sys.dm_sql_referenced_entities
。
不幸的是,经过一些测试,发现
sys.sql_expression_dependencies
和sys.dm_sql_referencing_entities
没有返回有关列级依赖关系的信息。
SELECT OBJECT_SCHEMA_NAME(o.object_id),
OBJECT_NAME(o.object_id)
FROM sys.objects o
JOIN sys.schemas s ON s.schema_id = o.schema_id
CROSS APPLY sys.dm_sql_referenced_entities(QUOTENAME(s.name) + '.' + QUOTENAME(o.name), 'OBJECT') d
INNER JOIN sys.columns c
ON c.object_id = d.referenced_id
AND c.column_id = d.referenced_minor_id
AND c.object_id = OBJECT_ID('dbo.Customers')
AND c.name = 'FullName'
WHERE o.type IN ('FN','TF','IF','P','V','TR'); -- scalar, multi-line and inline funcs, procs, views, triggers
【讨论】:
+1 用于提供非弃用选项。这样做的一个缺点或优点是,如果在已经破坏遗留问题的数据库中运行,它将返回不相关的错误。 (例如,有了这个对象CREATE FUNCTION [dbo].[LegacyNonsense]() RETURNS nvarchar(35) AS BEGIN RETURN (SELECT Foo FROM Bar) END
我没有从中得到任何错误。它应该给出什么错误?除了缺少架构和表引用之外,还有什么遗留或损坏的?
它引用了不存在的表和列。对于已经启动并运行了几年的任何数据库(因此“遗留问题”),哪种 IME 很常见 - 所以运行查询仍然会产生结果,但也会产生错误消息 i.stack.imgur.com/ZJobp.png
@Charlieface 非常感谢您挽救了我的生命。实际上,当我们更改表的列名时,我需要这个查询。在使用您提供的此查询之前,我必须检查所有存储过程、函数、触发器和视图,以找到我们在哪里使用了该特定表的该列。现在它节省了我很多时间,让生活更轻松。【参考方案2】:
sys.sql_dependencies
已弃用,但您仍然可以使用它
SELECT OBJECT_SCHEMA_NAME(d.object_id),
OBJECT_NAME(d.object_id)
FROM sys.sql_dependencies d
INNER JOIN sys.columns c
ON c.object_id = d.referenced_major_id
AND c.column_id = d.referenced_minor_id
WHERE d.class = 0
AND d.referenced_major_id = object_id('dbo.Customers')
AND c.name = 'FullName'
与文本搜索相比,这有很多优势,因为当过程同时包含字符串 Customers
和 FullName
但作为 cmets 或其他会产生误报的上下文时,您不会遇到问题。它还处理过程包含*
而不是明确提及名称的情况。
如果您使用动态 SQL,您可能需要退回到更痛苦的文本搜索。
我可能最终会使用混合方法来涵盖所有角度,如下所示,这样我就可以消除实际查看 sys.sql_dependencies
中找到的明确依赖项文本的需要,而只需要手动查看“可能”
WITH Candidates AS
(
SELECT d.object_id, 0 AS Source
FROM sys.sql_dependencies d
INNER JOIN sys.columns c
ON c.object_id = d.referenced_major_id
AND c.column_id = d.referenced_minor_id
WHERE d.class = 0
AND d.referenced_major_id = object_id('dbo.Customers')
AND c.name = 'FullName'
UNION ALL
SELECT m.object_id, 1 AS Source
FROM sys.sql_modules m
WHERE m.definition LIKE '%Customers%' AND (m.definition LIKE '%FullName%' OR m.definition LIKE '%*%')
)
SELECT SchemaName = OBJECT_SCHEMA_NAME(object_id),
ModuleName = OBJECT_NAME(object_id),
Confidence = IIF(MIN(Source) = 0, 'High', 'Possible')
FROM Candidates
GROUP BY object_id
【讨论】:
为什么不sys.sql_expression_dependencies
?
@Charlieface - 没有相同的“每列”详细信息
@Charlieface i.stack.imgur.com/yfqca.png
看来你是对的。 sys.dm_sql_referencing_entities
也没有。但是sys.dm_sql_referenced_entities
确实返回列级信息
@Charlieface - 是的。 TBH 我忘了那个。虽然使用起来很痛苦,因为它需要从具有潜在引用对象的结果中获得CROSS APPLY
-ed,并且最终可能会引发错误【参考方案3】:
sys.dm_sql_referenced_entities
表将为您提供所需的信息。你可以在微软网站查看它的参考:SQL Server 2019 Reference
我喜欢通过文本搜索来完成这项工作。为此,您可以将所有存储过程脚本导出为平面文件,然后在文件中进行搜索。
您可以使用 Notepad++ 的“在文件中查找”功能来查找引用。您需要考虑到该列可能已使用不同的格式引用:."Date_Id"、.[Date_Id] 或 .Date_Id。
【讨论】:
【参考方案4】:由于 SQL 的动态方面(对象之间的链接在创建对象时并不总是已知,除非使用 SCHEMABINDING 指令)链接在“执行”对象时完成。因此,确保您会发现所有带有另一个对象或对象属性的引用的 objetc 的唯一方法是使用内部标准进行命名......
Personnaly I use this convention for my business development (actually I do that for clubmed...)... 但它是法语的!
总结一下:
-
所有表的名称都以 T_ 开头并以唯一的结尾
三元组(在表列表中是唯一的)。示例:T_CUSTOMER_CST
所有视图都有一个以 V_ 开头并以唯一名称结尾的名称
三元组(在视图列表中是唯一的)。示例:V_CUSTOMER_CST
所有表函数的名称都以 F_ 开头并以 a 结尾
唯一的三元组(在函数列表中是唯一的)。例子 :
F_CUSTOMER_CST
表的所有内部数据列的名称都以
表的三元组。表 T_CUSTOMER_CST 的示例
客户是 CST_NAME,ID 是 CST_ID。
所有外部数据列(外键)保持原名,并且
如果它存在多个引用,则由一些完成
区别元素。表 T_JOURNEY_JRN 的 id 的示例
来自表 T_TOWN_TWN 的起始城镇和目标城镇是
TWN_ID_STARTS 和 TWN_ID_ENDS
等等……
因此,要找出在例程(过程、触发器、函数、视图...)中更改列定义的任何影响,要运行的查询是:
SELECT *
FROM sys.sql_modules
WHERE definition LIKE '%TWN?_ID%' ESCAPE '?'
这将找到所有包含名为 TWN_ID 的列的对象。
【讨论】:
以上是关于如何找出哪个存储过程正在使用 SQL Server 中特定表的特定列?的主要内容,如果未能解决你的问题,请参考以下文章