这项工作是从由于 FK 检查导致 SQL Server 中的更新冲突而中止的快照隔离事务之后进行的。
我运行此代码来创建数据库:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Parent]
(
[ParentID] [int] NOT NULL,
[UpdateTime] [datetime] NOT NULL,
CONSTRAINT [PK dbo.Parent ParentID]
PRIMARY KEY CLUSTERED ([ParentID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Child]
(
[ChildID] [int] NOT NULL,
[ParentID] [int] NULL,
[UpdateTime] [datetime] NULL,
CONSTRAINT [PK dbo.Child ChildID]
PRIMARY KEY CLUSTERED ([ChildID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Child] WITH CHECK
ADD CONSTRAINT [FK dbo.Child to dbo.Parent]
FOREIGN KEY([ParentID]) REFERENCES [dbo].[Parent] ([ParentID])
GO
ALTER TABLE [dbo].[Child] CHECK CONSTRAINT [FK dbo.Child to dbo.Parent]
GO
CREATE TABLE [dbo].[Dummy]
(
[x] [int] NULL
) ON [PRIMARY]
GO
数据库必须允许快照隔离并启用已提交的读取快照。
填充数据库如下:
DELETE FROM dbo.Child
DELETE FROM dbo.Parent
GO
-- Insert parent rows
INSERT INTO dbo.Parent (ParentID, UpdateTime) VALUES (1, GETUTCDATE());
INSERT INTO dbo.Parent (ParentID, UpdateTime) VALUES (2, GETUTCDATE());
INSERT INTO dbo.Parent (ParentID, UpdateTime) VALUES (3, GETUTCDATE());
-- Insertion a child row
INSERT INTO dbo.Child select 101, 2, GetUTCDate()
go
然后运行这两个脚本(按照指示):
-- Session 1 - part one (1st bit to run)
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRANSACTION;
-- Ensure snapshot transaction is started
SELECT COUNT_BIG(*) FROM dbo.Dummy AS D;
-- Session 1 - part two (3rd bit to run)
DELETE FROM dbo.Parent WHERE ParentID = 3
-- Session 2 - part one (2nd bit to run)
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN TRANSACTION;
UPDATE dbo.Child
SET UpdateTime = GETUTCDATE()
WHERE ParentID = 1
INSERT INTO dbo.Child
SELECT 201, 2, GetUTCDate()
-- Session 2 - part two (4th bit to run)
COMMIT TRANSACTION;
会话 1 按预期生成更新错误:
消息 3960,级别 16,状态 1,第 10 行
快照隔离事务因更新冲突而中止。您不能使用快照隔离直接或间接访问数据库“Example Changed”中的表“dbo.Child”来更新、删除或插入已被另一个事务修改或删除的行。重试事务或更改更新/删除语句的隔离级别。
根据文章,这应该通过将 PK 更改为非聚集并添加唯一的聚集索引来消除,但会产生相同的错误。这样做应该可以解决 FK 问题,但似乎并没有解决,即使执行计划暗示它应该这样做。
为什么现在是这样?
谢谢伊恩