อะไรจะหายไปเมื่อฉันสร้าง Foreign Key โดยใช้ "WITH NOCHECK"


11

ฉันรู้ว่าถ้าฉันEXISTS()โทรหาค่าการค้นหา FK ดังนั้นถ้าข้อ จำกัด FK นั้นเชื่อถือได้ผลลัพธ์จะเป็นทันที

และถ้ามันไม่น่าเชื่อถือ (เช่นเมื่อฉันสร้าง FK โดยใช้WITH NOCHECK) แล้ว SQL Server จะต้องไปและตรวจสอบตารางเพื่อดูว่าค่านั้นมีจริง

มีอะไรอีกบ้างที่ฉันแพ้โดยใช้NOCHECK?

คำตอบ:


13

ตามที่คุณได้ค้นพบกับ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


4

คุณกำลังสูญเสียการเพิ่มประสิทธิภาพข้อความค้นหา ในทางปฏิบัติการเพิ่มประสิทธิภาพเพียงอย่างเดียวที่ฉันจำได้คือกำจัดการรวมที่ซ้ำซ้อน ตัวอย่างเช่นถ้าคุณมีมุมมอง:

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

และเมื่อใช้มุมมองคุณไม่ได้ใช้ประโยชน์จากคอลัมน์จากcนั้นเข้าร่วมสามารถลบได้หากมีการตั้งค่า FK ที่เหมาะสม

EXISTSตัวอย่างของคุณเป็นกรณีพิเศษในการลบการเข้าร่วมที่ซ้ำซ้อน ฉันไม่คิดว่าตัวอย่างเฉพาะนั้นมีความเกี่ยวข้องกันจริง

คุณสูญเสียความถูกต้องของข้อมูลที่เข้มงวดซึ่งมีข้อ จำกัด ที่เชื่อถือได้


3

ตัวเลือก NOCHECK ทำสิ่งที่ตรงกับที่บอกไว้บนกระป๋อง

ส่วนใหญ่จะใช้สำหรับการเพิ่มคีย์ต่างประเทศครึ่งทางผ่านการมีอยู่ของตารางที่มีความสัมพันธ์ใหม่ที่อาจไม่จำเป็นต้องใช้ (นั่นคือความเข้าใจของฉันอย่างน้อย)

หมายความว่าคอลัมน์ที่มีคีย์ต่างประเทศอาจมีค่าอยู่ภายในซึ่งไม่เกี่ยวข้องกับค่าที่ตั้งไว้ซึ่งควรเกี่ยวข้อง

ซึ่งหมายความว่าเมื่อคุณมีตัวเลือก NOCHECK บน SQL Server ต้องไปจริง ๆ และตรวจสอบว่าค่าคีย์นั้นเป็นคีย์หลักจริงหรือไม่ หากไม่ได้ตั้งค่า NOCHECK แล้ว SQL Server จะถือว่ามีสิ่งใดก็ตามที่อยู่ในคอลัมน์นั้นอย่างแน่นอนเนื่องจากรายการไม่สามารถอยู่ในตารางได้หากยังไม่ได้เป็นคีย์หลักและคุณไม่สามารถลบคีย์หลักโดยไม่ต้องลบแถวใน คำถาม.

เพียงแค่ NOCHECK เป็นกุญแจสำคัญในต่างประเทศที่คุณไม่สามารถเชื่อใจได้ว่าเกี่ยวข้องกับอะไร

คุณไม่ได้สูญเสียสิ่งใดนอกจากความไว้วางใจที่คีย์หลักรับประกันว่าจะมี


ไม่ชัดเจนจากคำตอบของคุณว่ามีการบังคับใช้คีย์ foreign หลังจากการสร้างข้อ จำกัดครั้งแรกหรือไม่ คุณสามารถอธิบายให้ชัดเจนว่าเกิดอะไรขึ้นถ้าคุณลองINSERTแถวใหม่ที่เกี่ยวข้องกับแถวหลักที่ไม่มีอยู่หรือถ้าคุณลองDELETEแถวที่มีแถวลูกในภายหลัง
jpmc26
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.