「WITH NOCHECK」を使用して外部キーを作成すると、何が失われますか?


11

EXISTS()FKルックアップ値で呼び出しを行うと、そのFK制約が信頼できる場合、結果はすぐにわかります。

そして、それが信頼されていない場合(を使用してFKを作成するときなどWITH NOCHECK)、SQL Serverはテーブルに移動して、値が実際に存在するかどうかを確認する必要があります。

他に使用することで失うものはありNOCHECKますか?

回答:


13

このexists例で発見したように、SQL Serverは、クエリプランの構築時に外部キーが信頼されているという事実を利用できます。

NOCHECKを使用することで他に失うものはありますか?

Ste Bovによって回答されたはずのない列に値を追加できるという事実とは別に、外部キーが信頼されている場合にクエリプランがより適切になるシナリオが増えます。

以下は、インデックス付きビューの例です。

信頼できるFK制約を持つ2つのテーブルがあります。

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 Cityは、の新しい行と一致する行がないことを認識していますCountry


4

クエリの最適化を失っています。実際、私が思い出す唯一の最適化は、冗長な結合の除去です。たとえば、ビューにいる場合:

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

また、ビューを使用するc場合、適切なFKが設定されていれば、その結合を削除できます。

あなたのEXISTS例は、冗長な結合を削除する特別なケースです。特定の例が実際に関連しているとは思いません。

また、信頼できる制約が提供する厳密なデータの整合性も失われます。


3

NOCHECKオプションは、缶に書かれていることを正確に実行します。

これは主に、必要とされていない可能性のある新しい関係が存在するテーブルの存在の途中で、外部キーを追加するために使用されます(少なくとも私の理解です)。

これは、外部キーを持つ列に、関連する指定された値と相関しない値が含まれる可能性があることを意味します。

つまり、SQL ServerにNOCHECKオプションがある場合、実際に行って、そのキー値が実際に主キーであるかどうかを確認する必要があります。NOCHECKが設定されていない場合、SQL Serverは、その列に何かが確実に存在するものと見なします。これは、エントリがまだ主キーでない場合、テーブルにエントリが存在できなかったためであり、主キーを削除するには、行を削除する必要があります。質問。

単にNOCHECKは外部キーであり、実際に何かに関係するとは信頼できません。

実際には、主キーが存在することが保証されているという信頼以外は何も失っていません。


制約を最初に作成した後で外部キーが適用されているかどうかは、回答から明らかではありません。INSERT存在しない親行に関連する新しい行を試みた場合、またはDELETE後で子行を含む行を試みた場合に何が起こるかを明確にできますか?
jpmc26
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.