Olá pessoal,
Bom dia!
Neste post vou mostrar a vocês como encontrar dependências entre objetos de vários níveis de hierarquia no SQL Server utilizando queries Transact-SQL, simulando um comportamento semelhante ao que nos é apresentado na interface do Management Studio.
Utilizando o SQL Server Management Studio
Essa é a forma mais fácil de realizar esse mapeamento, pois não exige nenhum conhecimento técnico, basta utilizar a interface do Management Studio. Um contra dessa implementação é que você não pode trabalhar com os dados retornados para criar algum levantamento ou mapeamento em massa por exemplo, ou definição de nível de hierarquia para a busca. Além disso, essa tela não mostra as dependências cross-databases, ou seja, dependências entre objetos de databases diferentes.
Para visualizar as dependências, basta abrir o Object Explorer, selecionar o objeto que deseja visualizar as dependências (no exemplo, escolhi a tabela Clientes), clicar com o botão direito e selecionar a opção “View Dependencies”
Uma vez que a tela é aberta, você pode escolher visualizar:
– Objetos que dependem do objeto em questão (Objects that depend on [Clientes])
– Outros objetos que o objeto em questão possui dependência (Objects on which [Clientes] depends)
Essa tela lista tanto dependências direta (nível 1), quando um objeto depende diretamente de outro quanto dependências indiretas (quando um objeto depende de outro objeto e esse outro objeto é que possui a dependência). Quando mais níveis aparecem entre o objeto inicial e o final, maior é a hierarquia deles.
Utilizando Transact-SQL
Nos exemplos abaixo, vou demonstrar como listar os objetos e suas dependências utilizando queries T-SQL, fazendo uso das DMV’s sys.dm_sql_referenced_entities e sys.dm_sql_referencing_entities e da view de catálogo sys.sql_expression_dependencies.
Utilizando a sp_depends
Com o uso dessa SP de sistema, pode-se rapidamente listar os dependências de um objeto (apenas 1º nível e não é cross-database)
1 |
EXEC sp_depends @objname = N'dbo.Clientes' |
Utilizando a sp_MSdependencies
Uma outra SP de sistema que pode ajudar nessa situação, é a sp_MSdependencies. Apesar de não ser cross-database, ela permite visualizar os objetos dependentes do objeto X (Flag 1315327) e os que o objeto X depende (Flag 1053183).
1 2 3 4 5 |
-- Lista os objetos que dependem da tabela dbo.Clientes EXEC sp_MSdependencies N'dbo.Clientes', null, 1315327 -- Lista os objetos que a tabela dbo.Clientes depente EXEC sp_MSdependencies N'dbo.Clientes', null, 1053183 |
Utilizando a view de catálogo syscomments
Utilizando essa view de catálogo, pode-se facilmente realizar uma busca textual (é busca de texto, não é por objeto) entre os objetos para tentar entrar uma string específica em objetos como views, functions, procedures, triggers, etc. Esse recurso não é cross-database e retorna apenas dependências de 1º nível.
1 2 3 4 5 6 7 |
SELECT DISTINCT B.name FROM syscomments A INNER JOIN sysobjects B ON A.id = B.id WHERE CHARINDEX('Clientes', text) > 0 |
Utilizando a view de catálogo INFORMATION_SCHEMA.ROUTINES
Com a query abaixo, podemos fazer uma busca textual em procedures e functions que possuem uma string no nome, como o nome do objeto que estamos buscando dependências. Essa solução não é cross-database e é uma busca textual.
1 2 3 4 5 6 7 8 9 10 |
SELECT ROUTINE_CATALOG, ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE, ROUTINE_DEFINITION FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_DEFINITION LIKE '%Clientes%' |
Dependências Cross Database
Com a query abaixo, é possível selecionar todas as dependências cross-database, onde os objetos do banco atual da conexão possuem dependências para outros databases.
1 2 3 4 5 6 7 8 9 10 |
SELECT OBJECT_NAME(referencing_id) AS referencing_object, referenced_database_name, referenced_schema_name, referenced_entity_name FROM sys.sql_expression_dependencies WHERE referenced_database_name IS NOT NULL AND is_ambiguous = 0 |
Dependências de schema-bound
Com a query abaixo, é possível identificar a mapear as dependências do tipo schema-bound, como views indexadas (criadas com o hint SCHEMABINDING), colunas calculadas e check constraints:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
SELECT OBJECT_NAME(d.referencing_id) AS referencing_name, o.type_desc referencing_object_type, d.referencing_minor_id AS referencing_column_id, cc2.name AS referencing_column_name, d.referenced_entity_name, d.referenced_minor_id AS referenced_column_id, cc.name AS referenced_column_name FROM sys.sql_expression_dependencies d JOIN sys.all_columns cc ON d.referenced_minor_id = cc.column_id AND d.referenced_id = cc.[object_id] JOIN sys.objects o ON d.referencing_id = o.[object_id] LEFT JOIN sys.all_columns cc2 ON d.referencing_minor_id = cc2.column_id AND d.referencing_id = cc2.[object_id] WHERE d.is_schema_bound_reference = 1 AND d.referencing_minor_id > 0 |
Mostrando dependências em vários níveis
Com a query abaixo é possível listar as dependências em vários níveis hierárquicos, da mesma forma que a interface do SQL Server Management Studio nos mostra
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
WITH Arvore_Dependencias ( referenced_id, referenced_name, referencing_id, referencing_name, NestLevel ) AS ( SELECT A.[object_id] AS referenced_id, A.name AS referenced_name, A.[object_id] AS referencing_id, A.name AS referencing_name, 0 AS NestLevel FROM sys.objects A WHERE A.name = 'Clientes' UNION ALL SELECT A.referenced_id, OBJECT_NAME(A.referenced_id), A.referencing_id, OBJECT_NAME(A.referencing_id), NestLevel + 1 FROM sys.sql_expression_dependencies A JOIN Arvore_Dependencias B ON A.referenced_id = B.referencing_id ) SELECT DISTINCT referenced_id, referenced_name, referencing_id, referencing_name, NestLevel FROM Arvore_Dependencias WHERE NestLevel > 0 ORDER BY NestLevel, referencing_id |
Encontrando dependências por tipo de dado
Como você deve saber, os tipos de dados TEXT, NTEXT e IMAGE serão descontinuados e não mais suportados em futuras versões do SQL Server. Se você planeja realizar o upgrade da sua aplicação e substituir esses tipos, a query abaixo pode ser um bom ponto de partida. A query abaixo vai mostrar todos os objetos que utilizam esses tipos de dados e suas dependências:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
WITH Arvore_Dependencias AS ( SELECT DISTINCT A.name, A.[object_id] AS referenced_id, A.name AS referenced_name, A.[object_id] AS referencing_id, A.name AS referencing_name, 0 AS NestLevel FROM sys.objects A JOIN sys.columns B ON A.[object_id] = B.[object_id] WHERE A.is_ms_shipped = 0 AND B.system_type_id IN ( 34, 99, 35 ) -- TEXT, NTEXT e IMAGE UNION ALL SELECT B.name, A.referenced_id, OBJECT_NAME(A.referenced_id), A.referencing_id, OBJECT_NAME(A.referencing_id), NestLevel + 1 FROM sys.sql_expression_dependencies A JOIN Arvore_Dependencias B ON A.referenced_id = B.referencing_id ) SELECT name AS parent_object_name, referenced_id, referenced_name, referencing_id, referencing_name, NestLevel FROM Arvore_Dependencias t1 WHERE NestLevel > 0 ORDER BY name, NestLevel |
Relatório completo de dependências
A query abaixo vai mostrar uma linha para cada objeto do database que possua dependências, com os objetos dependentes separados por vírgula.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
SELECT DB_NAME() AS dbname, o.type_desc AS referenced_object_type, d1.referenced_entity_name, d1.referenced_id, STUFF(( SELECT ', ' + OBJECT_NAME(d2.referencing_id) FROM sys.sql_expression_dependencies d2 WHERE d2.referenced_id = d1.referenced_id ORDER BY OBJECT_NAME(d2.referencing_id) FOR XML PATH('') ), 1, 1, '') AS dependent_objects_list FROM sys.sql_expression_dependencies d1 JOIN sys.objects o ON d1.referenced_id = o.[object_id] GROUP BY o.type_desc, d1.referenced_id, d1.referenced_entity_name ORDER BY o.type_desc, d1.referenced_entity_name |
Procedure de Dependências Diretas
Após demonstrar todas essas utilizações, vou compartilhar uma stored procedure que eu uso sempre que preciso listar as dependências cross-database rapidamente. Existe um pré-requisito para criar essa SP, que é a fncSplit, que deve ser criada antes.
Essa procedure lista todas as dependências diretas de um objeto, de modo cross-database:
Visualizar código-fonte
Procedure Cross-database e multi-nível
Com a procedure abaixo, que utiliza CTE e recursividade, é possível listar todos os objetos dependentes com vários níveis de hierarquia no banco de origem e as dependências diretas (1º nível) e cross-database.
Visualizar código-fonteComo identificar, apagar e recriar Foreign Keys (FK)
Caso você queira identificar ou recriar dependências a nível de chaves Foreign Key’s, leia o artigo Como identificar, apagar e recriar Foreign Keys (FK) de uma tabela no SQL Server
É isso aí, pessoal!
Até o próximo post!