事务隔离 - INSERTS 依赖于以前的记录值
Transaction isolation - INSERTS dependant on previous records values
这个问题 related/came 来自对另一件事的讨论:
想象一下我们有通常的 Orders_Headers 和 Orders_LineItems 表的场景。还可以说我们有一个特殊的业务规则:
每个订单都有折扣字段,该字段是根据上次输入订单后经过的时间计算的
如果最近Y小时内有超过X个订单,则每个下一个订单折扣字段都是专门计算的。
如果最近10个订单的平均频率高于每分钟x次,则专门计算每个下一个订单折扣字段。
每个下订单折扣字段都是专门计算的
这里的重点是表明每个订单都依赖于以前的订单,隔离级别至关重要。
我们有一笔交易(只是显示代码的逻辑):
BEGIN TRANSACTION
INSERT INTO Order_Headers...
SET @Id = SCOPE_IDENTITY()
INSERT INTO Order_LineItems...(using @Id)
DECLARE @SomeVar INT
--just example to show selecting previous x orders
--needed to calculate Discount value for new Order
SELECT @SomeVar = COUNT(*) Order_Headers
WHERE ArbitraryCriteria
UPDATE Order_Headers
SET Discount= UDF(@SomeVar)
WHERE Id = @Id
COMMIT
END TRANSACTION
我们还有一个读取订单的事务:
SELECT TOP 10 * FROM Order_Headers
ORDER BY Id DESC
问题
第一个事务是 SNAPSHOT 隔离级别,第二个适当级别是 READ COMMITED 吗?
是否有更好的方法来处理 CREATE/UPDATE 交易,或者是这样做的方法吗?
快照的问题不在于 inserting/reading(我假设您决定使用它)。关于更新,你应该关心。
快照隔离级别正在使用行版本控制。这意味着任何时候你 insert/update/delete 行,这些行都会在 tempdb 中复制(版本存储,这些行的位置),并使用版本控制标签将其大小增加 14 个字节,以便你新启动的事务可以读取来自最后提交的事务的行。请记住,这些调整大小的行将保持原样,直到您重建索引。
这应该是一个指标,如果您的 table 真的很忙,您的索引将更快地进行碎片整理,并且会给您的 temp.So 增加一定的 % 开销,请记住这一点.
正如我提到的,这里更令人担忧的是更新。
任何时候你 insert/delete/update 行,你都会在这些行上获得独占锁(稍后对象),并且由于你的快照正在使用行版本控制,来自另一个事务的插入会在新行上添加独占锁,这不是 problem.However 如果您尝试更新现有行并且会话 2 尝试获取该行的 X 锁,它将失败,因为会话 1 已经在其上具有 X 锁,这就是您将获得的地方此消息:
Read Committed 和 Serializable 很好地解决了这些问题,因此您可能想采用这种方法并在实际实施之前测试所有解决方案。请记住,所有事务都会导致更新阻塞,并且 snapshot/read 提交的快照只会失败。
我个人会使用读取提交的快照和更改的过程,在 catch 块中重新运行 N 次,但是嘿,这也有缺陷!
serializable
选项:
通过 updlock
和 serializable
table 提示使用悲观锁定策略来获取由 where
标准指定的键范围锁(由支持索引只锁定查询需要的范围):
declare @Id int, @SomeVar int;
begin tran;
select @SomeVar = count(OrderDate)
from Order_Headers with (updlock,serializable)
where OrderDate >= '20170101';
insert into Order_Headers (OrderDate, SomeVar)
select sysdatetime(), @SomeVar;
set @Id = scope_identity();
insert into Order_LineItems (id,cols)
select @Id, cols
from @TableValuedParameter;
commit tran;
关于使用 updlock
和 serializable
table 提示锁定键范围的原因和方法的很好指南 select
,以及为什么需要两者都包含在 Sam Saffron''s upsert (update/insert) patterns.
中
参考:
这个问题 related/came 来自对另一件事的讨论:
想象一下我们有通常的 Orders_Headers 和 Orders_LineItems 表的场景。还可以说我们有一个特殊的业务规则:
每个订单都有折扣字段,该字段是根据上次输入订单后经过的时间计算的
如果最近Y小时内有超过X个订单,则每个下一个订单折扣字段都是专门计算的。
如果最近10个订单的平均频率高于每分钟x次,则专门计算每个下一个订单折扣字段。
每个下订单折扣字段都是专门计算的
这里的重点是表明每个订单都依赖于以前的订单,隔离级别至关重要。
我们有一笔交易(只是显示代码的逻辑):
BEGIN TRANSACTION
INSERT INTO Order_Headers...
SET @Id = SCOPE_IDENTITY()
INSERT INTO Order_LineItems...(using @Id)
DECLARE @SomeVar INT
--just example to show selecting previous x orders
--needed to calculate Discount value for new Order
SELECT @SomeVar = COUNT(*) Order_Headers
WHERE ArbitraryCriteria
UPDATE Order_Headers
SET Discount= UDF(@SomeVar)
WHERE Id = @Id
COMMIT
END TRANSACTION
我们还有一个读取订单的事务:
SELECT TOP 10 * FROM Order_Headers
ORDER BY Id DESC
问题
第一个事务是 SNAPSHOT 隔离级别,第二个适当级别是 READ COMMITED 吗?
是否有更好的方法来处理 CREATE/UPDATE 交易,或者是这样做的方法吗?
快照的问题不在于 inserting/reading(我假设您决定使用它)。关于更新,你应该关心。
快照隔离级别正在使用行版本控制。这意味着任何时候你 insert/update/delete 行,这些行都会在 tempdb 中复制(版本存储,这些行的位置),并使用版本控制标签将其大小增加 14 个字节,以便你新启动的事务可以读取来自最后提交的事务的行。请记住,这些调整大小的行将保持原样,直到您重建索引。
这应该是一个指标,如果您的 table 真的很忙,您的索引将更快地进行碎片整理,并且会给您的 temp.So 增加一定的 % 开销,请记住这一点.
正如我提到的,这里更令人担忧的是更新。
任何时候你 insert/delete/update 行,你都会在这些行上获得独占锁(稍后对象),并且由于你的快照正在使用行版本控制,来自另一个事务的插入会在新行上添加独占锁,这不是 problem.However 如果您尝试更新现有行并且会话 2 尝试获取该行的 X 锁,它将失败,因为会话 1 已经在其上具有 X 锁,这就是您将获得的地方此消息:
Read Committed 和 Serializable 很好地解决了这些问题,因此您可能想采用这种方法并在实际实施之前测试所有解决方案。请记住,所有事务都会导致更新阻塞,并且 snapshot/read 提交的快照只会失败。
我个人会使用读取提交的快照和更改的过程,在 catch 块中重新运行 N 次,但是嘿,这也有缺陷!
serializable
选项:
通过 updlock
和 serializable
table 提示使用悲观锁定策略来获取由 where
标准指定的键范围锁(由支持索引只锁定查询需要的范围):
declare @Id int, @SomeVar int;
begin tran;
select @SomeVar = count(OrderDate)
from Order_Headers with (updlock,serializable)
where OrderDate >= '20170101';
insert into Order_Headers (OrderDate, SomeVar)
select sysdatetime(), @SomeVar;
set @Id = scope_identity();
insert into Order_LineItems (id,cols)
select @Id, cols
from @TableValuedParameter;
commit tran;
关于使用 updlock
和 serializable
table 提示锁定键范围的原因和方法的很好指南 select
,以及为什么需要两者都包含在 Sam Saffron''s upsert (update/insert) patterns.
参考: