報告 SQL 相依性
SQL 相依性是 SQL 運算式中使用的依名稱 (by-name) 參考,可以讓一種使用者定義實體相依於另一個實體。例如,檢視和預存程序必須相依於特定資料表,這些資料表中包含檢視或程序所傳回的資料。在下列案例中,報告相依性資訊相當有用:
移動模組,例如,將預存程序從一個應用程式移到另一個應用程式。
移動模組前,您可以判斷是否有模組所參考的任何資料庫或跨資料庫實體也必須隨著該模組移動。
修改實體的定義,例如,在資料表中加入或卸除資料行。
修改實體前,您可以判斷是否有其他實體與目前的實體定義相依。在修改後查詢或叫用時,這些相依實體可能會產生非預期的結果,而且可能需要重新整理中繼資料或修改其定義。
將一或多個資料庫從一個伺服器移到另一個伺服器。
將資料庫移到另一個伺服器前,您可以判斷一個資料庫中的實體是否與另一個資料庫中的實體相依。如此一來,您就可以知道是否要將這些資料庫移到相同的伺服器中。
為跨越多個資料庫的應用程式設定容錯移轉。
您想要確認應用程式隨時可以使用,而且使用資料庫鏡像做為容錯移轉策略。應用程式與一個以上的資料庫相依,而且您想要確認如果容錯移轉到鏡像伺服器,該應用程式可以成功執行它。由於鏡像是在資料庫層級執行,您必須判斷對於應用程式而言,哪些資料庫是重要的,這樣才可以針對所有資料庫個別設定鏡像。然後,您可以確認所有資料庫都會一起容錯移轉,因而確保應用程式可以在鏡像伺服器上執行。
使用四部分名稱,在執行分散式查詢的應用程式中尋找實體。
您想要知道在分散式查詢中使用哪些連結的伺服器。
尋找用於應用程式的實體,實體包含呼叫者相依參考或一部分名稱參考。
部署應用程式前,您可以決定應用程式所使用的實體包含呼叫者相依參考或僅使用一部分名稱之實體的參考。這種參考表示程式設計方法不佳,而且在部署應用程式時,可能會導致非預期的行為。這是因為受參考實體的解析 (繫結) 相依於呼叫者的結構描述,而且直到執行階段才會決定這個資訊。尋找這些參考後,可以指定適當的多部分名稱 (例如,schema_name.object_name) 來修正查詢。
如需有關 SQL 相依性的詳細資訊,請參閱<了解 SQL 相依性>。
使用系統檢視與函數報告相依性
若要檢視 SQL 相依性,SQL Server 2008 會提供 sys.sql_expression_dependencies 目錄檢視以及 sys.dm_sql_referenced_entities 和 sys.dm_sql_referencing_entities 動態管理函數。您可以查詢這些物件,以傳回使用者定義實體的相依性資訊。
也可以使用 SQL Server Management Studio 中的 [檢視相依性] 檢視 SQL 相依性。如需詳細資訊,請參閱<如何:檢視 SQL 相依性 (SQL Server Management Studio)>。
使用 sys.sql_expression_dependencies 目錄檢視
sys.sql_expression_dependencies 目錄檢視會提供資料庫擁有者或資料庫管理員報告給定資料庫之相依性資訊的能力。您可以使用這個檢視來回答類似下列的全域問題:
資料庫有哪些跨伺服器或跨資料庫相依性?
在資料庫中有哪種相依性?
資料庫中的哪些實體有呼叫者相依的參考?
在資料庫中,哪些伺服器層級或資料庫層級的 DDL 觸發程序有實體的相依性?
資料庫中的哪些模組使用使用者定義型別 (UDT)?
sys.sql_expression_dependencies 有下列限制:
只有在指定有效的四部分或三部分名稱時,才會傳回跨伺服器和跨資料庫實體的相依性。而不會傳回受參考實體的識別碼。
只有結構描述繫結的實體會報告資料行層級的相依性。
使用 sys.dm_sql_referenced_entities 動態管理函數
sys.dm_sql_referenced_entities 會針對在指定之參考實體的定義中依據名稱參考的每個使用者定義實體,傳回一個資料列。參考實體可以是使用者定義物件、伺服器層級 DDL 觸發程序,或資料庫層級 DDL 觸發程序。這是 sys.sql_expression_dependencies 傳回的相同資訊,但是,結果集限制為指定之參考實體所參考的實體。此函數對於想要追蹤所擁有之模組相依性或追蹤具有 VIEW DEFINITION 權限之相依性的開發人員而言,相當有用。
使用 sys.dm_sql_referencing_entities 動態管理函數
sys.dm_sql_referencing_entities 函數會針對目前資料庫中,依名稱參考另一個使用者定義實體的每個使用者定義實體,傳回一個資料列。參考實體可以是使用者定義物件、資料型別 (別名或 CLR UDT)、XML 結構描述集合,或資料分割函數。此函數對於想要追蹤所擁有之實體相依性的開發人員而言,相當有用。例如,修改使用者定義型別前,開發人員可以使用此函數來決定資料庫中相依於該型別的所有實體。請注意,除非在計算資料行、CHECK 條件約束或 DEFAULT 條件約束的定義中指定型別,否則不會報告資料表中的使用者定義型別參考。
範例
下列範例可以使用 sys.sql_expression_dependencies 目錄檢視以及 sys.dm_sql_referenced_entities 和 sys.dm_sql_referencing_entities 動態管理函數傳回 SQL 相依性。
報告指定之實體相依的實體
您可以查詢 sys.sql_expression_dependencies 目錄檢視或 sys.dm_sql_referenced_entities 動態管理函數傳回指定之實體相依的實體清單。例如,您可以傳回模組 (例如,預存程序或觸發程序) 所參考的實體清單。
下列範例會建立一個資料表、一個檢視,以及三個預存程序。在之後的查詢中會使用這些物件示範如何報告相依性資訊。請注意,MyView 和 MyProc3 都參考 Mytable。MyProc1 參考 MyView,而 MyProc2 參考 MyProc1。
USE AdventureWorks2008R2;
GO
-- Create entities
CREATE TABLE dbo.MyTable (c1 int, c2 varchar(32));
GO
CREATE VIEW dbo.MyView
AS SELECT c1, c2 FROM dbo.MyTable;
GO
CREATE PROC dbo.MyProc1
AS SELECT c1 FROM dbo.MyView;
GO
CREATE PROC dbo.MyProc2
AS EXEC dbo.MyProc1;
GO
CREATE PROC dbo.MyProc3
AS SELECT * FROM AdventureWorks2008R2.dbo.MyTable;
EXEC dbo.MyProc2;
GO
下列範例會查詢 sys.sql_expression_dependencies 目錄檢視以傳回 MyProc3 所參考的實體。
USE AdventureWorks2008R2;
GO
SELECT OBJECT_NAME(referencing_id) AS referencing_entity_name
,referenced_server_name AS server_name
,referenced_database_name AS database_name
,referenced_schema_name AS schema_name
, referenced_entity_name
FROM sys.sql_expression_dependencies
WHERE referencing_id = OBJECT_ID(N'dbo.MyProc3');
GO
以下為結果集:
referencing_entity server_name database_name schema_name referenced_entity
------------------ ----------- -------------------- ----------- -----------------
MyProc3 NULL NULL dbo MyProc2
MyProc3 NULL AdventureWorks2008R2 dbo MyTable
(2 個資料列受到影響)
在 MyProc3 的定義中,會傳回依名稱參考的兩個實體。由於沒有使用有效的四部分名稱指定受參考的實體,伺服器名稱為 NULL。但是 MyTable 的資料庫名稱會顯示出來,因為已在程序中使用有效的三部分名稱定義該實體。
類似的資訊可以使用 sys.dm_sql_referenced_entities 傳回。除了報告物件名稱之外,此函數還可以用來傳回結構描述繫結與非結構描述繫結之實體的資料行層級相依性。下列範例會傳回 MyProc3 相依的實體,包括資料行層級的相依性。
USE AdventureWorks2008R2;
GO
SELECT referenced_server_name AS server
, referenced_database_name AS database_name
, referenced_schema_name AS schema_name
, referenced_entity_name AS referenced_entity
, referenced_minor_name AS column_name
FROM sys.dm_sql_referenced_entities ('dbo.MyProc3', 'OBJECT');
GO
以下為結果集:
server_name database_name schema_name referenced_entity column_name
----------- -------------------- ----------- ----------------- -----------
NULL NULL dbo MyProc2 NULL
NULL AdventureWorks2008R2 dbo MyTable NULL
NULL AdventureWorks2008R2 dbo MyTable c1
NULL AdventureWorks2008R2 dbo MyTable c2
(4 個資料列受到影響)
在此結果集中,會傳回兩個相同的實體,但是,也會傳回其他兩個資料列,以便在 MyTable 中顯示 c1 和 c2 資料行的相依性。請注意,在 MyProc3 的定義中,會使用 SELECT * 陳述式參考 MyTable 中的資料行。這不是建議的編碼方式,但是,Database Engine 仍然會追蹤資料行層級的相依性。
到目前為止,這些範例已經示範如何傳回實體直接相依的這些實體。下列範例使用遞迴通用資料表運算式 (CTE) 傳回實體的所有直接和間接相依性。
DECLARE @referencing_entity AS sysname;
SET @referencing_entity = N'MyProc3';
WITH ObjectDepends(entity_name,referenced_schema, referenced_entity, referenced_id,level)
AS (
SELECT entity_name =
CASE referencing_class
WHEN 1 THEN OBJECT_NAME(referencing_id)
WHEN 12 THEN (SELECT t.name FROM sys.triggers AS t
WHERE t.object_id = sed.referencing_id)
WHEN 13 THEN (SELECT st.name FROM sys.server_triggers AS st
WHERE st.object_id = sed.referencing_id) COLLATE database_default
END
,referenced_schema_name
,referenced_entity_name
,referenced_id
,0 AS level
FROM sys.sql_expression_dependencies AS sed
WHERE OBJECT_NAME(referencing_id) = @referencing_entity
UNION ALL
SELECT entity_name =
CASE sed.referencing_class
WHEN 1 THEN OBJECT_NAME(sed.referencing_id)
WHEN 12 THEN (SELECT t.name FROM sys.triggers AS t
WHERE t.object_id = sed.referencing_id)
WHEN 13 THEN (SELECT st.name FROM sys.server_triggers AS st
WHERE st.object_id = sed.referencing_id) COLLATE database_default
END
,sed.referenced_schema_name
,sed.referenced_entity_name
,sed.referenced_id
,level + 1
FROM ObjectDepends AS o
JOIN sys.sql_expression_dependencies AS sed ON sed.referencing_id = o.referenced_id
)
SELECT entity_name,referenced_schema, referenced_entity, level
FROM ObjectDepends
ORDER BY level;
GO
以下為結果集:
entity_name referenced_schema referenced_entity level
----------- ----------------- ----------------- -----
MyProc3 dbo MyProc2 0
MyProc3 dbo MyTable 0
MyProc2 dbo MyProc1 1
MyProc1 dbo MyView 2
MyView dbo MyTable 3
(5 個資料列受到影響)
在此結果集中,MyProc2 和 MyTable 會當做直接相依性傳回,如層級 0 的值所示。第三個資料列會顯示在 MyProc2 定義中參考之 MyProc1 的間接相依性。第四個資料列則會顯示在 MyProc1 定義中參考之 MyView 的相依性,最後顯示在 MyView 定義中參考之 MyTable 的相依性。
藉由傳回階層式相依性資訊,您可以在給定的實體上,判斷直接和間接相依性的完整清單,並在需要將這些相依性移到另一個資料庫時,推斷部署這些物件的順序。
下列範例會使用 sys.dm_sql_referenced_entities 函數,傳回相同的階層式相依性資訊。會傳回 MyProc3 所相依的實體,包括資料行層級的相依性。
USE AdventureWorks2008R2;
GO
DECLARE @entity AS sysname , @type AS sysname;
SET @entity = N'dbo.MyProc3';
SET @type = N'OBJECT';
WITH ObjectDepends(referenced_schema_name, referenced_entity_name, referenced_column,
referenced_id,level)
AS (
SELECT
referenced_schema_name
,referenced_entity_name
,referenced_minor_name AS referenced_column
,referenced_id
,0 AS level
FROM sys.dm_sql_referenced_entities (@entity, @type)
UNION ALL
SELECT
re.referenced_schema_name
,re.referenced_entity_name
,re.referenced_minor_name AS referenced_column
,re.referenced_id
,level + 1
FROM ObjectDepends AS o
CROSS APPLY sys.dm_sql_referenced_entities (o.referenced_schema_name + N'.' + o.referenced_entity_name, @type) AS re
)
SELECT referenced_schema_name, referenced_entity_name, referenced_column, level
FROM ObjectDepends
ORDER BY level;
GO
報告相依於指定之實體的實體
您可以查詢 sys.sql_expression_dependencies 目錄檢視或 sys.dm_sql_referencing_entities 動態管理函數傳回指定之實體相依的實體清單。例如,如果指定的實體為資料表,會傳回定義中依名稱參考該資料表的所有實體。
下列範例會傳回參考實體 dbo.MyTable 的實體。
USE AdventureWorks2008R2;
GO
SELECT OBJECT_SCHEMA_NAME ( referencing_id ) AS referencing_schema_name,
OBJECT_NAME(referencing_id) AS referencing_entity_name,
COALESCE(COL_NAME(referencing_id, referencing_minor_id), '(n/a)') AS referencing_column,
referencing_class_desc, referenced_class_desc,
referenced_server_name, referenced_database_name, referenced_schema_name,
referenced_entity_name,
COALESCE(COL_NAME(referenced_id, referenced_minor_id), '(n/a)') AS referenced_column,
is_caller_dependent, is_ambiguous
FROM sys.sql_expression_dependencies AS sed
WHERE referenced_id = OBJECT_ID(N'dbo.MyTable');
GO
可以使用 sys.dm_sql_referenced_entities 動態管理函數傳回類似的資訊。
USE AdventureWorks2008R2;
GO
SELECT referencing_schema_name, referencing_entity_name, referencing_id, referencing_class_desc, is_caller_dependent
FROM sys.dm_sql_referencing_entities ('dbo.MyTable', 'OBJECT');
GO
報告資料行層級相依性
針對結構描述繫結和非結構描述繫結的實體,資料行層級相依性可以使用 sys.dm_sql_referenced_entities 報告。結構描述繫結實體的資料行層級相依性也可以使用 sys.sql_expression_dependencies 報告。
下列範例會查詢 sys.dm_sql_referenced_entities 報告非結構描述繫結實體的資料行層級相依性。此範例會先建立 Table1 和 Table 2 以及預存程序 Proc1。這個程序會參考 Table1 中的資料行 b 和 c 以及 Table2 中的資料行 c2。然後,會以指定成參考實體的預存程序執行檢視 sys.dm_sql_referenced_entities。結果集包含所參考之實體 Table1 和 Table2 的資料列以及在預存程序定義中參考的資料行。請注意,在參考這些資料表的資料列中,NULL 會傳入 column_name 資料行。
USE AdventureWorks2008R2;
GO
CREATE TABLE dbo.Table1 (a int, b int, c int);
GO
CREATE TABLE dbo.Table2 (c1 int, c2 int);
GO
CREATE PROCEDURE dbo.Proc1 AS
SELECT b, c FROM dbo.Table1;
SELECT c2 FROM dbo.Table2;
GO
SELECT referenced_id, referenced_entity_name AS table_name, referenced_minor_name AS column_name
FROM sys.dm_sql_referenced_entities ('dbo.Proc1', 'OBJECT');
GO
以下為結果集:
referenced_id, table_name, column_name
------------- ----------- -------------
151671588 Table1 NULL
151671588 Table1 b
151671588 Table1 c
2707154552 Table2 NULL
2707154552 Table2 c2
報告跨伺服器和跨資料庫相依性
當實體使用有效的三部分名稱參考另一個實體時,會建立跨資料庫相依性。當實體使用有效的四部分名稱參考另一個實體時,則會建立跨伺服器參考。只有在明確指定名稱時,才會記錄伺服器和資料庫的名稱。例如,指定為 MyServer.MyDB.MySchema.MyTable 時,會記錄伺服器和資料庫名稱,但是,指定為 MyServer..MySchema.MyTable 時,則只會記錄伺服器名稱。如需有關如何在追蹤跨伺服器和跨資料庫相依性的詳細資訊,請參閱<了解 SQL 相依性>。
跨資料庫和跨伺服器相依性可以使用 sys.sql_expression_dependencies 或 sys.dm_sql_referenced_entitites 報告。
下列範例會傳回所有跨資料庫相依性。該範例會先在資料庫 db2 和 db3 中,建立參考資料表的資料庫 db1 以及兩個預存程序。然後會查詢 sys.sql_expression_dependencies 資料表以報告程序和資料表之間的跨資料庫相依性。請注意,在受參考實體 t3 的 referenced_schema_name 資料行中會傳回 NULL,因為在程序定義中,沒有指定該實體的結構描述名稱。
CREATE DATABASE db1;
GO
USE db1;
GO
CREATE PROCEDURE p1 AS SELECT * FROM db2.s1.t1;
GO
CREATE PROCEDURE p2 AS
UPDATE db3..t3
SET c1 = c1 + 1;
GO
SELECT OBJECT_NAME (referencing_id),referenced_database_name,
referenced_schema_name, referenced_entity_name
FROM sys.sql_expression_dependencies
WHERE referenced_database_name IS NOT NULL;
GO
USE master;
GO
DROP DATABASE db1;
GO
報告呼叫者相依參考
呼叫者相依參考表示在執行階段發生之受參考實體的結構描述繫結,因此,實體識別碼的解析會相依於呼叫者的預設結構描述。這通常稱為「動態結構描述繫結」(Dynamic Schema Binding),而且會在參考的實體為預存程序、擴充預存程序,或是在不指定結構描述名稱的情形下,於 EXECUTE 陳述式中呼叫的非結構描述繫結使用者定義函數時發生。例如,EXECUTE MySchema.MyProc 格式之實體的參考不是呼叫者相依的參考,但是,EXECUTE MyProc 格式的參考則是呼叫者相依的參考。
執行所參考之模組時,呼叫者相依參考可能會造成非預期的行為。例如,假設在使用一部份名稱來參考程序的下列預存程序情況下。
CREATE PROCEDURE dbo.Proc1
AS EXECUTE dbo.Proc2;
GO
執行 Proc1 時,Proc2 會繫結到呼叫者的結構描述。假設執行 Proc1 的 User1 具有 S1 的預設結構描述,而 User2 具有 S2 的預設結構描述。當 User1 執行 Proc1 時,受參考實體會解析成 S1.Proc2。當 User2 執行 Proc1 時,受參考實體會解析成 S2.Proc2。由於這個行為的緣故,在執行 Proc1 前無法解析 Proc2 的識別碼,因此,在 sys.sql_expression_dependencies 檢視和 sys.dm_sql_referenced_entities 函數中,is_caller_dependent 資料行會設定為 1。執行 Proc1 時,Database Engine 將會在呼叫者的預設結構描述中,尋找受參考實體 Proc2。如果找不到,則會檢視 dbo 結構描述。如果在 dbo 結構描述中找不到 Proc2,則無法解析 Proc2 的識別碼,因此陳述式會失敗。建議在參考資料庫實體時指定兩段式名稱以排除應用程式的潛在錯誤。
下列範例會在包含呼叫者相依參考的目前資料庫中,傳回每個實體。
SELECT OBJECT_NAME(referencing_id) AS referencing_entity, referenced_database_name,
referenced_schema_name, referenced_entity_name, referenced_id
FROM sys.sql_expression_dependencies
WHERE is_caller_dependent = 1;
報告使用指定之 UDT 的實體
下列範例會在參考定義中指定之型別的目前資料庫中,傳回每個實體。結果集會顯示有兩個預存程序使用這個型別。此型別也用於 HumanResources.Employee 資料表中的數個資料行定義中,但是,由於該型別不在資料表的計算資料行定義、CHECK 條件約束或 DEFAULT 條件約束中,因此不會傳回資料表的任何資料列。
USE AdventureWorks2008R2;
GO
SELECT referencing_schema_name, referencing_entity_name, referencing_id, referencing_class_desc, is_caller_dependent
FROM sys.dm_sql_referencing_entities ('dbo.Flag', 'TYPE');
GO
報告伺服器層級 DDL 觸發程序相依性
只有在內容設定為 master 資料庫時,才可以使用 sys.sql_expression_dependencies 和 sys.dm_sql_referencing_entities 報告伺服器層級 DDL 觸發程序的相依性。使用 sys.dm_sql_referenced_entities 函數時,內容可以是任何資料庫。
下列範例會查詢 sys.sql_expression_dependencies檢視以報告伺服器層級 DDL 觸發程序相依性。
USE master;
GO
SELECT OBJECT_NAME(referencing_id) AS referencing_entity, referencing_class_desc, referenced_server_name, referenced_database_name, referenced_schema_name, referenced_entity_name, referenced_id
FROM sys.sql_expression_dependencies
WHERE referencing_class = 13;