排除 SQL 依赖关系的故障

本主题介绍常见对象依赖关系问题及其解决方案。

动态管理函数 sys.dm_sql_referenced_entities 不返回列级依赖关系

sys.dm_sql_referenced_entities 系统函数将报告绑定到架构的引用的任何列级依赖关系。例如,此函数将报告索引视图的所有列级依赖关系,因为索引视图需要架构绑定。但是,如果被引用实体不绑定到架构,则仅当引用列的所有语句可以绑定时,才会报告列依赖关系。只有在分析语句时所有对象都存在,才可以成功绑定语句。如果在实体中定义的任何语句无法绑定,将不报告列依赖关系,并且 referenced_minor_id 列将返回 0。无法解析列依赖关系时,将引发错误 2020。此错误不会阻止查询返回对象级别的依赖关系。

解决方案

更正消息中标识的错误 2020 之前的任何错误。例如,在以下代码示例中,视图 Production.ApprovedDocuments 在 Production.Document 表的列Title、ChangeNumber 和 Status 中定义。将向 sys.dm_sql_referenced_entities 系统函数查询 ApprovedDocuments 视图所依赖的对象和列。因为视图不是使用 WITH SCHEMA_BINDING 子句创建的,所以可以在被引用表中修改视图中引用的列。该示例通过将 Production.Document 表中的列 ChangeNumber 重命名为 TrackingNumber 对其进行更改。将再次向目录视图查询 ApprovedDocuments 视图;但是它不能绑定到该视图中定义的所有列。将返回错误 207 和 2020 来标识问题。若要解决问题,必须改变视图,以反映列的新名称。

USE AdventureWorks2008R2;
GO
CREATE VIEW Production.ApprovedDocuments
AS
    SELECT Title, ChangeNumber, Status
    FROM Production.Document
    WHERE Status = 2;
GO
SELECT referenced_schema_name AS schema_name
    ,referenced_entity_name AS table_name
    ,referenced_minor_name AS referenced_column
FROM sys.dm_sql_referenced_entities ('Production.ApprovedDocuments', 'OBJECT');
GO
EXEC sp_rename 'Production.Document.ChangeNumber', 'TrackingNumber', 'COLUMN';
GO
SELECT referenced_schema_name AS schema_name
    ,referenced_entity_name AS table_name
    ,referenced_minor_name AS referenced_column
FROM sys.dm_sql_referenced_entities ('Production.ApprovedDocuments', 'OBJECT');
GO

该查询返回以下错误消息。

Msg 207, Level 16, State 1, Procedure ApprovedDocuments, Line 3

Invalid column name 'ChangeNumber'.

Msg 2020, Level 16, State 1, Line 1

The dependencies reported for entity "Production.ApprovedDocuments" do not include references to columns. This is either because the entity references an object that does not exist or because of an error in one or more statements in the entity. Before rerunning the query, ensure that there are no errors in the entity and that all objects referenced by the entity exist.

以下示例更正了视图中的列名。

USE AdventureWorks2008R2;
GO
ALTER VIEW Production.ApprovedDocuments
AS
    SELECT Title,TrackingNumber, Status
    FROM Production.Document
    WHERE Status = 2;
GO

对于包含临时表的联接的存储过程中的语句,将不返回列级依赖关系。对于包含多个语句的存储过程,针对不含临时表的联接的语句将返回列级依赖关系。联接到临时表的语句将不具有列级依赖关系报告功能。

列 is_ambiguous 报告与用户定义函数不一致的值

列 is_ambiguous 中为用户定义函数报告的值可能不一致。目录视图 sys.sql_expression_dependencies 中的 is_ambiguous 列以及动态函数 sys.dm_sql_referenced_entities 指示对实体的引用不明确。也就是,实体可以在运行时解析为用户定义函数、用户定义类型 (UDT) 或对类型 xml 的列的 XQuery 引用。根据您引用用户定义函数的方式,实体类型可能是明确的,也可能是不明确的,这会导致 is_ambiguous 列在一种情况下设置为 1 (true),在另一种情况下设置为 0 (false)。例如,请考虑以下存储过程。

CREATE PROCEDURE dbo.p1 
AS
    SELECT Sales.GetOrder() FROM t1;
    SELECT Sales.GetOrder();

在第一个 SELECT 语句中,不清楚 Sales.GetOrder() 是 Sales 架构中的用户定义函数,还是具有 GetOrder() 方法且类型为 UDT 的 Sales 列。在这种情况下,被引用实体 Sales.GetOrder() 的 is_ambiguous 列将设置为 1。在第二个 SELECT 语句中,对 Sales.GetOrder() 的引用是清楚的;根据语法,它只能是对用户定义函数的引用。在这种情况下,is_ambiguous 列设置为 0。此行为会使得列 is_ambiguous 中报告的值可能不一致。了解如何确定 is_ambiguous 列的值可以明确报告的值。

在下列情况下,is_ambiguous 列设置为 0 (false):

  • 很明显,引用指向用户定义函数。也就是,查询绑定到用户定义函数,并且具有该名称的列 UDT 方法或类型为 xml 的列不存在。

  • 很明显,引用指向列 UDT 方法。也就是,具有该 UDT 方法的列存在,并且具有该名称的用户定义函数或类型为 xml 的列不存在。

在下列情况下,is_ambiguous 列设置为 1 (true):

  • 具有被引用名称的用户定义函数、列 UDT 方法或类型为 xml 的列不存在。

  • 被引用名称存在于多个实体。例如,用户定义函数和列 UDT 方法具有相同名称。

对于本质上不明确的实体,referenced_database_name 列和 referenced_schema_name 列可能无效。例如,请考虑以下用户定义函数:

CREATE FUNCTION GetNextEmpHierarchyId (@empname varchar(25))
RETURNS hierarchyid
AS
BEGIN
    RETURN 
(
    SELECT h.empid.GetDescendant((SELECT MAX(h1.empid)  
                                  FROM dbo.Employees AS h1  
                                  WHERE h1.empid.GetAncestor(1) = h.empid), NULL)
    FROM dbo.Employees AS h  
    WHERE h.empname = @empname  
)  
END;

由于 hierarchyid UDT 方法调用,列 referenced_database_name 和 referenced_schema_name 对于该函数无效。不清楚对 h.empid.GetDescendant 和 h1.empid.GetAncestor 的引用是对使用由三部分构成的名称的实体 (database.schema.object) 的引用,还是对 UDT 方法 (table.column.method) 的引用。

解决方案

不需要任何用户操作。

不报告跨数据库依赖关系的列 referenced_id

不会在 sys.sql_expression_dependencies 目录视图中对跨数据库引用解析 referenced_id 列。仅当显式指定数据库名称和架构名称时,才会记录相应的名称。例如,当指定为 MyDB.MySchema.MyTable 时,会记录数据库和架构的名称;但是,当指定为 MyDB..MyTable 时,将只记录数据库的名称。

仅当被引用实体可以成功绑定时,才会在 sys.dm_sql_referenced_entities 系统函数中为跨数据库引用报告 referenced_id。绑定可能由于几个原因(包括下列原因)而失败:

  • 数据库处于脱机状态。

  • 被引用实体不存在于数据库中。

解决方案

验证数据库是否处于联机状态,并且被引用实体是否存在于数据库中。

数据库内被引用实体的列 referenced_id 为 Null

sys.dm_sql_referenced_entities 系统函数和 sys.sql_expression_dependencies 系统视图将报告任何绑定到架构的被引用实体的 ID。但是,当被引用实体的 ID 不能确定时,数据库内非绑定到架构的引用的 referenced_id 列为 NULL。在以下情况下可能会出现这种情形:

  • 被引用实体不存在于数据库中。

  • 名称解析依赖调用方。在这种情况下,is_caller_dependent 列设置为 1。

解决方案

验证被引用实体是否存在于数据库中。如果未找到,则创建实体;如果实体存在,则确保符合以下要求:

  • 被引用实体的名称拼写正确。

  • 指定的名称符合数据库的排序规则要求。如果数据库使用区分大小写的排序规则,则指定名称的大小写必须与对象名称的大小写完全匹配。例如,如果指定为 saleshistory,将不会在使用区分大小写排序规则的数据库中找到名为 SalesHistory 的对象的 ID。

  • 已指定对象的架构名称。如果对象不在调用方的默认架构、sys 架构或 dbo 架构中,则需要使用由两部分构成的名称 (schema_name.object_name)。

修改引用实体的定义以符合上面的要求。

如果被引用实体依赖调用方,则通过为被引用实体指定由两部分构成的名称,修改引用实体的定义。有关依赖调用方的引用的详细信息,请参阅报告 SQL 依赖关系

master 数据库中对象的依赖关系信息不报告

可以对在 master 数据库中创建的用户定义实体创建和维护 SQL 依赖关系。如果不报告实体的 SQL 依赖关系,则执行下列步骤:

  • 确保实体是有效类型的依赖关系跟踪

    并非跟踪所有用户对象的依赖关系信息。对于为其创建和维护依赖关系信息的实体类型的列表,请参阅了解 SQL 依赖关系

  • 确保实体未标记为系统对象。

    sys.objects 目录视图中查询实体的 is_ms_shipped 列。如果此列设置为 1,则实体为 SQL Server 附带的系统对象,或者为通过手动将此列设置为 1 从而修改为模拟系统对象的用户定义对象。 

解决方案

如果不支持对象的类型,依赖关系信息将不可用。

不跟踪系统对象的依赖关系。如果实体是用户定义的,且要让 SQL Server 在实体上创建和维护依赖关系,则 is_ms_shipped 列必须重置为 0。