查看数据库对象的引用关系,查看数据库对象的依赖关系
分类:
IT文章
•
2022-03-25 12:48:20

转自:https://www.cnblogs.com/seusoftware/p/4858115.html
在SQL Server中,(可编程)对象间的引用即依赖关系,有多种方式可以检查,随着版本变更,方式也有所不同。
父子关系的对象,不通过依赖关系来查询,比如:
1. 外键关系
use tempdb
GO
--drop table tb1,tb2
create table tb1
(
col1 int Primary key,
col2 int
)
insert into tb1 values (2,2),(3,2),(4,2),(5,2)
GO
create table tb2
(
col3 int primary key,
col4 int constraint FK_tb2 foreign key references tb1(col1)
)
GO
--检查外键
select object_name(constraint_object_id) constraint_name,
object_name(parent_object_id) parent_object_name,
col_name(parent_object_id,parent_column_id) parent_object_column_name,
object_name(referenced_object_id) referenced_object_name,
col_name(referenced_object_id,referenced_column_id) referenced_object_column_name
from sys.foreign_key_columns
where referenced_object_id = object_id('tb1')
2. 表上的索引,触发器
use tempdb
GO
if OBJECT_ID('T','U') is not null
drop table T
create table T(id int)
GO
if exists(select 1 from sys.indexes where name = 'IX_001' and object_id = object_id('T','U'))
drop index T.IX_001
create index IX_001 on T(id)
if OBJECT_ID ('test_dml_trigger', 'TR') is not null
drop trigger test_dml_trigger
GO
create trigger test_dml_trigger
ON T
AFTER INSERT, UPDATE
AS
RAISERROR ('Notify Customer Relations', 16, 10);
GO
--检查索引
select object_name(object_id) as table_name,*
from sys.indexes
where name = 'IX_001' and object_id = object_id('T','U')
--检查DML触发器
select name as table_name, object_name(a.parent_obj) as dml_trigger_name
from sysobjects a
where a.xtype = 'TR'
在SSMS中,数据库对象上右击/View Dependencies,可以查看到对象的依赖关系,那么用脚本怎么检查?
create database DB1;
create database DB2;
use DB1
GO
if OBJECT_ID('T1','U') is not null
drop table T1
GO
create table T1(id int);
GO
if OBJECT_ID('V1','V') is not null
drop view V1
GO
create view V1
as
select * from T1
GO
if OBJECT_ID('SP1','P') is not null
drop proc SP1
GO
create proc SP1
as
select * from V1
GO
use DB2
GO
if OBJECT_ID('SP2','P') is not null
drop proc SP2
GO
create proc SP2
as
select * from DB1..V1
GO
use DB1
GO
if OBJECT_ID('SP3','P') is not null
drop proc SP3
GO
create proc SP3
as
exec DB2..SP2
GO
use DB1
GO
if object_id('test_schema.T2','U') is not null
drop table test_schema.T2
GO
if exists(select 1 from sys.schemas where name = 'test_schema')
drop schema test_schema
GO
create schema test_schema
create table test_schema.T2(c1 int, c2 int)
GO
if OBJECT_ID('SP4','P') is not null
drop proc SP4
GO
create proc SP4
as
select * from test_schema.T2
GO
一. SQL Server 2000依赖关系查询
--从SQL Server 2000沿用下来的系统表,SQL Server 2016仍适用,后续版本将不再支持
USE DB1
SELECT o.name, o.xtype, p.name as referenced_name, p.xtype
FROM sysdepends d
INNER JOIN sysobjects o
ON d.id = o.id
INNER JOIN sysobjects p
ON d.depid = p.id
--从SQL Server 2000沿用下来的存储过程,SQL Server 2016仍适用,后续版本将不再支持
USE DB1
exec sp_depends 'V1'
--无文档记载的sp_MS存储过程,只能检查被自己引用的对象,SQL Server 2016仍适用
exec sp_MSdependencies 'V1'
注意:sysdepends, sp_depends, sp_MSdependencies 只能检查当前数据库对象的引用/被引用,对于跨数据库对象依赖关系,无法检查。
二. SQL Server 2005依赖关系查询
--从SQL Server 2005沿用下来的系统视图,SQL Server 2016仍适用,后续版本将不再支持
USE DB1
SELECT o.name, o.type_desc, p.name as referenced_name, p.type_desc
FROM sys.sql_dependencies d
INNER JOIN sys.objects o
ON d.object_id = o.object_id
INNER JOIN sys.objects p
ON d.referenced_major_id = p.object_id
注意:和sysdepends, sp_depends一样,sys.sql_dependencies只能检查当前数据库对象的引用/被引用,对于跨数据库对象依赖关系,无法检查。
三. SQL Server 2008后依赖关系查询
--从SQL Server 2008开始用的系统视图
USE DB1
SELECT o.name, o.type_desc, p.name as referenced_name, p.type_desc
FROM sys.sql_expression_dependencies d
INNER JOIN sys.objects o
ON d.referencing_id = o.object_id
INNER JOIN sys.objects p
ON d.referenced_id = p.object_id
USE DB1
--从SQL Server 2008开始用的系统函数,引用我的对象
SELECT * FROM sys.dm_sql_referencing_entities('dbo.V1','OBJECT')
--从SQL Server 2008开始用的系统函数,被我引用的对象
SELECT * FROM sys.dm_sql_referenced_entities('dbo.SP1','OBJECT')
USE DB2
--从SQL Server 2008开始用的系统函数,引用我的对象
SELECT * FROM sys.dm_sql_referencing_entities('dbo.SP2','OBJECT')
--从SQL Server 2008开始用的系统函数,被我引用的对象
SELECT * FROM sys.dm_sql_referenced_entities('dbo.SP2','OBJECT')
注意:
(1) sys.sql_expression_dependencies及这两个新增函数,都可以检查当前数据库中跨数据库,跨服务器引用的对象,但当前数据库对象被跨数据库,跨服务器引用,无法检查;
(2) 新增的2个系统函数,可以更方便的检查引用和被引用,但对象名要完整,必须包含schema name,否则无法返回正确结果;
(3) sys.dm_sql_referenced_entities 还可以查看被数据库/服务器DDL触发器引用的对象;
SELECT * FROM sys.dm_sql_referenced_entities ('ddl_database_trigger_name', 'DATABASE_DDL_TRIGGER');
(4) sys.dm_sql_referencing_entities 还可以查看引用了类型/分区函数等的对象。
四. 无法查明的依赖关系
1. 跨数据库/服务器对象
上面提到从SQL Server 2008开始,跨数据库,跨服务器引用的对象,已经可以查询;
但是写法上要稍微调整下,因为当前数据库中,并没有其他数据库对象的object_id,所以不能按照object_id来关联。改动后脚本如下:
USE DB1
SELECT schema_name(o.schema_id) as schema_name, o.name as object_name, o.type_desc,
d.referenced_server_name, d.referenced_database_name, isnull(d.referenced_schema_name,'dbo') as referenced_schema_name, d.referenced_entity_name
FROM sys.sql_expression_dependencies d
INNER JOIN sys.objects o
ON d.referencing_id = o.object_id
注意:跨数据库/跨服务器对象的引用,仅能检查3部分/4部分名称格式的对象引用,即如:server_name.db_name.schema_name.object_name格式,对于OPENROWSET, OPENQUERY, OPENDATASOURCE的引用并不记录。
2. 临时对象
对于存储过程中用到的临时表,只能检查到create table创建的非#开头临时表,并且用函数检查还会报错,因为表事先并不存在。
if OBJECT_ID('SP5','P') is not null
drop proc SP5
GO
create proc SP5
as
select * into #temp from sys.objects
select * into _temp from sys.objects
select getdate()
create table #t (id int)
insert into #t select 100
if OBJECT_ID('_t','U') is not null
drop proc _t
create table _t (id int)
insert into _t select 100
GO
USE DB1
--只能检查到create table创建的非#临时表
SELECT schema_name(o.schema_id) as schema_name, o.name as object_name, o.type_desc,
d.referenced_server_name, d.referenced_database_name, isnull(d.referenced_schema_name,'dbo') as referenced_schema_name, d.referenced_entity_name
FROM sys.sql_expression_dependencies d
INNER JOIN sys.objects o
ON d.referencing_id = o.object_id
--并且用函数检查还会报错,因为表事先并不存在
select * from sys.dm_sql_referenced_entities('dbo.SP5','OBJECT');
/*
Msg 2020, Level 16, State 1, Line 4
The dependencies reported for entity "dbo.SP5" might not include references to all 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 DB1
GO
if OBJECT_ID('T2','U') is not null
drop table T2
GO
create table T2(id int);
GO
if OBJECT_ID('SP6','P') is not null
drop proc SP6
GO
create proc SP6
as
exec('select * from T1')
declare @SQL nvarchar(max)
set @SQL = N'select * from T2'
exec sp_executesql @SQL
exec (@SQL)
GO