更新whereselect,保证原子性
Update where select, guarantee atomicity
我有一个像这样的 T-SQL 查询:
UPDATE
[MyTable]
SET
[MyField] = @myValue
WHERE
[Id] =
(
SELECT TOP(1)
[Id]
FROM
[MyTable]
WHERE
[MyField] IS NULL
-- AND other conditions on [MyTable]
ORDER BY
[Id] ASC
)
看来这个查询不是原子的(2个并发执行的select可以return同一个Id两次)
编辑:
如果我执行此查询,由 SELECT 编辑的 Id return 将无法用于下一次执行(因为 [MyField] 将不再为 NULL)。但是,如果我同时执行此查询两次,则两次执行可能 return 相同的 Id(第二次更新将覆盖第一次)。
我读过一个避免这种情况的解决方案是使用 SERIALIZABLE 隔离级别。这是最好/最快/最简单的方法吗?
先计算最大 ID,然后在交叉连接中使用它进行更新。
WITH cte as (
SELECT TOP 1 ID
FROM [MyTable]
WHERE MYFIELD IS NULL
ORDER BY ID
)
UPDATE t
SET [ID] = cte.[ID]
FROM [MyTable] t
CROSS JOIN cte;
输出
这将产生前 1 个值,但如果它相同,您有可能 return 多个值。
尝试使用 DISTINCT
我知道 top(1) 应该只有 return 1 行,但问题表明它 return 不止一行。所以我认为这可能是因为价值相同。所以你可以使用这样的东西
SELECT DISTINCT TOP 1 name FROM [Class];
它是那个或 where 子句来缩小结果
如我所见,UPDLOCK
就足够了(测试代码证实)
我有一个像这样的 T-SQL 查询:
UPDATE
[MyTable]
SET
[MyField] = @myValue
WHERE
[Id] =
(
SELECT TOP(1)
[Id]
FROM
[MyTable]
WHERE
[MyField] IS NULL
-- AND other conditions on [MyTable]
ORDER BY
[Id] ASC
)
看来这个查询不是原子的(2个并发执行的select可以return同一个Id两次)
编辑: 如果我执行此查询,由 SELECT 编辑的 Id return 将无法用于下一次执行(因为 [MyField] 将不再为 NULL)。但是,如果我同时执行此查询两次,则两次执行可能 return 相同的 Id(第二次更新将覆盖第一次)。
我读过一个避免这种情况的解决方案是使用 SERIALIZABLE 隔离级别。这是最好/最快/最简单的方法吗?
先计算最大 ID,然后在交叉连接中使用它进行更新。
WITH cte as (
SELECT TOP 1 ID
FROM [MyTable]
WHERE MYFIELD IS NULL
ORDER BY ID
)
UPDATE t
SET [ID] = cte.[ID]
FROM [MyTable] t
CROSS JOIN cte;
输出
这将产生前 1 个值,但如果它相同,您有可能 return 多个值。
尝试使用 DISTINCT
我知道 top(1) 应该只有 return 1 行,但问题表明它 return 不止一行。所以我认为这可能是因为价值相同。所以你可以使用这样的东西
SELECT DISTINCT TOP 1 name FROM [Class];
它是那个或 where 子句来缩小结果
如我所见,UPDLOCK
就足够了(测试代码证实)