我有以下过程(SQL Server 2008 R2):
create procedure usp_SaveCompanyUserData
@companyId bigint,
@userId bigint,
@dataTable tt_CoUserdata readonly
as
begin
set nocount, xact_abort on;
merge CompanyUser with (holdlock) as r
using (
select
@companyId as CompanyId,
@userId as UserId,
MyKey,
MyValue
from @dataTable) as newData
on r.CompanyId = newData.CompanyId
and r.UserId = newData.UserId
and r.MyKey = newData.MyKey
when not matched then
insert (CompanyId, UserId, MyKey, MyValue) values
(@companyId, @userId, newData.MyKey, newData.MyValue);
end;
Run Code Online (Sandbox Code Playgroud)
CompanyId、UserId、MyKey 构成目标表的组合键。CompanyId 是父表的外键。此外,还有一个非聚集索引CompanyId asc, UserId asc
。
它是从许多不同的线程调用的,我一直在调用相同语句的不同进程之间出现死锁。我的理解是“with (holdlock)”对于防止插入/更新竞争条件错误是必要的。
我假设两个不同的线程在验证约束时以不同的顺序锁定行(或页面),因此是死锁。
这是一个正确的假设吗? …
我读到,如果我使用 IsolationLevel.ReadUncommitted,则查询不应发出任何锁。但是,当我对此进行测试时,我看到了以下锁定:
Resource_Type:HOBT
Request_Mode:S(共享)
什么是 HOBT 锁?与 HBT(堆或二叉树锁)相关的东西?
为什么我还会得到 S 锁?
在不打开隔离级别快照选项的情况下进行查询时如何避免共享锁定?
我正在 SQLServer 2008 上对此进行测试,并且快照选项设置为关闭。查询仅执行选择。
我可以看到 Sch-S 是必需的,尽管 SQL Server 似乎没有在我的锁定查询中显示它。为什么它仍然发出共享锁?根据:
在该
READ UNCOMMITTED
级别运行的事务不会发出共享锁,以防止其他事务修改当前事务读取的数据。
所以我有点困惑。
在表中Orders
,我存储了我们从所有商店收到的订单。由于一个订单可以有多个行,列中有OrderID
和OrderLineID
在那里OrderID
可以复制,但OrderLineID
必须是一个顺序中是唯一的。
由于订单可以修改,存储过程首先检查收到的订单OrderLineID
是否已经存在于表中,然后决定插入还是更新。为此,我们:
然后是主表:
IF NOT EXISTS (Select 1 from Orders where OrderLineID=@OrderLineID ......)
INSERT INTO Orders () VALUES ()
ELSE UPDATE Orders SET ... WHERE OrderLineID=@OrderLineID
Run Code Online (Sandbox Code Playgroud)
或者该MERGE
功能是否提供更好的性能/控制?
但问题如下:
由于线路问题/服务器繁忙等,Order
消息(或修改)可能会被多次发送,我们不知道按哪个顺序发送。因此,为了避免Order
修改后到达,从而覆盖修改,我们添加了一个时间列:
IF NOT EXISTS (Select 1 from Orders where OrderLineID=@OrderLineID)
INSERT INTO Orders () VALUES ()
ELSE UPDATE Orders SET ... WHERE OrderLineID=@OrderLineID AND LastModified<@CreatedTime
Run Code Online (Sandbox Code Playgroud)
这样,如果后一条消息比前一条消息旧,则对表没有影响。
但是,消息及其修改可能会在很短的时间内发送两次(或更多),以至于后一条消息在保存前一条消息之前到达。因此,对于存储过程的两次执行,它 …
后续问题:
我们如何在并行、多线程环境中删除和重新插入行,同时避免竞争条件、死锁等?我们仍然使用 ( UPDLOCK, SERIALIZABLE
) 或其他锁吗?
我们有两个表:Order
和OrderLineDetail
。表Order
是存储一般信息的父级;和OrderLineDetail
是子表,因为订单有多个明细行项目。
订单可以更新,所以我们首先检查OrderId
表中是否存在,并相应地插入或更新。
由于客户修改、线路问题、服务器繁忙等,订单文件可以多次发送。我们有一个时间Lastfiledatetime
栏。如果传入的时间戳较旧,则对表没有影响。
对于OrderLineDetail
表,有时我们的文件中没有自然键或代理键,因此我们删除所有子OrderLineDetail
项,然后重新填充(这是一个较旧的遗留系统的 xml 文件)。
Create Table Orders
(OrderId bigint primary key, -- this is in xml files
Lastfiledatetime datetime null
)
Create Table OrderLineDetail
(OrderLineDetailid bigint primary key identity(1,1), -- this is Not in the xml files
OrderLineDescription varchar(50),
OrderLineQuantity int,
OrderId bigint foreign key references Orders(OrderId),
Lastfiledatetime datetime
) …
Run Code Online (Sandbox Code Playgroud)