`WITH NOCHECK` kullanarak bir Yabancı Anahtar oluşturduğumda ne kaybedilir?


11

EXISTS()Bir FK arama değeri üzerinden bir çağrı yaparsam , o zaman FK kısıtına güvenilirse, sonucun anında olduğunu biliyorum.

Ve eğer güvenilir değilse (FK kullanarak oluşturduğumda olduğu gibi WITH NOCHECK), SQL Server'ın değerin gerçekten orada olup olmadığını görmek için tabloya gitmesi gerekir.

Kullanarak kaybettiğim başka bir şey var mı NOCHECK?

Yanıtlar:


13

Örneğinizle keşfettiğiniz gibi existsSQL Server, sorgu planı oluşturulduğunda yabancı bir anahtarın güvenilir olması gerçeğini kullanabilir.

NOCHECK kullanarak kaybettiğim başka bir şey var mı?

Ste Bov tarafından yanıtlandığı gibi olmaması gereken bir sütuna değerler ekleyebilmeniz dışında , yabancı anahtar güvenilir olduğunda sorgu planının daha iyi olacağı daha fazla senaryoya sahip olacaksınız.

Dizine alınmış bir görünüme sahip bir örnek .

Güvenilir bir FK kısıtlamasına sahip iki tablonuz var.

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);

Çok fazla ülke yok ama bir milyon şehir var ve bazıları büyük şehirler.

Örnek veri:

-- 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;

Bu uygulamada en sık yürütülen sorgular, ülke başına büyük şehirlerin sayısını bulmakla ilgilidir. Bunu hızlandırmak için dizine eklenmiş bir görünüm ekliyoruz.

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);

Bir süre sonra yeni bir ülke ekleme talebi geliyor

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

Bu ek için sorgu planının sürprizleri yoktur.

resim açıklamasını buraya girin

Tabloya kümelenmiş dizin ekleme Country.

Şimdi, yabancı anahtarınıza güvenilmediyse

alter table dbo.City nocheck constraint FK_CountryID;

ve yeni bir ülke eklersin

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

Sonunda bu kadar hoş olmayan bir resim elde edersiniz.

resim açıklamasını buraya girin

Alt dal, dizinlenmiş görünümü güncellemek için oradadır. Tabloda zaten satırları Cityolan ülkenin olup olmadığını anlamak için tam bir tablo taraması yapar .CountryID = 5City

Anahtar güvenilir olduğunda, SQL Server içinde Cityyeni satırla eşleşen hiçbir satır olmadığını bilir Country.


4

Sorgu optimizasyonlarını kaybediyorsunuz. Pratikte hatırladığım tek optimizasyon, gereksiz birleşimlerin ortadan kaldırılmasıdır. Örneğin bir görünümde varsa:

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

Ve görünümü kullanırken, cuygun bir FK ayarı varsa, o birleştirmenin sütunlarını kullanmazsınız .

Sizin EXISTSörnek yedekli katılmak kaldırılması özel bir durumudur. Belirli bir örneğin pratikte geçerli olduğunu düşünmüyorum.

Ayrıca, güvenilir bir kısıtlamanın sağladığı katı veri bütünlüğünü de kaybedersiniz.


3

NOCHECK opsiyonu kalayda söylediklerini aynen yapar.

Esas olarak, gerekli olmayan yeni bir ilişkinin olduğu bir tablonun varlığında yarıya yabancı bir anahtar eklemek için kullanılır (en azından benim anlayışım budur).

Bu, yabancı anahtar MAY (MAY) anahtarına sahip sütunun, içinde ilgili olması gereken atanmış değerle ilişkili olmayan değerlere sahip olduğu anlamına gelir.

Bu, SQL Server'da bir NOCHECK seçeneğiniz olduğunda, bu anahtar değerinin gerçekten birincil anahtar olup olmadığını gerçekten kontrol etmesi gerektiği anlamına gelir. NOCHECK ayarlanmamışsa, SQL Server bu sütunda bulunan herhangi bir şeyin kesinlikle var olduğunu varsayar, çünkü giriş zaten birincil anahtar olmasaydı tabloda bulunamamıştır ve içindeki satırı silmeden birincil anahtarı silemediniz. soru.

Basitçe NOCHECK, herhangi bir şeyle ilişki kurmak için güvenemeyeceğiniz yabancı bir anahtardır.

Aslında birincil anahtarın orada olacağına dair güven dışında bir şey kaybetmiyorsunuz.


Kısıtlamanın ilk oluşturulduktan sonra yabancı anahtarın uygulanıp uygulanmayacağı cevabınızdan anlaşılamaz . INSERTMevcut olmayan bir üst satırla ilgili yeni bir satıra çalışırsanız veya DELETEdaha sonra alt satırları olan bir satıra çalışırsanız ne olacağını açıklığa kavuşturabilir misiniz ?
jpmc26
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.