Faj*_*iya 5 sql-server hints upsert design-pattern
DECLARE @key INTEGER = 33, @val INTEGER = 44;
BEGIN TRANSACTION;
INSERT dbo.t([key], val)
SELECT @key, @val
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.t WITH (UPDLOCK, SERIALIZABLE)
WHERE [key] = @key
);
IF @@ROWCOUNT = 0
BEGIN
UPDATE dbo.t SET val = @val WHERE [key] = @key;
END
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)
DECLARE @key INTEGER = 33, @val INTEGER = 44;
BEGIN TRANSACTION;
INSERT dbo.t WITH (UPDLOCK, SERIALIZABLE) ([key], val)
SELECT @key, @val
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.t
WHERE [key] = @key
);
IF @@ROWCOUNT = 0
BEGIN
UPDATE dbo.t SET val = @val WHERE [key] = @key;
END
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)
DECLARE @key INTEGER = 33, @val INTEGER = 44;
BEGIN TRANSACTION;
INSERT dbo.t WITH (UPDLOCK, SERIALIZABLE) ([key], val)
SELECT @key, @val
WHERE NOT EXISTS
(
SELECT 1 FROM dbo.t WITH (UPDLOCK, SERIALIZABLE)
WHERE [key] = @key
);
IF @@ROWCOUNT = 0
BEGIN
UPDATE dbo.t SET val = @val WHERE [key] = @key;
END
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)
我对提示的位置感到困惑。如果部分和子查询中的表INSERT
相同,那么在哪里编写提示还有区别吗?
这些提示仅适用于它们所在的位置。源表和目标表相同并不重要。
需要这些提示来NOT EXISTS
确保 (a) 该行保持锁定足够长的时间;(b) 如果测试范围内不存在行,则在事务持续时间内继续出现这种情况。在存在测试中暗示读取是实现这些目标的最可靠方法。
版本 1 是正确的“upsert”模式之一,用于预计插入会更常见的情况。
版本 2 缺乏有关表读取的必要提示,以便在并发情况下正确工作,同时最大限度地减少死锁。NOT EXISTS
在插入发生之前,另一个会话有一小段机会在该范围内插入一行。
版本 3 不必要地重复插入目标上的提示,但它在其他方面是无害的。
请参阅Michael Swart 撰写的SQL Server UPSERT 模式和反模式。
归档时间: |
|
查看次数: |
288 次 |
最近记录: |