查询以递归方式识别对象依赖项

时间:2013-02-25 17:10:24

标签: sql-server dependencies common-table-expression

我有一个复杂的查询,其中包含多个表,视图和函数。函数和视图分成更多的视图和函数,可能会拆分成更多的视图和函数。

此查询存在性能问题,因此我希望获得一个清晰简明的列表,列出我的查询中引用的所有对象,以便为调查提供依据。如何获取此对象列表?

6 个答案:

答案 0 :(得分:6)

<强>描述

写下此存储过程, RECURSIVELY 列出所有依赖子对象和子对象依赖对象以及子对象等。输入参数可以是Stored Proc,User Function,View。 可以轻松更改以获取第5列的唯一列表,无论对象的调用级别以及对象的深度和深度。

<强>列

  1. UsedByObjectId - 使用从属对象的父对象
  2. UsedByObjectName - 父对象的名称
  3. UsedByObjectType - 父对象的类型(P,V,FN)
  4. DependentObjectId - 父级使用的子对象
  5. DependentObjectName - 子对象的名称
  6. DependentObjectType - 从属子对象的类型(P,V,FN,U)
  7. 级别 - 对象的嵌套递归级别有多深
  8. 代码

    --=========================================================================
    --=========================================================================
    --== utlGetAllDependentObjectsRecursive - Uses recursive common table
    --==     expression to recursively get all the dependent objects as well
    --==     as the child objects and child's child objects of a 
    --==     Stored Procedure or View or Function.  can be easily modified to 
    --==     include all other types of Objects
    --=========================================================================
    --=========================================================================
    CREATE PROCEDURE utlGetAllDependentObjectsRecursive
    (
       -- Supports Stored Proc, View, User Function, User Table
       @PARAM_OBJECT_NAME VARCHAR(500)
    )
    AS
    BEGIN
        WITH CTE_DependentObjects AS
        (
            SELECT DISTINCT 
            b.object_id AS UsedByObjectId, 
            b.name AS UsedByObjectName, b.type AS UsedByObjectType, 
            c.object_id AS DependentObjectId, 
            c.name AS DependentObjectName , c.type AS DependenObjectType
            FROM  sys.sysdepends a
            INNER JOIN sys.objects b ON a.id = b.object_id
            INNER JOIN sys.objects c ON a.depid = c.object_id
            WHERE b.type IN ('P','V', 'FN') AND c.type IN ('U', 'P', 'V', 'FN') 
        ),
        CTE_DependentObjects2 AS
        (
           SELECT 
              UsedByObjectId, UsedByObjectName, UsedByObjectType,
              DependentObjectId, DependentObjectName, DependenObjectType, 
              1 AS Level
           FROM CTE_DependentObjects a
           WHERE a.UsedByObjectName = @PARAM_OBJECT_NAME
           UNION ALL 
           SELECT 
              a.UsedByObjectId, a.UsedByObjectName, a.UsedByObjectType,
              a.DependentObjectId, a.DependentObjectName, a.DependenObjectType, 
              (b.Level + 1) AS Level
           FROM CTE_DependentObjects a
           INNER JOIN  CTE_DependentObjects2 b 
              ON a.UsedByObjectName = b.DependentObjectName
        )
        SELECT DISTINCT * FROM CTE_DependentObjects2 
        ORDER BY Level, DependentObjectName    
    END 
    

答案 1 :(得分:5)

我看到这个post来识别引用特定同义词的所有对象,并在递归CTE中使用答案中的基本逻辑来识别与逗号分隔的对象列表相关的所有对象。正在执行的顶级查询。

Declare @baseObjects Nvarchar(1000) = '[Schema].[Table],[Schema].[View],[Schema].[Function],[Schema].[StoredProc]',
        @SQL Nvarchar(Max);

Declare @objects Table (SchemaName Varchar(512), TableName Varchar(512), ID Int, xtype Varchar(10));

Set     @SQL = 'Select  ss.name As SchemaName,
                        so.name As TableName,
                        so.id,
                        so.xtype
                From    sysobjects so
                Join    sys.schemas ss
                        On  so.uid = ss.schema_id
                Where   so.id In (Object_ID(''' + Replace(@baseObjects,',','''),Object_ID(''') + '''))';

Insert  @objects
Exec    sp_executeSQL @SQL;

With    test As
(
        Select  ss.name As SchemaName,
                so.name As TableName,
                so.id,
                so.xtype
        From    sys.sql_expression_dependencies sed
        Join    @objects vo
                On  sed.referencing_id = vo.ID
        Join    sysobjects so
                On  sed.referenced_id = so.id
        Join    sys.schemas ss
                On  so.uid = ss.schema_id
        Union   All
        Select  ss.name As SchemaName,
                so.name As TableName,
                so.id,
                so.xtype
        From    test
        Join    sys.sql_expression_dependencies sed
                On  sed.referencing_id = test.id
                And sed.referencing_id <> sed.referenced_id
        Join    sysobjects so
                On  sed. referenced_id = so.id
        Join    sys.schemas ss
                On  so.uid = ss.schema_id
)
Select  Distinct *
From    test
Union
Select  *
From    @objects;

答案 2 :(得分:3)

在SQL Server 2008中,引入了两个新的动态管理功能来跟踪对象依赖性:sys.dm_sql_referenced_entitiessys.dm_sql_referencing_entities

1 /返回引用给定实体的实体:

SELECT
        referencing_schema_name, referencing_entity_name, 
        referencing_class_desc, is_caller_dependent
FROM sys.dm_sql_referencing_entities ('<TableName>', 'OBJECT')

2 /返回对象引用的实体:

SELECT
        referenced_schema_name, referenced_entity_name, referenced_minor_name, 
        referenced_class_desc, is_caller_dependent, is_ambiguous
FROM sys.dm_sql_referenced_entities ('<StoredProcedureName>', 'OBJECT');

另一种选择是使用Red Gate中名为SQL Dependency Tracker的非常有用的工具。

答案 3 :(得分:2)

选中此项,您将获得所有递归对象。

    WITH Refobjects 
(referencing_object_name,referencing_object_type_desc) 
    AS 
    (
        SELECT
        o.name AS referencing_object_name,
        o.type_desc AS referencing_object_type_desc
        FROM
        sys.sql_expression_dependencies sed
        INNER JOIN
        sys.objects o ON sed.referencing_id = o.[object_id]
        WHERE
        sed.referenced_entity_name = 'Your Object Name'
      UNION ALL 

        SELECT
            o.name AS referencing_object_name,
            o.type_desc AS referencing_object_type_desc
        FROM
            sys.sql_expression_dependencies sed
            INNER JOIN
            sys.objects o ON sed.referencing_id = o.[object_id]
            INNER JOIN Refobjects ON sed.referenced_entity_name = Refobjects.referencing_object_name 
    )
    SELECT distinct * FROM Refobjects
    Order by 2 desc,1 ;

答案 4 :(得分:0)

基于@Raju Chavan的上述答案,效果很好。然而...

我已经添加了对架构的支持,以及返回(和排序)递归级别,因此可以轻松将其转换为脚本使用sp_refreshsqlmodule以正确的顺序刷新引用对象(参见下面的第3点)。

WITH 
  cRefobjects AS (

      SELECT o.name, s.name AS sch, o.type_desc, 1 AS level
      FROM sys.sql_expression_dependencies sed
        INNER JOIN sys.objects o ON o.object_id = sed.referencing_id
        INNER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
      WHERE (sed.referenced_schema_name = '<your schema>' OR sed.referenced_schema_name IS NULL)
      AND  sed.referenced_entity_name = '<your object name>'

    UNION ALL 

      SELECT o.name, s.name AS sch, o.type_desc, cRefobjects.level + 1 AS level
      FROM
        sys.sql_expression_dependencies AS sed
        INNER JOIN sys.objects o ON o.object_id = sed.referencing_id
        INNER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
        INNER JOIN cRefobjects ON sed.referenced_entity_name = cRefobjects.name
                               AND sed.referenced_schema_name = cRefobjects.sch
  )

SELECT DISTINCT name, sch, type_desc, level 
FROM cRefobjects
ORDER BY level, type_desc DESC, name;

需要考虑的一些事项:

  1. 替换&lt;您的架构&gt;和&lt;你的对象&gt;满足你的需求。
  2. 引用的对象在引用对象中没有架构前缀时,架构实际上是未知的,因此谓词高于OR sed.referenced_schema_name IS NULL。如果您没有遵循数据库对象中的最佳实践,则可能会出现错误的引用对象。
  3. 我寻求和找到这个答案的目的是编写一个脚本,在编辑视图后使用sp_refreshsqlmodule自动刷新数据库中的引用对象。为此,只需如下所示包裹上面显示的CTE。这将打印所需的SQL,以便以正确的顺序刷新引用对象:
  4. DECLARE @SQL NVARCHAR(4000); SET @SQL = '';
    WITH 
      cRefobjects AS (
        ...
      )
    --SELECT DISTINCT name, sch, type_desc, level 
    SELECT @SQL = @SQL + 'EXEC sys.sp_refreshsqlmodule ''' + sch + '.' + name + '''' + CHAR(13)+CHAR(10)
    FROM cRefobjects
    ORDER BY level, type_desc DESC, name;
    
    PRINT @SQL
    

答案 5 :(得分:0)

由于没有人为我工作,因此我改善了以上答案。 我需要一种通过sp_refreshsqlmodule类型刷新复杂的嵌套对象的方法。 您需要更新并更改为您自己的

以下方法对我有用:

func getProcessList() -> [kinfo_proc]? {
    var name : [Int32] = [ CTL_KERN, KERN_PROC, KERN_PROC_ALL ]
    var length = size_t()
    sysctl(&name, UInt32(name.count), nil, &length, nil, 0)
    let count = length / MemoryLayout<kinfo_proc>.size
    var procList = Array(repeating: kinfo_proc(), count: count)
    let result = sysctl(&name, UInt32(name.count), &procList, &length, nil, 0)
    guard result == 0 else { return nil } // Some error ...
    return Array(procList.prefix(length / MemoryLayout<kinfo_proc>.size))
}

选择名称,以MAX(level)作为级别,'EXEC sys.sp_refreshsqlmodule @name ='''+ sch +'。' +名称+'''',输入 来自cRefobjects GROUP BY名称,sch,类型 ORDER BY级别,类型,名称;