重新启用外键约束后执行计划奇怪

时间:2009-07-04 17:56:04

标签: sql sql-server tsql sql-execution-plan

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

我得到了与nocheck一起使用的相同的过时执行计划。

为什么SQL服务器会生成执行计划,就好像外部约束FKBtoA被禁用,即使再次使用以下语句添加检查后也是如此?

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)

但对于真正的大桌子来说,这似乎是一种矫枉过正 - 有更好的方法吗?

[ANSWER]

我必须在alter statement中添加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声明

的执行计划的屏幕截图

禁用外键约束之前
alt text

禁用外键约束后 alt text

重新启用外键约束后 alt text

3 个答案:

答案 0 :(得分:7)

很可能您的约束已启用但不受信任,因此子表中可能存在孤立行。阅读Hugo Kornelis撰写的这篇精彩文章:Can you trust your constraints?

答案 1 :(得分:1)

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

我认为你做的是某种实验,在现实世界中你应该加入那些不使用内部EXIST的表。

答案 2 :(得分:0)

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