阅读了很多与上述主题相关的文章和答案后,我仍然想知道SQL Server数据库引擎在以下示例中是如何工作的:
假设我们有一个名为t3的表:
create table t3 (a int , b int);
create index test on t3 (a);
并且有以下这个查询:
INSERT INTO T3
SELECT -86,-86
WHERE NOT EXISTS (SELECT 1 FROM t3 where t3.a=-86);
该查询在验证列"a"上的行是否已存在之后,将一条记录插入到表t3中。许多文章和答案表明,使用上述查询没有重复插入行的可能性。对于上述查询的执行,我假设数据库引擎按以下方式工作:
- 先执行子查询。
- 数据库引擎对范围设置共享锁(s)。
- 读取数据。
- 释放共享锁。根据MSDN,共享锁在数据被读取后立即释放。
- 如果行不存在,则在表中插入新行。
- 使用独占锁(x)锁定新行
- 处理器A(SPID 1)执行上述查询。
- 处理器B(SPID 2)执行相同的查询。
- [SPID 1]数据库引擎设置了一个共享锁(s)
- [SPID 1]子查询读取数据。现在返回了几行。
- [SPID 1]共享锁被释放。
- [SPID 2]数据库引擎设置了一个共享锁(s)
- [SPID 2]子查询读取数据。未返回任何行。
- [SPID 2]共享锁被释放。
- 两个进程都进行了一行插入(然后我们得到了重复的条目)。
begin tran
if (SELECT 1 FROM t3 with (updlock) where t3.a=-86)
begin
INSERT INTO T3
SELECT -86,-86
end
commit