使用“ WITH NOCHECK”创建外键时会丢失什么?


11

我知道如果我EXISTS()调用FK查找值,那么,如果该FK约束是可信任的,则结果是立即的。

而且,如果它不受信任(例如当我使用创建FK时WITH NOCHECK),则SQL Server必须去检查表以查看该值是否确实存在。

使用后还有其他损失NOCHECK吗?

Answers:


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知道其中没有行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 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.