2009-08-10 175 views
32

有誰知道一個查詢列出了應用了「WITH NOCHECK」說明的數據庫中的所有外鍵嗎? (去除它們將提高性能和穩定性)。如何在SQL Server中使用「WITH NOCHECK」列出所有外鍵

+1

什麼版本的SQL Server? – 2009-08-10 08:42:36

+0

SQL Server 2005 – digiguru 2009-08-10 08:50:07

+0

夥計們,我需要同樣的東西,但SQL 2000兼容! – 2010-05-19 22:48:43

回答

30

下面將在目前的返回外鍵的名稱數據庫與NOCHECK

殘疾人即對於SQL Server 2005/2008:

select * from sys.foreign_keys where is_disabled=1 




有大約不受信任禁用&之間的差別,答案了一些討論。 以下內容解釋了差異 下面是一些代碼,用於說明is_disabled &之間的區別是不可信的。

-- drop table t1 
-- drop table t2 
create table t1(i int not null, fk int not null) 
create table t2(i int not null) 
-- create primary key on t2 
alter table t2 
add constraint pk_1 primary key (i) 
-- create foriegn key on t1 
alter table t1 
add constraint fk_1 foreign key (fk) 
    references t2 (i) 
--insert some records 
insert t2 values(100) 
insert t2 values(200) 
insert t2 values(300) 
insert t2 values(400) 
insert t2 values(500) 
insert t1 values(1,100) 
insert t1 values(2,100) 
insert t1 values(3,500) 
insert t1 values(4,500) 
---------------------------- 
-- 1. enabled and trusted 
select name,is_disabled,is_not_trusted from sys.foreign_keys 
GO 

-- 2. disable the constraint 
alter table t1 NOCHECK CONSTRAINT fk_1 
select name,is_disabled,is_not_trusted from sys.foreign_keys 
GO 

-- 3. re-enable constraint, data isnt checked, so not trusted. 
-- this means the optimizer will still have to check the column 
alter table t1 CHECK CONSTRAINT fk_1 
select name,is_disabled,is_not_trusted from sys.foreign_keys 
GO 

--4. drop the foreign key constraint & re-add 
-- it making sure its checked 
-- constraint is then enabled and trusted 
alter table t1 DROP CONSTRAINT fk_1 
alter table t1 WITH CHECK 
add constraint fk_1 foreign key (fk) 
    references t2 (i) 
select name,is_disabled,is_not_trusted from sys.foreign_keys 
GO 


--5. drop the foreign key constraint & add but dont check 
-- constraint is then enabled, but not trusted 
alter table t1 DROP CONSTRAINT fk_1 
alter table t1 WITH NOCHECK 
add constraint fk_1 foreign key (fk) 
    references t2 (i) 
select name,is_disabled,is_not_trusted from sys.foreign_keys 
GO 

is_disabled手段約束被禁用

isnottrusted意味着SQL Server不相信,列已針對外鍵表檢查。

因此不能假定重新啓用外鍵約束將被優化。爲確保優化器信任該列,最好放棄外鍵約束&使用WITH CHECK選項(4.)

+1

對不起,我剛纔讀了這個答案。這真是太棒了! – digiguru 2011-02-01 15:53:15

+10

您可以重新啓用約束,並使用以下代碼同時檢查: 'ALTER TABLE t1 WITH CHECK CHECK CONSTRAINT fk_1' 這比刪除和重新創建約束更簡單一些。 – Aaron 2012-09-12 19:40:11

5

WITH NOCHECK應該只適用於FK的暫時性,或者當您的鏈接文章指出它們對優化程序無用時。從BOL:

的查詢優化器不會考慮與 NOCHECK定義 約束。這些約束將被忽略 ,直到通過使用 重新啓用它們爲止。ALTER TABLE表CHECK CONSTRAINT ALL。

這會找出所有的外鍵(在WITH NOCHECK位工作...)

SELECT C.TABLE_CATALOG [PKTABLE_QUALIFIER], 
     C.TABLE_SCHEMA [PKTABLE_OWNER], 
     C.TABLE_NAME [PKTABLE_NAME], 
     KCU.COLUMN_NAME [PKCOLUMN_NAME], 
     C2.TABLE_CATALOG [FKTABLE_QUALIFIER], 
     C2.TABLE_SCHEMA [FKTABLE_OWNER], 
     C2.TABLE_NAME [FKTABLE_NAME], 
     KCU2.COLUMN_NAME [FKCOLUMN_NAME], 
     RC.UPDATE_RULE, 
     RC.DELETE_RULE, 
     C.CONSTRAINT_NAME [FK_NAME], 
     C2.CONSTRAINT_NAME [PK_NAME], 
     CAST(7 AS SMALLINT) [DEFERRABILITY] 
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS C 
     INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU 
     ON C.CONSTRAINT_SCHEMA = KCU.CONSTRAINT_SCHEMA 
      AND C.CONSTRAINT_NAME = KCU.CONSTRAINT_NAME 
     INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC 
     ON C.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA 
      AND C.CONSTRAINT_NAME = RC.CONSTRAINT_NAME 
     INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C2 
     ON RC.UNIQUE_CONSTRAINT_SCHEMA = C2.CONSTRAINT_SCHEMA 
      AND RC.UNIQUE_CONSTRAINT_NAME = C2.CONSTRAINT_NAME 
     INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU2 
     ON C2.CONSTRAINT_SCHEMA = KCU2.CONSTRAINT_SCHEMA 
      AND C2.CONSTRAINT_NAME = KCU2.CONSTRAINT_NAME 
      AND KCU.ORDINAL_POSITION = KCU2.ORDINAL_POSITION 
WHERE C.CONSTRAINT_TYPE = 'FOREIGN KEY' 

Ref

順便說一句,這兩個SQL Server 2000和2005年,但如果任何數據違反使用約束檢查:

DBCC CHECKCONSTRAINTS (table_name) 
+0

DBCC CHECKCONSTRAINTS很有用,但這實際上並沒有回答這個問題。 – digiguru 2009-08-10 09:27:13

9
SELECT * FROM sys.foreign_keys AS f Where Is_Not_Trusted = 1 
+1

is_not_trusted列表示sql server沒有*檢查*值以確保FK的完整性。即如果約束曾應用NOCHECK!這非常聰明,實際上優化器會用來確定它是否可以信任列的完整性。所以你需要做的是不重新啓用約束,但重新檢查列 – 2009-08-10 09:59:43

+0

但它不是「禁用」。你會如何建議執行「重新啓用」它? – digiguru 2009-08-10 10:24:48

+0

+1:digiguru,http://msdn.microsoft.com/en-us/library/ms189807.aspx您可以像這樣重新檢查密鑰:'ALTER TABLE [schema]。[table] CHECK CONSTRAINT [FK_myConstraint] ' – Brad 2010-10-29 19:57:15

2

重新創建它以下代碼將檢索標記爲'WITH NOCHECK'的所有外鍵,然後使用ALTER語句來解決這些問題了:

-- configure cursor on all FKs with "WITH NOCHECK" 
DECLARE UntrustedForeignKeysCursor CURSOR STATIC FOR 
    SELECT f.name, 
      t.name 
    FROM sys.foreign_keys AS f 
      LEFT JOIN sys.tables AS t 
       ON f.parent_object_id = t.object_id 
    Where Is_Not_Trusted = 1 
OPEN UntrustedForeignKeysCursor 

-- loop through the untrusted FKs 
DECLARE @FKName varchar(100) 
DECLARE @TableName varchar(100) 
FETCH NEXT FROM UntrustedForeignKeysCursor INTO @FKName, @TableName 
WHILE @@FETCH_STATUS = 0 
BEGIN 

    -- Rebuild the FK constraint WITH CHECK 
    EXEC ('ALTER TABLE ' + @TableName + ' WITH CHECK CHECK CONSTRAINT ' + @FKName) 

    -- get next user 
    FETCH NEXT FROM UntrustedForeignKeysCursor INTO @FKName, @TableName 

END 

-- cleanup 
CLOSE UntrustedForeignKeysCursor 
7

下面的腳本將生成ALTER語句都將檢查現有數據,並防止對那些目前沒有可信的(「WITH NOCHECK」)外鍵的任何新的違規行爲。

在SQL Server Management Studio中執行它以生成腳本,然後將它們複製到查詢窗口中以執行它們。

select 
    'alter table ' + quotename(s.name) + '.' + quotename(t.name) + ' with check check constraint ' + fk.name +';' 
from 
    sys.foreign_keys fk 
inner join 
    sys.tables t 
on 
    fk.parent_object_id = t.object_id 
inner join 
    sys.schemas s 
on 
    t.schema_id = s.schema_id 
where 
    fk.is_not_trusted = 1 
0

我知道這是一個老問題,有一些老的答案有一些很好的信息。不過,我只是想分享,我一直在使用相當多的不同的數據庫來解決這一問題方面爲我們的腳本:

-- Foreign Keys 
SELECT 'ALTER TABLE ' + o.name + ' WITH CHECK CHECK CONSTRAINT ' + i.name + ';' AS AlterStatement 
from sys.foreign_keys i 
INNER JOIN sys.objects o ON i.parent_object_id = o.object_id 
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id 
WHERE i.is_not_trusted = 1 AND i.is_not_for_replication = 0; 
GO 

-- Constraints 
SELECT 'ALTER TABLE ' + o.name + ' WITH CHECK CHECK CONSTRAINT ' + i.name + ';' AS AlterStatement 
from sys.check_constraints i 
INNER JOIN sys.objects o ON i.parent_object_id = o.object_id 
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id 
WHERE i.is_not_trusted = 1 AND i.is_not_for_replication = 0 AND i.is_disabled = 0; 
GO 

,這將產生ALTER語句的集合,以解決這個問題「NOCHECK」問題與外鍵和約束。這是基於Brent Ozar提供的一些查詢,但是我爲了我的目的和易用性而進行了調整。這可以很容易地調整與UNION使其成爲一個單一的查詢。

僅供參考,我在Azure SQL數據庫環境中專門使用了它。我不確定在舊版本的SQL Server上是否存在限制,但它在Azure中效果很好。

相關問題