2013-02-25 3 views
4

У меня сложный запрос с несколькими таблицами, представлениями и функциями внутри него. Функции и представления разделены на большее количество представлений и функций, которые потенциально могут отделиться на большее количество видов и функций внутри них.Запрос для рекурсивного определения зависимостей объектов

Этот запрос имеет проблемы с производительностью, поэтому я хочу получить четкий и краткий список всех объектов, на которые ссылаются в моем запросе, поэтому у меня есть основа для моего расследования. Как получить этот список объектов?

ответ

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; 
3

В SQL Server 2008 есть две новые функции динамического управления, введенные для отслеживания зависимостей объекта: sys.dm_sql_referenced_entities и sys.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'); 

Другой вариант - использовать довольно полезный инструмент под названием SQL Dependency Tracker от Red Gate.

+1

Является ли это ваш веб-сайт? В настоящее время Sophos блокирует ссылки с помощью «Запрошенное местоположение содержит вредоносный контент, идентифицированный как Troj/JSRedir-RX и был заблокирован от загрузки». Tbh Я ожидал, что они все равно свяжутся с соответствующими записями BOL. –

+0

Это не работает рекурсивно и, следовательно, не отвечает на вопрос OP. – DaveBoltman

4

ОПИСАНИЕ

писал эту хранимую процедуру, ниже которой Рекурсивно перечисляет все зависимые дочерние объекты и ребенок зависимых объектов и ребенок ребенка ... и т.д.. Параметр ввода может быть сохранен в 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. Уровень - Как глубоко, вложенная рекурсивный уровень которого объект используется

КОД

--========================================================================= 
--========================================================================= 
--== 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 
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 ; 
+0

Плюс один - простой и элегантный и просто работает. Это загадка, почему вы уже никого не заметили. – DaveBoltman

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. Заменить < вашей схемы > и < вашего объекта > с тем, что вам требуется.
  2. Когда объект , на который ссылается объект, не имеет префикса схемы в ссылочном объекте, схема фактически неизвестна, поэтому предикат выше OR sed.referenced_schema_name IS NULL. Это может привести к неправильному ссылочному объекту, если вы не используете лучшие методы в своих объектах базы данных.
  3. Моя цель заключается в том, чтобы написать сценарий, чтобы автоматически обновлять ссылки на объекты в базе данных после редактирования вида, используя sp_refreshsqlmodule. Для этого просто заверните CTE, показанный выше, следующим образом. Это выводит необходимый SQL для обновления ссылающихся объектов в правильном порядке:
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 
Смежные вопросы