Проблема тупика SQL Server 2005 - PullRequest
0 голосов
/ 18 сентября 2009

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

Не могли бы вы сообщить мне, почему у меня возникает проблема тупика, когда вызывается этот процесс?

CREATE PROCEDURE [dbo].[sp_LoadEventsTemp]
(
   @RequestKey varchar(20),
   @RequestType varchar(20),
   @Status varchar(20),
   @ScheduledDate smalldatetime = null
)
AS
BEGIN
   declare @LoadEvents table
   (
      id int
   )

   BEGIN TRANSACTION

   if (@scheduledDate is null)
   Begin
      insert into @LoadEvents (id)
      (
         Select eventqueueid FROM eventqueue
         WITH (HOLDLOCK, ROWLOCK)
         WHERE requestkey = @RequestKey
         and requesttype = @RequestType
         and [status] = @Status
      )
   END
   else
   BEGIN
      insert into @LoadEvents (id)
      (
         Select eventqueueid FROM eventqueue
         WITH (HOLDLOCK, ROWLOCK)
         WHERE requestkey = @RequestKey
         and requesttype = @RequestType
         and [status] = @Status
         and (convert(smalldatetime,scheduleddate) <= @ScheduledDate)
      )
   END

   update eventqueue set [status] = 'InProgress'
   where eventqueueid in (select id from @LoadEvents)

   IF @@Error 0
   BEGIN
      ROLLBACK TRANSACTION
   END
   ELSE
   BEGIN
      COMMIT TRANSACTION
      select * from eventqueue
      where eventqueueid in (select id from @LoadEvents)
   END
END

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 18 сентября 2009

Прежде всего, поскольку вы работаете с SQL Server, я бы порекомендовал вам ввести Performance Dashboard, который является очень удобным инструментом для определения того, какие блокировки в настоящее время устанавливаются на сервере.

Производительность Dahsboard Link

Во-вторых, проследите, как ваш SQL-сервер использует SQL Profiler (уже установлен), и убедитесь, что вы выбрали в Выбор событий пункт Блокировки> График взаимоблокировки, который покажет, что является причиной тупика.

Вы должны четко понимать, что такое тупик, чтобы начать устранение неполадок. При любом доступе к любой таблице или строке в БД выполняется блокировка.

Позволяет вызывать SPID 51 и SPID 52 (SPID = идентификатор процесса SQL)

SPID 51 блокирует ячейку A

SPID 52 замки Cell B

если в той же транзакции SPID 51 запрашивает ячейку B, он будет ждать SPID 52, пока не освободит его.

если в той же транзакции SPID 52 запрашивает ячейку A, вы попадаете в тупик, потому что эта ситуация никогда не закончится (51 ожидает 52 и 52 - 51)

Должен сказать вам, что не легко устранить неполадки, но вам нужно копать глубже, чтобы найти разрешение

1 голос
/ 18 сентября 2009

Есть ли у вас некластеризованный индекс, определенный как:

CREATE NONCLUSTERED INDEX NC_eventqueue_requestkey_requesttype_status
    ON eventqueue(requestkey, requesttype, status)
         INCLUDE eventqueueid

и еще один на eventqueueid?

Кстати, преобразование типа столбца scheduleddate в smalldatetime не позволит использовать индекс для этого столбца.

0 голосов
/ 18 сентября 2009

В большинстве случаев взаимные блокировки возникают (по моему опыту), когда разные ресурсы заблокированы в разных транзакциях в разных заказах.

Представьте себе 2 процесса, использующих ресурсы A и B, но блокирующих их в разных порядках.
- Процесс 1 блокирует ресурс A, затем ресурс B
- Процесс 2 блокирует ресурс B, затем ресурс A

Тогда становится возможным следующее:
- Процесс 1 блокирует ресурс A
- Процесс 2 блокирует ресурс B
- Процесс 1 пытается заблокировать ресурс B, затем останавливается и ждет, так как процесс 2 имеет его
- Процесс 2 пытается заблокировать ресурс A, затем останавливается и ждет, пока процесс 1 его получит
- Оба процесса ждут друг друга, тупик

В вашем случае нам нужно было бы точно определить, где падает SP из-за тупика (обновление, я думаю,?) И любых других процессов, которые ссылаются на эту таблицу. Это может быть триггер или что-то такое, что затем блокируется на другой таблице, а не на таблице, которую вы обновляете.


Я бы использовал синтаксис OUTPUT для SQL Server 2005 , чтобы избежать необходимости использовать транзакцию ...

UPDATE
  eventqueue
SET
  status = 'InProgress'
WHERE
      requestkey  = @RequestKey
  AND requesttype = @RequestType
  AND status      = @Status
  AND (convert(smalldatetime,scheduleddate) <= @ScheduledDate OR @ScheduledDate  IS NULL)
OUTPUT
  inserted.*
...