5

我有一个奇怪的问题,在设置nocheck外部约束并重新启用它之后,

我得到了一个与nocheckon 一起使用的过时的执行计划。

为什么FKBtoA即使在使用以下语句再次添加检查后,SQL Server 仍会生成执行计划,就好像禁用了外部约束一样?

alter table B check constraint FKBtoA

[UPDATE1]
到目前为止,删除外部约束并读取它是有效的。

alter table B drop constraint FKBtoA
alter table B add constraint FKBtoA foreign key (AID) references A(ID)

但是对于非常大的桌子,这似乎有点过头了——有没有更好的方法?

[回答]

我必须添加WITH CHECK如下更改语句才能获得旧的执行计划

alter table B WITH CHECK add constraint FKBtoA foreign key (AID) references A(ID)

这是完整的 SQL 语句

create table A ( ID int identity primary key )
create table B ( 
    ID int identity primary key,
    AID int not null constraint FKBtoA references A (ID)
)

select  *
from    B
where   exists (select 1 from A where A.ID = B.AID)

alter table B nocheck constraint FKBtoA
GO
select  *
from    B
where   exists (select 1 from A where A.ID = B.AID)

alter table B check constraint FKBtoA
GO
select  *
from    B
where   exists (select 1 from A where A.ID = B.AID)

这是每个SELECT语句的执行计划截图

在禁用外键约束之前
替代文字

禁用外键约束后
替代文字

重新启用外键约束后
替代文字

4

3 回答 3

7

很可能您的约束已启用但不受信任,因此您的子表中可能存在孤立行。阅读 Hugo Kornelis 的这篇精彩文章:你能相信你的约束吗?

于 2009-07-04T19:43:10.700 回答
1

从您发布的脚本和计划中连接器的宽度来看,这些表中似乎没有任何数据。分析空表上的查询计划在很大程度上是无关紧要的:在单页读取时,优化器几乎肯定会选择全扫描。

我假设您这样做是为了进行某种实验,在现实世界中,您应该加入那些不使用内部 EXIST 的表。

于 2009-07-04T18:43:55.053 回答
0

我个人不知道,但我知道如何重建统计数据......

于 2009-07-04T18:01:37.010 回答