添加索引后即使死锁

时间:2013-12-05 15:58:42

标签: sql-server

我有一个存储过程,其中包含以下语句

INSERT INTO dbo.[ResultItems] (PGM,GRP,PGMGRPSEQ,ITMID,ITMDESC,BRAND,PackSize,IsSelected,UserId)
    SELECT  SRIS.PGM,SRIS.GRP,SRIS.PGMGRPSEQ,SRIS.ITMID,SRIS.ITMDESC,SRIS.BRAND,SRIS.PackSize,SRIS.IsSelected,SRIS.UserId
    FROM @ItemResult SRIS
    LEFT OUTER JOIN [dbo].[ResultItems] SRI (NOLOCK)
        ON SRI.ITMID = SRIS.ITMID
        AND SRI.PGM = SRIS.PGM
        AND SRI.GRP = SRIS.GRP
        AND SRI.PGMGRPSEQ = SRIS.PGMGRPSEQ
        AND SRI.UserId=SRIS.UserId 
    WHERE SRI.ITMID IS NULL  ----logic to avoid duplicate
    GROUP BY SRIS.PGM,SRIS.GRP,SRIS.PGMGRPSEQ,SRIS.ITMID,SRIS.ITMDESC,SRIS.BRAND,SRIS.PackSize,SRIS.IsSelected,SRIS.UserId


UPDATE SRI
SET SRI.IsSelected = 1
FROM @ItemResult IST 
INNER JOIN [dbo].ResultItems SRI (NOLOCK)
ON SRI.PGM = IST.[PGM]
    AND SRI.GRP = IST.GRP
    AND SRI.PGMGRPSEQ = IST.PGMGRPSEQ
    AND SRI.ITMID = IST.ITMID
    AND SRI.UserId=IST.UserId
WHERE SRI.UserId=@UserId

我在ResultItems表上有index

IF NOT EXISTS(select 1 from sys.sysindexes where name = 'IX_RESULTITEMS_USERID')
BEGIN
    CREATE NONCLUSTERED INDEX IX_RESULTITEMS_USERID
    ON [dbo].[ResultItems] ([UserId])
END
GO

五个并发用户正在调用此SP。 update语句在UserId上有一个过滤条件。每个用户将仅使用自己的用户ID执行sp。这就是我在UserId列上创建索引的原因。

期望是索引将有助于避免表扫描,并且不会出现死锁(因为每个用户都在寻找自己的记录)......但是十分之一的测试导致死锁。

我认为这是因为当存在大量数据时(每个用户超过20000条记录)升级到table scan

这里避免死锁的最佳方法是什么?

TABLE和INDEXES

CREATE TABLE [dbo].[ResultItems](
    [SRIID] [int] IDENTITY(1,1) NOT NULL,
    [PGM] [nvarchar](50) NULL,
    [GRP] [nvarchar](50) NULL,
    [PGMGRPSEQ] [nvarchar](50) NULL,
    [ITMID] [nvarchar](18) NULL,
    [ITMDESC] [nvarchar](255) NULL,
    [BRAND] [nchar](40) NULL,
    [PackSize] [nvarchar](max) NULL,
    [IsSelected] [bit] NULL,
    [UserId] [nvarchar](50) NULL,
 CONSTRAINT [PK_SEARCH_RESULT_ITEMS] PRIMARY KEY CLUSTERED 
(
    [SRIID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

CREATE NONCLUSTERED INDEX [IX_PGM_GRP_PGMGRPSEQ_ITMID_UserId] ON [dbo].[ResultItems]
(
    [PGM] ASC,
    [GRP] ASC,
    [PGMGRPSEQ] ASC,
    [ITMID] ASC,
    [UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_RESULTITEMS_USERID] ON [dbo].[ResultItems]
(
    [UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

参考

  1. Avoiding Deadlock Transaction Errors by Using ROWLOCK Hint in T-SQL
  2. INF: Analyzing and Avoiding Deadlocks in SQL Server
  3. Tips to avoid deadlocks?

2 个答案:

答案 0 :(得分:1)

使用MERGE而不是INSERT然后更新。另外,摆脱NOLOCK

MERGE INTO dbo.[ResultItems] SRI
USING @ItemResult SRIS ON (
      SRI.ITMID = SRIS.ITMID
  AND SRI.PGM = SRIS.PGM
  AND SRI.GRP = SRIS.GRP
  AND SRI.PGMGRPSEQ = SRIS.PGMGRPSEQ
  AND SRI.UserId=SRIS.UserId 
)
WHEN MATCHED THEN UPDATE
  SET SRI.IsSelected = 1
WHEN NOT MATCHED THEN
  INSERT (     PGM,     GRP,     PGMGRPSEQ,     ITMID,     ITMDESC,     BRAND,     PackSize,     IsSelected,     UserId)
  VALUES (SRIS.PGM,SRIS.GRP,SRIS.PGMGRPSEQ,SRIS.ITMID,SRIS.ITMDESC,SRIS.BRAND,SRIS.PackSize,SRIS.IsSelected,SRIS.UserId);

答案 1 :(得分:1)

相关问题