SQLServer 查看对象间依赖关系
在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,0)">4,0)">5,0)">2) table tb2 ( col3 primary constraint FK_tb2 foreign key references tb1(col1) ) 检查外键 select object_name(constraint_object_id) constraint_name,object_name(parent_object_id) parent_object_name,255)">col_name(parent_object_id,parent_column_id) parent_object_column_name,255)">object_name(referenced_object_id) referenced_object_name,255)">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. 表上的索引,触发器 if OBJECT_ID(T',U') is not null drop table T table T(id int) GO if exists(select 1 from sys.indexes where name IX_001' and object_id ')) index T.IX_001 index IX_001 on T(id) OBJECT_ID (test_dml_triggerTRnull trigger test_dml_trigger ON T AFTER INSERT,UPDATE AS RAISERROR (Notify Customer Relations16,0)">10); 检查索引 object_name(object_id) as table_name,128)">* from sys.indexes ') 检查DML触发器 select name object_name(a.parent_obj) as dml_trigger_name from sysobjects a where a.xtype ' ? 在SSMS中,数据库对象上右击/View Dependencies,可以查看到对象的依赖关系,那么用脚本怎么检查? database DB1; database DB2; use DB1 T1table T1 table T1(id int); V1Vview V1 as * from T1 SP1Pproc SP1 as from V1 use DB2 SP2proc SP2 from DB1..V1 SP3proc SP3 exec DB2..SP2 test_schema.T2table test_schema.T2 from sys.schemas where name test_schema') schema test_schema table test_schema.T2(c1 int,c2 SP4proc SP4 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 JOIN sysobjects p ON d.depid = p.id 从SQL Server 2000沿用下来的存储过程,SQL Server 2016仍适用,后续版本将不再支持 exec sp_depends ' 无文档记载的sp_MS存储过程,只能检查被自己引用的对象,SQL Server 2016仍适用 exec sp_MSdependencies ' 注意:sysdepends,sp_depends,sp_MSdependencies 只能检查当前数据库对象的引用/被引用,对于跨数据库对象依赖关系,无法检查。 ? 二. SQL Server 2005依赖关系查询 从SQL Server 2005沿用下来的系统视图,SQL Server 2016仍适用,后续版本将不再支持 FROM sys.sql_dependencies d JOIN sys.objects o ON d.= o.object_id JOIN sys.objects p ON d.referenced_major_id = p.object_id注意:和sysdepends,sp_depends一样,sys.sql_dependencies只能检查当前数据库对象的引用/被引用,对于跨数据库对象依赖关系,无法检查。 三. SQL Server 2008后依赖关系查询 从SQL Server 2008开始用的系统视图 FROM sys.sql_expression_dependencies d ON d.referencing_id ON d.referenced_id object_id 从SQL Server 2008开始用的系统函数,引用我的对象 SELECT FROM sys.dm_sql_referencing_entities(dbo.V1OBJECT') 从SQL Server 2008开始用的系统函数,被我引用的对象 FROM sys.dm_sql_referenced_entities(dbo.SP1USE DB2 dbo.SP2')注意: (1) sys.sql_expression_dependencies及这两个新增函数,都可以检查当前数据库中跨数据库,跨服务器引用的对象,但当前数据库对象被跨数据库,跨服务器引用,无法检查; (2) 新增的2个系统函数,可以更方便的检查引用和被引用,但对象名要完整,必须包含schema name,否则无法返回正确结果; (3) sys.dm_sql_referenced_entities 还可以查看被数据库/服务器DDL触发器引用的对象; FROM sys.dm_sql_referenced_entities (ddl_database_trigger_nameDATABASE_DDL_TRIGGER'); (4) sys.dm_sql_referencing_entities 还可以查看引用了类型/分区函数等的对象。 四.?无法查明的依赖关系 1.?跨数据库/服务器对象 上面提到从SQL Server 2008开始,跨数据库,跨服务器引用的对象,已经可以查询; 但是写法上要稍微调整下,因为当前数据库中,并没有其他数据库对象的object_id,所以不能按照object_id来关联。改动后脚本如下: SELECT schema_name(o.schema_id) as schema_name,o.name as object_name,d.referenced_server_name,d.referenced_database_name,255)">isnull(d.referenced_schema_name,0)">dboas referenced_schema_name,d.referenced_entity_name 注意:跨数据库/跨服务器对象的引用,仅能检查3部分/4部分名称格式的对象引用,即如:server_name.db_name.schema_name.object_name格式,对于OPENROWSET,OPENQUERY,OPENDATASOURCE的引用并不记录。2.?临时对象 对于存储过程中用到的临时表,只能检查到create table创建的非#开头临时表,并且用函数检查还会报错,因为表事先并不存在。 SP5proc SP5 into #temp from sys.objects into _getdate() table #t (id into #t 100 _tproc _t table _t (id into _t 100 GO 3.?动态SQL里引用的对象 T2table T2 table T2(id SP6proc SP6 exec(select * from T1declare @SQL nvarchar(max) set @SQL = Nselect * from T2' exec sp_executesql @SQL exec (@SQL) 无论系统视图/函数,都查不到 dbo.SP6'); 动态SQL里引用的对象,无论系统视图/函数,都查不到;也许只能试试查可编程对象的文本定义: ANSI SQL标准里定义的INFORMATION_SCHEMA对象 from INFORMATION_SCHEMA.ROUTINES where ROUTINE_DEFINITION like %T2%SQL Server 2000沿用下来的可编程对象文本定义 from syscomments where text SQL Server 2005开始的可编程对象文本定义 from sys.sql_modules where definition 注意:这种方法,对于hard coding的对象名,非常好用,但是,(1) 有时动态SQL里的对象名称并不是hard coding,所以也不一定能找到;比如: EXEC(SELECT * FROM dbo.table+ _name') SELECT * FROM + @table)(2) 另外一些书写不严格的SQL,也无法定位到对象名,比如: FROM dbo . table_name 这语法竟然也能通过 FROM dbo.table_name_2 名字只是部分类似,table_name_2不是table_name? 4.?延迟名称解析 如果被引用的数据库对象,在后面创建,那么用2000或者2005的方式去检查,会出现延迟名称解析(deferred name resolution),用2008后的方式,已经没有这个问题。 T3table T3 table T3(id 引用的SP_1st后创建 SP_2ndproc SP_2nd exec SP_1st SP_1stproc SP_1st from T3 出现延迟名称解析(deferred name resolution): 存储过程SP_2nd的引用对象,无法获取到 刷新对象定义,可以解决 exec sp_refreshsqlmodule 如果是视图,也可以这样刷新 exec sp_refreshview view_name使用2008后的系统视图,没有这个问题,它同时保存了引用对象的名称,object_id可先置为NULL 注意:新的视图虽然解决了延迟名称解析的问题,但也带来了新问题,如果引用的对象一直未被创建,或者创建后被重名命/删除,这条依赖关系仍然存在。 |