Sql-Server

當我使用“WITH NOCHECK”創建外鍵時會失去什麼?

  • September 8, 2015

我知道,如果我EXISTS()對 FK 查找值進行呼叫,那麼,如果該 FK 約束是可信的,那麼結果是立竿見影的。

如果它不被信任(比如當我使用創建 FK 時WITH NOCHECK),那麼 SQL Server 必須去檢查表以查看該值是否確實存在。

使用還有什麼我會失去的NOCHECK嗎?

正如您在exists範例中發現的那樣,SQL Server 可以在建構查詢計劃時使用外鍵受信任這一事實。

使用 NOCHECK 我還有什麼損失嗎?

除了您可以向Ste Bov回答的不應存在的列添加值這一事實之外,您將有更多的場景,當外鍵受信任時,查詢計劃會更好。

這是一個帶有索引視圖的範例。

您有兩個具有受信任 FK 約束的表。

create table dbo.Country
(
 CountryID int primary key,
 Name varchar(50) not null
);

create table dbo.City
(
 CityID int identity primary key,
 Name varchar(50),
 IsBig bit not null,
 CountryID int not null
);

alter table dbo.City 
 add constraint FK_CountryID 
 foreign key (CountryID) 
 references dbo.Country(CountryID);

國家不多,但城市數不勝數,其中一些是大城市。

樣本數據:

-- Three countries
insert into dbo.Country(CountryID, Name) values
(1, 'Sweden'),
(2, 'Norway'),
(3, 'Denmark');

-- Five big cities
insert into dbo.City(Name, IsBig, CountryID) values
('Stockholm', 1, 1),
('Gothenburg', 1, 1),
('Malmoe', 1, 1),
('Oslo', 1, 2),
('Copenhagen', 1, 3);

-- 300 small cities
insert into dbo.City(Name, IsBig, CountryID)
select 'NoName', 0, Country.CountryID
from dbo.Country
 cross apply (
             select top(100) *
             from sys.columns
             ) as T;

此應用程序中最常執行的查詢與查找每個國家/地區的大城市數量有關。為了加快速度,我們添加了一個索引視圖。

create view dbo.BigCityCount with schemabinding
as
select count_big(*) as BigCityCount,
      City.CountryID,
      Country.Name as CountryName
from dbo.City
 inner join dbo.Country
   on City.CountryID = Country.CountryID
where City.IsBig = 1 
group by City.CountryID,
        Country.Name;

go

create unique clustered index CX_BigCityCount
 on dbo.BigCityCount(CountryID);

一段時間後,需要添加一個新國家/地區

insert into dbo.Country(CountryID, Name) values(4, 'Finland');

該插入的查詢計劃沒有任何意外。

在此處輸入圖像描述

Country表中插入聚集索引。

現在,如果您的外鍵不受信任

alter table dbo.City nocheck constraint FK_CountryID;

然後你添加了一個新國家

insert into dbo.Country(CountryID, Name) values(5, 'Iceland');

你最終會得到這張不太漂亮的照片。

在此處輸入圖像描述

較低的分支用於更新索引視圖。它會進行全表掃描以確定表中是否已經有行City的國家/地區。CountryID = 5``City

當密鑰受信任時,SQL Server 知道其中沒有CityCountry.

您正在失去查詢優化。實際上,我記得的唯一優化是消除冗餘連接。例如,如果您有一個視圖:

select *
from Orders o
join Customers c on o.CustomerID = c.ID

並且在使用視圖時,c如果設置了正確的 FK,則可以刪除該連接的列。

您的EXISTS範例是刪除冗餘連接的特例。我認為這個特定的例子實際上並不相關。

您還會失去可信約束提供的嚴格數據完整性。

引用自:https://dba.stackexchange.com/questions/114411