相关疑难解决方法(0)

MERGE 死锁预防

在我们的一个数据库中,我们有一个由多个线程密集并发访问的表。线程确实通过MERGE. 还有一些线程偶尔会删除行,因此表数据非常不稳定。执行 upsert 的线程有时会陷入死锁。该问题看起来与问题中描述的问题相似。不过,不同之处在于,在我们的例子中,每个线程都只更新或插入一行

简化设置如下。该表是堆,上面有两个唯一的非聚集索引

CREATE TABLE [Cache]
(
    [UID] uniqueidentifier NOT NULL CONSTRAINT DF_Cache_UID DEFAULT (newid()),
    [ItemKey] varchar(200) NOT NULL,
    [FileName] nvarchar(255) NOT NULL,
    [Expires] datetime2(2) NOT NULL,
    CONSTRAINT [PK_Cache] PRIMARY KEY NONCLUSTERED ([UID])
)
GO
CREATE UNIQUE INDEX IX_Cache ON [Cache] ([ItemKey]);
GO
Run Code Online (Sandbox Code Playgroud)

典型的查询是

DECLARE
    @itemKey varchar(200) = 'Item_0F3C43A6A6A14255B2EA977EA730EDF2',
    @fileName nvarchar(255) = 'File_0F3C43A6A6A14255B2EA977EA730EDF2.dat';

MERGE INTO [Cache] WITH (HOLDLOCK) T
USING (
    VALUES (@itemKey, @fileName, dateadd(minute, 10, sysdatetime()))
) S(ItemKey, FileName, Expires)
ON …
Run Code Online (Sandbox Code Playgroud)

sql-server deadlock execution-plan merge

15
推荐指数
1
解决办法
7463
查看次数

在 SQL Server 中实现应用程序锁(分布式锁定模式)

在我的应用程序中,我必须执行分布式锁定模式。因为我们已经有一个 SQL Server 实例可以使用,所以我们决定在我们的 Web 应用程序的 SQL 层实现锁定是最容易的。

可以根据多种条件获得锁,包括:

  • 请求的锁类型
  • 任意应用程序标识符

出于所有意图和目的,将上述两个条件视为int数据类型。

在这种模式中,我们希望将我们所有的锁都视为 FIFO,我相信SERIALIZABLE隔离级别会给我们带来这种好处。

以下是我们建议如何执行“锁定”:

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

IF EXISTS (SELECT 1 FROM locks WHERE LockType = @LockType AND ApplicationIdentifier = @ApplicationIdentifier)
    BEGIN
        -- Awesome, the lock will be acquired
        INSERT INTO locks OUTPUT INSERTED.LockId VALUES (2,3)
    END
ELSE
    BEGIN
        -- Someone already has the lock
        SELECT -1
    END

SET TRANSACTION ISOLATION LEVEL READ COMITTED
Run Code Online (Sandbox Code Playgroud)

和“解锁”:

DELETE FROM locks WHERE LockId = @LockId
Run Code Online (Sandbox Code Playgroud)

所以我的问题有两个方面: …

sql-server locking isolation-level

7
推荐指数
1
解决办法
7352
查看次数

SQL Server 2014 并发输入问题

在表中Orders,我存储了我们从所有商店收到的订单。由于一个订单可以有多个行,列中有OrderIDOrderLineID 在那里OrderID可以复制,但OrderLineID必须是一个顺序中是唯一的。

由于订单可以修改,存储过程首先检查收到的订单OrderLineID是否已经存在于表中,然后决定插入还是更新。为此,我们:

  • 从 XML 输入动态构建插入和更新语句
  • 插入客户表
  • 插入到 shippingAddresses 表中

然后是主表:

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)

这样,如果后一条消息比前一条消息旧,则对表没有影响。

但是,消息及其修改可能会在很短的时间内发送两次(或更多),以至于后一条消息在保存前一条消息之前到达。因此,对于存储过程的两次执行,它 …

sql-server concurrency unique-constraint

5
推荐指数
1
解决办法
1191
查看次数