目前正在努力尋找數據庫中表的依賴性順序。並且在數據庫中有一些表的循環依賴的問題。如何在sql服務器中查找循環依賴表
,因爲一些表循環依賴IM沒有得到整個訂單.....
有沒有辦法找到在SQL Server數據庫的任何依賴圓形表,除了數據庫圖表?
目前正在努力尋找數據庫中表的依賴性順序。並且在數據庫中有一些表的循環依賴的問題。如何在sql服務器中查找循環依賴表
,因爲一些表循環依賴IM沒有得到整個訂單.....
有沒有辦法找到在SQL Server數據庫的任何依賴圓形表,除了數據庫圖表?
您並不需要購買工具來查找這些參考文獻。
SELECT
OBJECT_SCHEMA_NAME(fk1.parent_object_id)
+ '.' + OBJECT_NAME(fk1.parent_object_id),
OBJECT_SCHEMA_NAME(fk2.parent_object_id)
+ '.' + OBJECT_NAME(fk2.parent_object_id)
FROM sys.foreign_keys AS fk1
INNER JOIN sys.foreign_keys AS fk2
ON fk1.parent_object_id = fk2.referenced_object_id
AND fk2.parent_object_id = fk1.referenced_object_id;
@Sooraj,你想要一個能夠找到涉及73個表的循環引用的查詢,因爲這也是可能的嗎? –
看起來它只能找到直接循環引用(A-> B和B-> A),而不是像(A-> B,B-> C和C->)這樣更隱蔽的鏈。 –
@Karl yep,我從來沒有聲稱它會找到三,四或73張表(後者聲稱是來自OP的評論中的場景,但該評論已被刪除)。 –
下載Sql Dependency Tracker的免費試用版,並給它一個旋轉。如果你的作品,買吧:-)
http://www.red-gate.com/products/sql-development/sql-dependency-tracker/
另一種選擇是ApexSQL:
http://knowledgebase.apexsql.com/2012/08/apexsql-search-dependency-viewer.html
兩個都是很好的工具。
我偶然發現了我現在在幾處發現的腳本。我認爲它原來從SQL Azure Team Blog在後來自2010約:
在關係數據庫中的世界循環引用其中涉及的表的外鍵創建循環模式結構。當嘗試同步執行外鍵的兩個關係數據庫時,循環引用會導致特殊類型的問題。由於此問題,包含循環引用的數據庫模式在同步和複製數據庫時可以使用的工具中受到限制。本文將解釋循環引用並演示用於確定數據庫是否具有循環引用的Transact-SQL腳本。
它也被複制here並記入韋恩貝里。也許他在Sql Azure團隊中?
@ Aaron_Bertrand的回答非常簡潔。爲了完整性,我認爲值得添加這個腳本,因爲它找到了更長的依賴關係鏈。該鏈接很難發現,我將在這裏重現代碼,而不僅僅是讓下一個人更容易的鏈接希望。
它不簡潔。
下面的Transact-SQL腳本使用遞歸遊標來檢測數據庫模式中是否有任何循環引用。在嘗試將其與SQL Azure同步之前,可以在SQL Server數據庫上運行它,也可以在SQL Azure數據庫上運行它。您可以在SQL Server Management Studio的查詢窗口中運行它;輸出將顯示在消息部分。
如果您有循環引用的輸出將是這樣的:
dbo.City - > dbo.Author - > dbo.City dbo.Division - > dbo.Author - > dbo.City - > DBO .County - > dbo.Region - > dbo.Image - > dbo.Division dbo.State - > dbo.Image - > dbo.Area - > dbo.Author - > dbo.City - > dbo.County - > dbo。地區 - >> dbo.State dbo.County - > dbo.Region - > dbo.Author - > dbo.City - > dbo。縣 dbo.Image - > dbo.Area - > dbo.Author - > dbo.City - > dbo.County - > dbo.Region - > dbo.Image dbo.Location - > dbo.Author - > dbo.City - > dbo.County - > dbo.Region - > dbo.Image - > dbo.Location dbo.LGroup - > dbo.LGroup dbo.Region - > dbo.Author - > dbo.City - > dbo.County - > dbo 。區域 dbo.Author - > dbo.City - > dbo.Author dbo.Area - > dbo.Author - > dbo.City - > dbo.County - > dbo.Region - > dbo.Image - > dbo.Area
每一行都是循環引用,並帶有創建圓的表的鏈接列表。用於檢測循環引用的Transact-SQL腳本如下所示...此代碼可用於SQL Azure和SQL Server。
SET NOCOUNT ON
-- WWB: Create a Temp Table Of All Relationship To Improve Overall Performance
CREATE TABLE #TableRelationships (FK_Schema nvarchar(max), FK_Table nvarchar(max),
PK_Schema nvarchar(max), PK_Table nvarchar(max))
-- WWB: Create a List Of All Tables To Check
CREATE TABLE #TableList ([Schema] nvarchar(max), [Table] nvarchar(max))
-- WWB: Fill the Table List
INSERT INTO #TableList ([Table], [Schema])
SELECT TABLE_NAME, TABLE_SCHEMA
FROM INFORMATION_SCHEMA.TABLES
WHERE Table_Type = 'BASE TABLE'
-- WWB: Fill the RelationShip Temp Table
INSERT INTO #TableRelationships(FK_Schema, FK_Table, PK_Schema, PK_Table)
SELECT
FK.TABLE_SCHEMA,
FK.TABLE_NAME,
PK.TABLE_SCHEMA,
PK.TABLE_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON
C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON
C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON
C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT i1.TABLE_NAME, i2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON
i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT ON PT.TABLE_NAME = PK.TABLE_NAME
CREATE TABLE #Stack([Schema] nvarchar(max), [Table] nvarchar(max))
GO
-- WWB: Drop SqlAzureRecursiveFind
IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
OBJECT_ID(N'[dbo].[SqlAzureRecursiveFind]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[SqlAzureRecursiveFind]
GO
-- WWB: Create a Stored Procedure that Recursively Calls Itself
CREATE PROC SqlAzureRecursiveFind
@BaseSchmea nvarchar(max),
@BaseTable nvarchar(max),
@Schmea nvarchar(max),
@Table nvarchar(max),
@Fail nvarchar(max) OUTPUT
AS
SET NOCOUNT ON
-- WWB: Keep Track Of the Schema and Tables We Have Checked
-- Prevents Looping
INSERT INTO #Stack([Schema],[Table]) VALUES (@Schmea, @Table)
DECLARE @RelatedSchema nvarchar(max)
DECLARE @RelatedTable nvarchar(max)
-- WWB: Select all tables that the input table is dependent on
DECLARE table_cursor CURSOR LOCAL FOR
SELECT PK_Schema, PK_Table
FROM #TableRelationships
WHERE FK_Schema = @Schmea AND FK_Table = @Table
OPEN table_cursor;
-- Perform the first fetch.
FETCH NEXT FROM table_cursor INTO @RelatedSchema, @RelatedTable;
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
-- WWB: If We have Recurred To Where We Start This
-- Is a Circular Reference
-- Begin failing out of the recursions
IF (@BaseSchmea = @RelatedSchema AND
@BaseTable = @RelatedTable)
BEGIN
SET @Fail = @RelatedSchema + '.' + @RelatedTable
RETURN
END
ELSE
BEGIN
DECLARE @Count int
-- WWB: Check to make sure that the dependencies are not in the stack
-- If they are we don't need to go down this branch
SELECT @Count = COUNT(1)
FROM #Stack
WHERE #Stack.[Schema] = @RelatedSchema AND
#Stack.[Table] = @RelatedTable
IF (@Count=0)
BEGIN
-- WWB: Recurse
EXECUTE SqlAzureRecursiveFind @BaseSchmea,
@BaseTable,
@RelatedSchema, @RelatedTable, @Fail OUTPUT
IF (LEN(@Fail) > 0)
BEGIN
-- WWB: If the Call Fails, Build the Output Up
SET @Fail = @RelatedSchema + '.' + @RelatedTable
+ ' -> ' + @Fail
RETURN
END
END
END
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM table_cursor INTO @RelatedSchema, @RelatedTable;
END
CLOSE table_cursor;
DEALLOCATE table_cursor;
GO
SET NOCOUNT ON
DECLARE @Schema nvarchar(max)
DECLARE @Table nvarchar(max)
DECLARE @Fail nvarchar(max)
-- WWB: Loop Through All the Tables In the Database Checking Each One
DECLARE list_cursor CURSOR FOR
SELECT [Schema], [Table]
FROM #TableList
OPEN list_cursor;
-- Perform the first fetch.
FETCH NEXT FROM list_cursor INTO @Schema, @Table;
-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
-- WWB: Clear the Stack (Don't you love Global Variables)
DELETE #Stack
-- WWB: Initialize the Input
SET @Fail = ''
-- WWB: Check the Table
EXECUTE SqlAzureRecursiveFind @Schema,
@Table, @Schema,
@Table, @Fail OUTPUT
IF (LEN(@Fail) > 0)
BEGIN
-- WWB: Failed, Output
SET @Fail = @Schema + '.' + @Table + ' -> ' + @Fail
PRINT @Fail
END
-- This is executed as long as the previous fetch succeeds.
FETCH NEXT FROM list_cursor INTO @Schema, @Table;
END
-- WWB: Clean Up
CLOSE list_cursor;
DEALLOCATE list_cursor;
DROP TABLE #TableRelationships
DROP TABLE #Stack
DROP TABLE #TableList
DROP PROC SqlAzureRecursiveFind
非常感謝,這是我爲這個特殊問題找到的最好的代碼。 – valentin
從SQL Azure團隊博客腳本在回答1 ,它只能說明自身的引用 - 父/子關係到同一個表。 所以我寫了我自己的腳本:
-- variables for the path output
declare @delimList nvarchar(max) = ' > ',
@delimDot nvarchar(max) = '.'
/* Part 1: read all fk-pk relation
does not perform well in SQL Server with a CTE, thus using a temp table */
create table #fk_pk(
PK_schema sysname not null,
PK_table sysname not null,
FK_schema sysname not null,
FK_table sysname not null
)
insert into #fk_pk(
PK_schema,
PK_table,
FK_schema,
FK_table
)
select distinct
PK.TABLE_SCHEMA PK_schema,
PK.TABLE_NAME PK_table,
FK.TABLE_SCHEMA FK_schema,
FK.TABLE_NAME FK_table
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK
inner join
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
on C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
inner join
INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK
on C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
where PK.CONSTRAINT_TYPE = 'PRIMARY KEY'
and
-- ignore self-references
not (
PK.TABLE_SCHEMA = FK.TABLE_SCHEMA
and
PK.TABLE_NAME = FK.TABLE_NAME
)
;
with relation(
sourceSchema,
sourceTable,
PK_schema,
PK_table,
FK_schema,
FK_table,
path
) as (
/* Part 2: Find PKs that are referenced more then once (reduces workload for next step) */
-- anchor: more then one fk reference these pk tables
select fk_pk.PK_schema sourceSchema,
fk_pk.PK_table sourceTable,
fk_pk.PK_schema,
fk_pk.PK_table,
fk_pk.FK_schema,
fk_pk.FK_table,
cast(fk_pk.PK_schema as nvarchar(max)) + @delimDot + fk_pk.PK_table + @delimList + fk_pk.FK_schema + @delimDot + fk_pk.FK_table path
from #fk_pk fk_pk
where exists(
select 1
from #fk_pk fk_pk_exists
where fk_pk_exists.PK_schema = fk_pk.PK_schema
and
fk_pk_exists.PK_table = fk_pk.PK_table
and
not (
fk_pk_exists.FK_schema = fk_pk.FK_schema
and
fk_pk_exists.FK_table = fk_pk.FK_table
)
)
/* Part 3: Find all possible paths from those PK tables to any other table (using recursive CTE) */
union all
-- recursive
select relation.sourceSchema,
relation.sourceTable,
fk_pk_child.PK_schema,
fk_pk_child.PK_table,
fk_pk_child.FK_schema,
fk_pk_child.FK_table,
/* Part 5: Display result nicely
compose a path like: A -> B -> C */
relation.path + @delimList + fk_pk_child.FK_schema + @delimDot + fk_pk_child.FK_table path
from #fk_pk fk_pk_child
inner join
relation
on relation.FK_schema = fk_pk_child.PK_schema
and
relation.FK_table = fk_pk_child.PK_table
)
/* Part 4: Identify problematic circles */
select relation.sourceSchema + @delimDot + relation.sourceTable source,
relation.FK_schema + @delimDot + relation.FK_table target,
relation.path
from relation
where exists(
select 1
from relation relation_exists
where relation_exists.sourceSchema = relation.sourceSchema
and
relation_exists.sourceTable = relation.sourceTable
and
not (
relation_exists.PK_schema = relation.PK_schema
and
relation_exists.PK_table = relation.PK_table
)
and
relation_exists.FK_schema = relation.FK_schema
and
relation_exists.FK_table = relation.FK_table
)
order by relation.sourceSchema,
relation.sourceTable,
relation.FK_schema,
relation.FK_table,
relation.path
drop table #fk_pk
go
它報告的循環引用,並形成圓形的路徑。
該腳本僅適用於SQL Server,其代碼爲github repo。請讓我知道你是否將它移植到其他RDBMS。
你只是指外鍵引用?因爲可能存在其他依賴項,例如引用從另一個表中抽取的UDF的檢查約束等。 –
是的,我的意思是外鍵引用! – Sooraj