【问题标题】:Read blocks A when checking foreign constraint on B检查 B 上的外部约束时读取块 A
【发布时间】:2018-07-23 14:59:56
【问题描述】:

我有一个表,表 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 上的共享锁,不会阻塞其他读取。

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

谢谢!

【问题讨论】:

  • 这似乎是一个问题,答案取决于您使用的数据库的类型/版本。那么您介意为此添加标签吗?例如,行级锁定并非无处不在。
  • 我相信只有 SQL Server 使用那种奇怪的 WITH CHECK CHECK 语法:)
  • 此 dba.SE 发布创建了一种情况,即使用 NOCHECK 选项重新启用约束将允许无效数据保留在表中:dba.stackexchange.com/questions/167861/…

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


【解决方案1】:

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

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

ALTER TABLE B WITH CHECK CHECK CONSTRAINT ALL;

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

您可以仅禁用/启用检查 FK 到 A(如果有多个)。或者您可以 disable/enable-with-nocheck 重新启用约束,但不强制执行您在更新过程中所做的更改(并且不受查询优化器的信任)。

ALTER TABLE B WITH NOCHECK CHECK CONSTRAINT ALL;

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

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

ALTER TABLE 同时影响 A 和 B,因为 A 上的 DELETE 和 UPDATE 查询强制执行 FK。所以 ALTER TABLE 在 A、B 和 FK 对象上采用 Sch-M 锁。例如:

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

输出:

object_name                      request_mode
-------------------------------- -------------
FK__B__aid__412EB0B6             Sch-M
B                                Sch-M
A                                Sch-M

(3 rows affected)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-11
    相关资源
    最近更新 更多