2013-12-05 2 views
2

У меня есть хранимая процедура со следующими заявлениями в немМертвого замка даже после добавления индекса

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 [email protected] 

Я следующий index на столе ResultItems

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. Каждый пользователь будет выполнять sp только с собственным идентификатором пользователя. Вот почему я создал индекс в столбце UserId.

Ожидание было индексом, чтобы избежать сканирования таблицы, и не будет мертвой блокировки (поскольку каждый пользователь ищет свои собственные записи) ... Но 1 из 10 тестов вызывает мертвую блокировку.

Я считаю, что это связано с тем, что эскалация до table scan при наличии огромных данных (более 20000 записей каждым пользователем).

Каков наилучший способ избежать взаимоблокировки здесь?

ТАБЛИЦА и индексирует

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?
+0

Каков уровень изоляции? По умолчанию? Рассматривали ли вы добавление индекса, который фактически разрешает поиск (например, тот, который охватывает все столбцы в предложении JOIN)? Вы также можете добавить дополнительный фильтр 'AND SRI.IsSelected <> 1', потому что нет оснований сопоставлять строки, которые уже были обновлены. –

+0

Вы можете показать CREATE TABLE, включая все индексы? –

+0

@AaronBertrand Добавил данные таблицы/индекса – Lijo

ответ

1

Я решил проблему, перезаписав логику хранимой процедуры, чтобы избежать обновления инструкции. Обновление происходит на temporary table перед вставкой.

Другие мысли используются для анализа и использования MERGE для запроса.

ДРУГИЕ ЛИТЕРАТУРА

  1. Слияние Пример (Solutions for INSERT OR UPDATE on SQL Server)
  2. https://dba.stackexchange.com/questions/23467/sql-server-2008-merge-statement-deadlocking-itself
  3. sql server deadlock case
  4. Locking with MERGE statement compared to Update/Insert in SQL Server 2005
  5. Stress-Test those Stored Procedures using C# and Nunit

MERGE ОШИБКИ

  1. Aaron Bertrand - Use Caution with SQL Server's MERGE Statement
  2. http://sqlblog.com/blogs/paul_white/archive/2013/02/06/incorrect-results-with-indexed-views.aspx
  3. http://www.sqlperformance.com/2013/02/t-sql-queries/another-merge-bug
1

Вместо INSERT, затем UPDATE, используйте MERGE. Кроме того, избавиться от 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); 
Смежные вопросы