从数据库中删除行时,由于更新冲突,快照隔离事务中止

Spu*_*nik 4 sql-server snapshot-isolation sql-server-2019

我在这个问题上花了一些时间,终于有了一个重现该问题的示例(即使在所有 FK 上都有适当的非聚集索引)。

这是数据库操作的简要概述:

a) 更新/插入是在已提交读(快照)隔离下完成的。

b) 项目的删除是在快照隔离下完成的。

c) 所有FK都有索引。

清除过程会从数据库中删除旧的行。20-60 分钟后,下面的删除脚本将失败并出现快照错误。我被告知 FK 检查会恢复为读提交隔离,但即使这样也无法解释我们下面看到的内容。

重现步骤:

a) 创建数据库并确保快照选项为True。我们将该数据库称为 SnapshotTest。

b) 使用以下脚本创建数据库:

ALTER DATABASE [SnapshotTest] SET READ_COMMITTED_SNAPSHOT ON
GO
CREATE TYPE [dbo].[udtPPChildObject] AS TABLE(
    [InsertionId] [bigint] NOT NULL,
    [ChildInsertionId] [bigint] NOT NULL,
    [PropertyMapNameId] [int] NOT NULL,
    [UpdateId] [bigint] NULL,
    PRIMARY KEY CLUSTERED 
(
    [ChildInsertionId] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
CREATE TYPE [dbo].[udtPPChildObjectList] AS TABLE(
    [InsertionId] [bigint] NOT NULL,
    [ChildInsertionId] [bigint] NOT NULL,
    [SortIndex] [int] NULL,
    [UpdateId] [bigint] NULL,
    [SortText] [nvarchar](260) NULL,
    [RemovalThreshold] [bigint] NULL,
    PRIMARY KEY CLUSTERED 
(
    [ChildInsertionId] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
CREATE TYPE [dbo].[udtPPGuidList] AS TABLE(
    [Guid] [uniqueidentifier] NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [Guid] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
CREATE TYPE [dbo].[udtPPObject] AS TABLE(
    [InsertionId] [bigint] NOT NULL,
    [ObjectId] [uniqueidentifier] NOT NULL,
    [TypeNameId] [int] NOT NULL,
    [UpdateId] [bigint] NULL,
    [SourceInterpreterID] [uniqueidentifier] NULL,
    [LevelID] [nvarchar](max) NULL,
    [SearchParentInsertionID] [bigint] NULL,
    PRIMARY KEY CLUSTERED 
(
    [InsertionId] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
CREATE TYPE [dbo].[udtPPObjectBlobProperty] AS TABLE(
    [InsertionId] [bigint] NOT NULL,
    [PropertyMapNameId] [int] NOT NULL,
    [BlobValue] [varbinary](max) NULL,
    [UpdateId] [bigint] NULL,
    PRIMARY KEY CLUSTERED 
(
    [InsertionId] ASC,
    [PropertyMapNameId] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
CREATE TYPE [dbo].[udtPPObjectProperty] AS TABLE(
    [InsertionId] [bigint] NOT NULL,
    [PropertyMapNameId] [int] NOT NULL,
    [UpdateId] [bigint] NOT NULL,
    [BitValue] [bit] NULL,
    [UIDValue] [uniqueidentifier] NULL,
    [FloatValue] [float] NULL,
    [BigIntValue] [bigint] NULL,
    [IntValue] [int] NULL,
    [NVarCharValue] [nvarchar](max) NULL,
    [SearchText] [nvarchar](max) NULL,
    [TypeIndex] [tinyint] NOT NULL,
    PRIMARY KEY CLUSTERED 
(
    [InsertionId] ASC,
    [PropertyMapNameId] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
CREATE TABLE [dbo].[tblPPObject](
    [ObjectID] [uniqueidentifier] NOT NULL,
    [UpdateTime] [datetime] NULL,
    [InsertionID] [bigint] NOT NULL,
    [SourceInterpreterID] [uniqueidentifier] NULL,
    [LevelID] [nvarchar](260) NULL,
    [UpdateID] [bigint] NULL,
    [TypeNameID] [int] NOT NULL,
    [SearchParentInsertionID] [bigint] NULL,
 CONSTRAINT [PK_tblPPObject] PRIMARY KEY CLUSTERED 
(
    [InsertionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblPPObjectBlobProperty](
    [Value] [varbinary](max) NULL,
    [UpdateTime] [datetime] NULL,
    [InsertionID] [bigint] NOT NULL,
    [UpdateID] [bigint] NULL,
    [PropertyMapNameID] [int] NOT NULL,
 CONSTRAINT [PK_tblPPObjectBlobProperty] PRIMARY KEY CLUSTERED 
(
    [InsertionID] ASC,
    [PropertyMapNameID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblPPObjectChildObject](
    [UpdateTime] [datetime] NULL,
    [InsertionID] [bigint] NOT NULL,
    [ChildInsertionID] [bigint] NOT NULL,
    [UpdateID] [bigint] NULL,
    [PropertyMapNameID] [int] NULL,
 CONSTRAINT [PK_tblPPObjectChildObject] PRIMARY KEY CLUSTERED 
(
    [InsertionID] ASC,
    [ChildInsertionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblPPObjectChildObjectList](
    [SortIndex] [int] NOT NULL,
    [UpdateTime] [datetime] NULL,
    [InsertionID] [bigint] NOT NULL,
    [ChildInsertionID] [bigint] NOT NULL,
    [SortText] [nvarchar](260) NULL,
    [UpdateID] [bigint] NULL,
    [RemovalThreshold] [bigint] NULL,
 CONSTRAINT [PK_tblPPObjectChildObjectList] PRIMARY KEY CLUSTERED 
(
    [InsertionID] ASC,
    [ChildInsertionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblPPObjectProperty](
    [UpdateTime] [datetime] NULL,
    [InsertionID] [bigint] NOT NULL,
    [BitValue] [bit] NULL,
    [UIDValue] [uniqueidentifier] NULL,
    [FloatValue] [float] NULL,
    [BigIntValue] [bigint] NULL,
    [IntValue] [int] NULL,
    [NVarCharValue] [nvarchar](max) NULL,
    [TypeIndex] [tinyint] NOT NULL,
    [SearchText] [nvarchar](max) NULL,
    [UpdateID] [bigint] NULL,
    [PropertyMapNameID] [int] NOT NULL,
 CONSTRAINT [PK_tblPPObjectProperty] PRIMARY KEY CLUSTERED 
(
    [InsertionID] ASC,
    [PropertyMapNameID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblPPPropertyMapName](
    [PropertyMapName] [varchar](max) NOT NULL,
    [PropertyMapNameID] [int] IDENTITY(1,1) NOT NULL,
 CONSTRAINT [PK_tblPPPropertyMapName] PRIMARY KEY CLUSTERED 
(
    [PropertyMapNameID] 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] TEXTIMAGE_ON [PRIMARY]
GO
CREATE TABLE [dbo].[tblPPRedundantObjects](
    [InsertionID] [bigint] NOT NULL,
    [UpdateTime] [datetime] NULL,
 CONSTRAINT [PK_tblPPRedundantObjects] PRIMARY KEY CLUSTERED 
(
    [InsertionID] 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].[tblPPTypeName](
    [TypeName] [varchar](max) NOT NULL,
    [TypeNameID] [int] IDENTITY(1,1) NOT NULL,
 CONSTRAINT [PK_tblPPTypeName] PRIMARY KEY CLUSTERED 
(
    [TypeNameID] 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] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObject_LevelID_TypeNameID_InsertionID_INC_ObjectID] ON [dbo].[tblPPObject]
(
    [LevelID] ASC,
    [TypeNameID] ASC,
    [InsertionID] ASC
)
INCLUDE([ObjectID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_tblPPObject_ObjectID_INC_InsertionID_UpdateID_TypeNameID_SourceInterpreterID_LevelID] ON [dbo].[tblPPObject]
(
    [ObjectID] ASC
)
INCLUDE([InsertionID],[UpdateID],[TypeNameID],[SourceInterpreterID],[LevelID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObject_SearchParentInsertionID_SourceInterpreteID_InsertionID_INC_ObjectID_LevelID_UpdateID] ON [dbo].[tblPPObject]
(
    [SearchParentInsertionID] ASC,
    [SourceInterpreterID] ASC,
    [InsertionID] ASC
)
INCLUDE([ObjectID],[LevelID],[UpdateID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObjectBlobProperty_InsertionID] ON [dbo].[tblPPObjectBlobProperty]
(
    [InsertionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObjectChildObject_ChildInsertionID] ON [dbo].[tblPPObjectChildObject]
(
    [ChildInsertionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObjectChildObjectList_ChildInsertionID] ON [dbo].[tblPPObjectChildObjectList]
(
    [ChildInsertionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObjectProperty_InsertionID] ON [dbo].[tblPPObjectProperty]
(
    [InsertionID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObjectProperty_InsertionID_TypeIndex_INC_SearchText] ON [dbo].[tblPPObjectProperty]
(
    [InsertionID] ASC,
    [TypeIndex] ASC
)
INCLUDE([SearchText]) 
WHERE ([TypeIndex]=(6))
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
ALTER TABLE [dbo].[tblPPObjectProperty] ADD  CONSTRAINT [DF_ObjectProperty_SearcText]  DEFAULT (NULL) FOR [SearchText]
GO
ALTER TABLE [dbo].[tblPPObject]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObject_tblPPTypeName] FOREIGN KEY([TypeNameID])
REFERENCES [dbo].[tblPPTypeName] ([TypeNameID])
GO
ALTER TABLE [dbo].[tblPPObject] CHECK CONSTRAINT [FK_tblPPObject_tblPPTypeName]
GO
ALTER TABLE [dbo].[tblPPObjectBlobProperty]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObjectBlobProperty_tblPPObject] FOREIGN KEY([InsertionID])
REFERENCES [dbo].[tblPPObject] ([InsertionID])
GO
ALTER TABLE [dbo].[tblPPObjectBlobProperty] CHECK CONSTRAINT [FK_tblPPObjectBlobProperty_tblPPObject]
GO
ALTER TABLE [dbo].[tblPPObjectBlobProperty]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObjectBlobProperty_tblPPPropertyMapName] FOREIGN KEY([PropertyMapNameID])
REFERENCES [dbo].[tblPPPropertyMapName] ([PropertyMapNameID])
GO
ALTER TABLE [dbo].[tblPPObjectBlobProperty] CHECK CONSTRAINT [FK_tblPPObjectBlobProperty_tblPPPropertyMapName]
GO
ALTER TABLE [dbo].[tblPPObjectChildObject]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObjectChildObject_tblPPObject] FOREIGN KEY([ChildInsertionID])
REFERENCES [dbo].[tblPPObject] ([InsertionID])
GO
ALTER TABLE [dbo].[tblPPObjectChildObject] CHECK CONSTRAINT [FK_tblPPObjectChildObject_tblPPObject]
GO
ALTER TABLE [dbo].[tblPPObjectChildObject]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObjectChildObject_tblPPPropertyMapName] FOREIGN KEY([PropertyMapNameID])
REFERENCES [dbo].[tblPPPropertyMapName] ([PropertyMapNameID])
GO
ALTER TABLE [dbo].[tblPPObjectChildObject] CHECK CONSTRAINT [FK_tblPPObjectChildObject_tblPPPropertyMapName]
GO
ALTER TABLE [dbo].[tblPPObjectChildObjectList]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObjectChildObjectList_tblPPObject] FOREIGN KEY([ChildInsertionID])
REFERENCES [dbo].[tblPPObject] ([InsertionID])
GO
ALTER TABLE [dbo].[tblPPObjectChildObjectList] CHECK CONSTRAINT [FK_tblPPObjectChildObjectList_tblPPObject]
GO
ALTER TABLE [dbo].[tblPPObjectProperty]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObjectProperty_tblPPObject] FOREIGN KEY([InsertionID])
REFERENCES [dbo].[tblPPObject] ([InsertionID])
GO
ALTER TABLE [dbo].[tblPPObjectProperty] CHECK CONSTRAINT [FK_tblPPObjectProperty_tblPPObject]
GO
ALTER TABLE [dbo].[tblPPObjectProperty]  WITH CHECK ADD  CONSTRAINT [FK_tblPPObjectProperty_tblPPPropertyMapName] FOREIGN KEY([PropertyMapNameID])
REFERENCES [dbo].[tblPPPropertyMapName] ([PropertyMapNameID])
GO
ALTER TABLE [dbo].[tblPPObjectProperty] CHECK CONSTRAINT [FK_tblPPObjectProperty_tblPPPropertyMapName]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObjectChildObject_UpdateID] ON [dbo].[tblPPObjectChildObject]
(
    [UpdateID] ASC
)
INCLUDE([ChildInsertionID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_tblPPObjectChildObjectList_UpdateID] ON [dbo].[tblPPObjectChildObjectList]
(
    [UpdateID] ASC
)
INCLUDE([ChildInsertionID]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 85, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
GO
CREATE procedure [dbo].[spMergePPObject]
(
    @values dbo.udtPPObject readonly
)
as
begin

    begin try

        declare @updatetime datetime
        set @updatetime = GetUTCDate()

        update t
        set t.UpdateTime = @updatetime, t.UpdateId = s.UpdateId, t.TypenameId = s.TypeNameId, t.SourceInterpreterID = s.SourceInterpreterID, t.LevelID = s.LevelID, t.SearchParentInsertionID = s.SearchParentInsertionID           
        from tblPPObject as t
        join @values as s
        on s.InsertionId = t.InsertionID and (s.UpdateID is not null)

        insert into tblPPObject (InsertionId, ObjectId, TypeNameId, UpdateId, UpdateTime, SourceInterpreterID, LevelID, SearchParentInsertionID)  
        select s.InsertionId, s.ObjectId, s.TypeNameId, s.UpdateId, @updatetime, s.SourceInterpreterID, s.LevelID, s.SearchParentInsertionID
        from @values as s
        left join tblPPObject as t
        on s.InsertionID = t.InsertionID
        where t.InsertionID is null

    end try
    begin catch

        declare @errormessage varchar(256)
        select @errormessage = ERROR_MESSAGE()
        raiserror('Error updating entries in the tblPPObject Table. %s', 16, 1, @errormessage)

    end catch

end
GO
CREATE procedure [dbo].[spMergePPObjectBlobProperty]
(
    @values dbo.udtPPObjectBlobProperty readonly
)
as
begin

    begin try

        declare @updatetime datetime
        set @updatetime = GetUTCDate()

        update t
        set t.UpdateTime = @updatetime, t.[Value] = s.BlobValue, t.UpdateId = s.UpdateId
        from tblPPObjectBlobProperty as t
        join @values as s
        on s.InsertionId = t.InsertionID and t.PropertyMapNameId = s.PropertyMapNameID

        insert into tblPPObjectBlobProperty (PropertyMapNameId, Value, UpdateId, UpdateTime, InsertionId) 
        select s.PropertyMapNameId, s.BlobValue, s.UpdateId, @updatetime, s.InsertionId
        from @values as s
        left join tblPPObjectBlobProperty as t
        on s.InsertionID = t.InsertionID and t.PropertyMapNameId = s.PropertyMapNameID
        where t.InsertionID is null and t.PropertyMapNameID is null

    end try
    begin catch

        declare @errormessage varchar(256)
        select @errormessage = ERROR_MESSAGE()
        raiserror('Error updating entries in the tblPPObjectBlobProperty Table. %s', 16, 1, @errormessage)

    end catch

end
GO
create procedure [dbo].[spMergePPObjectChildObject]
(
    @values dbo.udtPPChildObject readonly
)
as
begin

    begin try

        declare @updatetime datetime
        set @updatetime = GetUTCDate()

        update t
        set t.UpdateID = s.UpdateID, t.UpdateTime = @updatetime
        from tblPPObjectChildObject as t
        join @values as s
        on s.InsertionId = t.InsertionID and t.ChildInsertionId = t.ChildInsertionID

        insert into tblPPObjectChildObject (InsertionID, ChildInsertionID, PropertyMapNameID, UpdateID, UpdateTime) 
        select s.InsertionID, s.ChildInsertionID, s.PropertyMapNameID, s.UpdateID, @updatetime
        from @values as s
        left join tblPPObjectChildObject as t
        on s.InsertionId = t.InsertionID and s.ChildInsertionID = t.ChildInsertionID
        where t.ChildInsertionID is null

    end try
    begin catch

        declare @errormessage varchar(256)
        select @errormessage = ERROR_MESSAGE()
        raiserror('Error updating entries in the tblPPObjectChildObject Table. %s', 16, 1, @errormessage)

    end catch

end
GO
create procedure [dbo].[spMergePPObjectChildObjectList]
(
    @values dbo.udtPPChildObjectList readonly
)
as
begin

    begin try

        declare @updatetime datetime
        set @updatetime = GetUTCDate()

        update t
        set t.UpdateID = isnull(s.UpdateID, t.UpdateID), t.UpdateTime = @updatetime, t.RemovalThreshold = isnull(s.RemovalThreshold, t.RemovalThreshold), t.SortIndex = isnull(s.SortIndex, t.SortIndex), t.SortText = isnull(s.SortText, t.SortText)
        from tblPPObjectChildObjectList as t
        join @values as s
        on s.InsertionID = t.InsertionID and s.ChildInsertionId = t.ChildInsertionID

        insert into tblPPObjectChildObjectList (InsertionID, ChildInsertionID, SortIndex, UpdateID, UpdateTime, SortText, RemovalThreshold) 
        select s.InsertionID, s.ChildInsertionID, isnull(s.SortIndex, -1), s.UpdateID, @updatetime, s.SortText, s.RemovalThreshold
        from @values as s
        left join tblPPObjectChildObjectList as t
        on s.InsertionId = t.InsertionID and s.ChildInsertionID = t.ChildInsertionID
        where t.ChildInsertionID is null

    end try
    begin catch

        declare @errormessage varchar(256)
        select @errormessage = ERROR_MESSAGE()
        raiserror('Error updating entries in the tblPPObjectChildObjectList Table. %s', 16, 1, @errormessage)

    end catch

end
GO
CREATE procedure [dbo].[spMergePPObjectProperty]
(
    @values dbo.udtPPObjectProperty readonly
)
as
begin

    begin try

        declare @updatetime datetime
        set @updatetime = GetUTCDate()

        update t 
        set t.UpdateTime = @updatetime, t.BitValue = s.BitValue, t.UIDValue = s.UIDValue, t.FloatValue = s.FloatValue, t.IntValue = s.IntValue, t.NVarCharValue = s.NVarCharValue, t.BigIntValue = s.BigIntValue, t.UpdateId = s.UpdateId, t.TypeIndex = s.TypeIndex, t.SearchText = s.SearchText
        from tblPPObjectProperty as t
        join @values as s
        on s.InsertionId = t.InsertionID and t.PropertyMapNameId = s.PropertyMapNameID

        insert into tblPPObjectProperty (InsertionId, PropertyMapNameId, UpdateID, UpdateTime, BitValue, UIDValue, FloatValue, IntValue, NVarCharValue, BigIntValue, TypeIndex, SearchText)
        select s.InsertionId, s.PropertyMapNameId, s.UpdateId, @updatetime, s.BitValue, s.UidValue, s.floatValue, s.IntValue, s.NVarCharValue, s.BigIntValue, s.TypeIndex, s.SearchText
        from @values as s
        left join tblPPObjectProperty as t
        on s.InsertionID = t.InsertionID and t.PropertyMapNameId = s.PropertyMapNameID
        where t.InsertionID is null and t.PropertyMapNameID is null

    end try
    begin catch

        declare @errormessage varchar(256)
        select @errormessage = ERROR_MESSAGE()
        raiserror('Error updating entries in the tblPPObjectProperty Table. %s', 16, 1, @errormessage)

    end catch

end
GO
create procedure [dbo].[spPurge](@modelinsertionid bigint)
as
begin

    set deadlock_priority low
    set nocount on

    print 'Start Purge'

    -- Work out what can be removed
    begin transaction

    declare @Redundant

Dan*_*man 5

删除执行计划显示带有完整扫描的合并连接,因此所有行都会被触及。罪魁祸首是dbo.spPurge过程中的表变量:

declare @RedundantInsertionIDs table (InsertionID bigint, UpdateTime DateTime)
Run Code Online (Sandbox Code Playgroud)

这缺少帮助优化删除查询的索引。我观察到表变量上的主键改进了计划,以便通过查找而不是扫描来访问目标表,只触及要删除的行而不是活动行。

declare @RedundantInsertionIDs table (InsertionID bigint primary key, UpdateTime DateTime);
Run Code Online (Sandbox Code Playgroud)

如果您仍然遇到问题,使用临时表而不是表变量可能会有所帮助。作为最后的手段,您还可以在清除过程中实施重试。