Вы не предоставили достаточной информации о своих запросах, но график взаимоблокировки, которым вы поделились, ясно показывает, что это «писатель-писатель» тупик из-за параллелизма, поскольку все предоставленные или запрошенные блокировки либо X или U .
<resource-list>
<ridlock fileid="1" pageid="2392" dbid="6" objectname="xx" id="lock164096b7800" mode="X" associatedObjectId="72057594051493888">
<owner-list>
<owner id="process163feab3088" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process16409057468" mode="U" requestType="wait"/>
</waiter-list>
</ridlock>
<ridlock fileid="1" pageid="2392" dbid="6" objectname="mytable" id="lock163f7fb2c80" mode="X" associatedObjectId="72057594051493888">
<owner-list>
<owner id="process16409057468" mode="X"/>
</owner-list>
<waiter-list>
<waiter id="process163feab3088" mode="U" requestType="wait"/>
</waiter-list>
</ridlock>
</resource-list>
Одна важная вещь о писатель-писатель взаимоблокировках заключается в том, что SQL Server удерживает эксклюзивные блокировки до фиксации транзакции, в отличие от общих блокировок, которые по умолчанию read committed
уровень изоляции.
Без подробностей запроса не удастся выяснить точную причину ошибки.Как правило, вам необходимо повторно учитывать ваши запросы, чтобы избежать взаимных блокировок, таких как
- Переместить
SELECT
запросов за пределы транзакций, чтобы он возвращал только зафиксированные данные, а не возвращал данные, содержащие изменения, которые могут накатыватьназад. - Иногда вам нужно настроить запрос, чтобы SQL Server не нужно было его распараллеливать так сильно или вообще.
- Добавление
MAXDOP
подсказки к запросу, чтобы заставить его выполнитьСерийно удалит любое изменение тупика параллелизма внутри запроса.
Другая распространенная причина тупика - это когда вы читаете данные с намерением обновить или удалить их позже, просто установив общую блокировку.Оператор UPDATE
не может получить необходимые блокировки обновления, поскольку ресурс уже заблокирован другим процессом, вызывающим взаимоблокировку.
Чтобы устранить эту проблему, вы можете выбрать записи, используя WITH (SERIALIZABLE)
, например,
UPDATE mytable WITH (SERIALIZABLE)
SET UserID = @ToUserID
WHERE UserID = @UserID
Это займет необходимую блокировку обновления для записи и остановит другой процесс для полученияЛюбая блокировка (разделяемая / исключительная) записи и предотвращает любые тупики.
Вам также нужно искать порядок ваших запросов, неправильный порядок может привести к Cycle Deadlock ,В этом случае запрос ожидает завершения другого запроса в других транзакциях.