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

Vac*_*ano 12 foreign-key sql-server t-sql

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

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

使用我还有什么损失NOCHECK吗?

Mik*_*son 14

正如您在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);
Run Code Online (Sandbox Code Playgroud)

没有那么多国家,但有无数城市,其中一些是大城市。

样本数据:

-- 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;
Run Code Online (Sandbox Code Playgroud)

此应用程序中最常执行的查询与查找每个国家/地区的大城市数量有关。为了加快速度,我们添加了一个索引视图。

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);
Run Code Online (Sandbox Code Playgroud)

过了一会儿又出现了添加一个新国家的需求

insert into dbo.Country(CountryID, Name) values(4, 'Finland');
Run Code Online (Sandbox Code Playgroud)

该插入的查询计划没有任何意外。

在此处输入图片说明

Country表的聚集索引插入。

现在,如果您的外键不受信任

alter table dbo.City nocheck constraint FK_CountryID;
Run Code Online (Sandbox Code Playgroud)

然后你添加了一个新的国家

insert into dbo.Country(CountryID, Name) values(5, 'Iceland');
Run Code Online (Sandbox Code Playgroud)

你最终会得到这张不太漂亮的照片。

在此处输入图片说明

较低的分支用于更新索引视图。它会进行全表扫描,City以确定表中是否CountryID = 5已包含行的国家/地区City

当密钥受信任时,SQL Server 知道中不可能有City与 中的新行匹配的行Country


Ste*_*Bov 3

NOCHECK 选项的作用与它在罐子上所说的完全一样。

它主要用于在表存在的过程中添加外键,其中存在可能不需要的新关系(至少这是我的理解)。

这意味着具有外键的列中可能包含与其应关联的指定值不相关的值。

这意味着当 SQL Server 上有 NOCHECK 选项时,必须实际检查该键值是否实际上是主键。如果未设置 NOCHECK,则 SQL Server 假定该列中的任何内容肯定存在,因为如果该条目还不是主键,则该条目不可能存在于表中,并且如果不删除其中的行,则无法删除主键。问题。

简而言之,NOCHECK 是一个外键,您不能相信它实际上与任何事物相关。

除了主键保证存在的信任之外,您实际上并没有失去任何东西。