【发布时间】:2019-04-11 20:13:53
【问题描述】:
我正在尝试编写一些对相当复杂的标准执行 upsert 的 SQL:
BEGIN TRAN;
UPDATE LocationLog WITH(SERIALIZABLE)
SET StartTime = CASE
WHEN StartTime > @StartTime THEN @StartTime
ELSE StartTime
END,
EndTime = CASE
WHEN EndTime < @EndTime THEN @EndTime
ELSE EndTime
END,
Updated = GETUTCDATE()
WHERE Who = @Who
AND (
StartTime BETWEEN @RangeStart and @RangeEnd
or
EndTime BETWEEN @RangeStart and @RangeEnd
)
AND cast(Latitude as decimal(8,5)) = cast(@Latitude as decimal(8, 5))
AND cast(Longitude as decimal(8,5)) = cast(@Longitude as decimal(8, 5))
AND (Accuracy = @Accuracy or COALESCE(Accuracy, @Accuracy) is NULL)
AND (Altitude = @Altitude or COALESCE(Altitude, @Altitude) is NULL)
AND (AltitudeAccuracy = @AltitudeAccuracy or COALESCE(AltitudeAccuracy, @AltitudeAccuracy) is NULL)
AND (Heading = @Heading or COALESCE(Heading, @Heading) is NULL)
AND (Speed = @Speed or COALESCE(Speed, @Speed) is NULL);
IF @@ROWCOUNT = 0
BEGIN
INSERT Position(UUID, Who, StartTime, EndTime, Latitude, Longitude, Accuracy, Altitude, AltitudeAccuracy, Heading, Speed, CreatedTime, Updated)
VALUES (NEWID(), @Who, @StartTime, @EndTime, @Latitude, @Longitude, @Accuracy, @Altitude, @AltitudeAccuracy, @Heading, @Speed, GETUTCDATE(), GETUTCDATE())
END
COMMIT TRAN
我正在使用标准的“更新,如果@@rowcount = 0 插入”与事务和可序列化,这(据我所知)与Sam Saffron's "Insert or Update pattern for Sql Server" Blog post 相同,除了使用单个列 ID ,我正在使用大量候选列,因为无法以编程方式生成单个候选键。
当同时调用它时,我遇到了死锁,我不知道为什么。只是为了帮助完成图片,这是表格定义:
CREATE TABLE LocationLog (
[UUID] [uniqueidentifier] NOT NULL CONSTRAINT [PK_Position] PRIMARY KEY NONCLUSTERED ,
[Who] [uniqueidentifier] NOT NULL INDEX [IX_Who],
[StartTime] [datetime] NOT NULL,
[EndTime] [datetime] NULL,
[Latitude] [decimal](9, 6) NOT NULL,
[Longitude] [decimal](9, 6) NOT NULL,
[Accuracy] [float] NULL,
[Altitude] [float] NULL,
[AltitudeAccuracy] [float] NULL,
[Heading] [float] NULL,
[Speed] [float] NULL,
[CreatedUtc] [datetime] NOT NULL,
[UpdatedUtc] [datetime] NOT NULL
)
这是一个使用上述 sql 会导致很多死锁的脚本:https://dotnetfiddle.net/xkze6l
我希望得到两个答案:
- 解释为什么会出现死锁。 (我已经浏览了代码,但我不明白我做错了什么)。
- 修复了可以让我执行此操作的代码。
【问题讨论】:
-
是否有可能更改为集群 IDENTITIY bigint 主键?有什么方法可以消除 WHERE 子句中的 CAST(),并提供适当的索引来促进该 WHERE 子句?
-
发布死锁图 - 它会告诉您是什么原因造成的。
-
并考虑在dba.stackexchange.com 发帖,因为他们专门研究数据库问题。
-
@pmbAustin 我当然计划非常仔细地编制索引,这可能 a) 包括 CAST 或 b) 将铸件换成索引的
PERSISTED计算列...我知道这里的性能问题,但我想弄清楚的是死锁(可能相关?)。话虽如此,我很肯定主键根本不是问题的一部分,特别是因为我明确将其标记为非集群以避免碎片问题,并且因为这是一个独立的表,没有其他表引用它。 -
@DaleBurrell 谢谢!我会同时做(死锁图,并考虑 dba.stackexchange.com)。
标签: sql-server database-deadlocks