检查B上的外部约束时,读取块A

时间:2018-07-23 14:59:56

标签: sql sql-server performance stored-procedures foreign-keys

我有一个表,表B,该表具有表A的外键。两个表都比较大。

在表B的更新过程中,我首先禁用约束,更新内容,然后启用约束。

ALTER TABLE B NOCHECK CONSTRAINT ALL;
-- Update table b
ALTER TABLE B WITH CHECK CHECK CONSTRAINT ALL;

问题在于最后一行需要一段时间才能运行10-15分钟,而在运行时,从表A读取的速度确实很慢! Web应用程序需要表A,并且该应用程序在运行时将超时。

第一个问题:为什么会这样?我认为这只是对表A的共享锁,不会阻止其他读取。

第二个问题:如何避免这种情况?

谢谢!

1 个答案:

答案 0 :(得分:2)

  

第一个问题:为什么会这样?

因为您要求每一行B都验证其FK中的每一个。

更改表B 要检查请检查所有内容;

这可能比仅在更新期间强制执行约束要昂贵得多。

您可以仅对FK到A(如果有多个)禁用/启用检查功能。或者,您可以禁用/不带nocheck来重新启用约束,但是对于在更新过程中所做的更改(并且不受查询优化器信任),使其不被强制执行。

更改表B 不检查检查所有约束;

然后您可以安排任务以检查所有行。

  

我认为这只是表A的共享锁,不会阻止其他读取。

ALTER TABLE同时影响A和B,因为对A的DELETE和UPDATE查询强制执行FK。因此,ALTER TABLE对A,B和FK对象采用Sch-M锁定。 EG:

pmap_lgl

输出:

use tempdb

drop table if exists B
drop table if exists A

create table A(id int primary key)
create table B(id int, aid int references A)

insert into A(id) values (1)

insert into b(id,aid) values (1,1)

begin transaction

ALTER TABLE B WITH CHECK CHECK CONSTRAINT ALL 

select object_name(resource_associated_entity_id) object_name, request_mode
from sys.dm_tran_locks 
where request_session_id = @@spid 
  and resource_type = 'OBJECT'
  and request_mode = 'Sch-M'    
rollback