Тупик на одном столе с замком X и U - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть хранимая процедура со следующими двумя транзакциями в разделе Начало и принятие транзакции.

UPDATE  mytable
SET     UserID = @ToUserID
WHERE   UserID = @UserID 

DELETE  FROM mytable
WHERE   UserID = @UserID 

При выполнении этой процедуры хранения с несколькими выполнениями я получаю мертвую блокировку.График тупиковой ситуации:

<deadlock-list>
    <deadlock victim="process16409057468">
        <process-list>
            <process id="process16409057468" taskpriority="0" logused="912" waitresource="RID: 6:1:2392:152" waittime="3022" ownerId="6283339" transactionname="user_transaction" lasttranstarted="2019-02-08T21:08:24.663" XDES="0x16401b98490" lockMode="U" schedulerid="8" kpid="23924" status="suspended" spid="92" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-02-08T21:08:24.667" lastbatchcompleted="2019-02-08T21:08:24.667" lastattention="1900-01-01T00:00:00.667" clientapp=".Net SqlClient Data Provider" hostname="GYAAN" hostpid="5624" loginname="sa" isolationlevel="read uncommitted (1)" xactid="6283339" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
                <executionStack>
                    <frame procname="mytable" line="377" stmtstart="33320" stmtend="33540" sqlhandle="0x030006004f6bf63211085201eaa9000001000000000000000000000000000000000000000000000000000000">
                        UPDATE  mytable
                        SET     UserID = @ToUserID
                        WHERE   UserID = @UserID      
                    </frame>
                </executionStack>
                <inputbuf>
                    Proc [Database Id = 6 Object Id = 855010127]    
                </inputbuf>
            </process>
            <process id="process163feab3088" taskpriority="0" logused="912" waitresource="RID: 6:1:2392:149" waittime="99" ownerId="6282851" transactionname="user_transaction" lasttranstarted="2019-02-08T21:08:22.107" XDES="0x16401b20490" lockMode="U" schedulerid="3" kpid="33220" status="suspended" spid="81" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2019-02-08T21:08:22.103" lastbatchcompleted="2019-02-08T21:08:22.107" lastattention="1900-01-01T00:00:00.107" clientapp=".Net SqlClient Data Provider" hostname="GYAAN" hostpid="5624" loginname="sa" isolationlevel="read uncommitted (1)" xactid="6282851" currentdb="6" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
                <executionStack>
                    <frame procname="mytable" line="382" stmtstart="33650" stmtend="33848" sqlhandle="0x030006004f6bf63211085201eaa9000001000000000000000000000000000000000000000000000000000000">
                        DELETE  FROM mytable
                        WHERE   UserID = @UserID     
                    </frame>
                </executionStack>
                <inputbuf>
                    Proc [Database Id = 6 Object Id = 855010127]    
                </inputbuf>
            </process>
        </process-list>

        <resource-list>
            <ridlock fileid="1" pageid="2392" dbid="6" objectname="mytable" 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>
    </deadlock>
</deadlock-list>

Может ли кто-нибудь объяснить, как и что могло послужить причиной тупиковой блокировки?

В настоящий момент у меня возникают трудности с пониманием этого потока блокировок X и U.

Можете ли вы объяснить, что могло произойти, если X и U застряли между мертвой блокировкой?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

За исключением того факта, что вы, например, обновляете и затем удаляете ту же запись, что выглядит неправильно, вы можете получить все необходимые блокировки до того, как выполнить DDL.

select UserID
FROM mytable   with(xlock, holdlock, rowlock)
WHERE UserID  in (@ToUserID, @UserID)

UPDATE  mytable
SET     UserID = @ToUserID
WHERE   UserID = @UserID 

DELETE  FROM mytable
WHERE   UserID = @UserID 
0 голосов
/ 11 февраля 2019

Вы не предоставили достаточной информации о своих запросах, но график взаимоблокировки, которым вы поделились, ясно показывает, что это «писатель-писатель» тупик из-за параллелизма, поскольку все предоставленные или запрошенные блокировки либо 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 уровень изоляции.

Без подробностей запроса не удастся выяснить точную причину ошибки.Как правило, вам необходимо повторно учитывать ваши запросы, чтобы избежать взаимных блокировок, таких как

  1. Переместить SELECT запросов за пределы транзакций, чтобы он возвращал только зафиксированные данные, а не возвращал данные, содержащие изменения, которые могут накатыватьназад.
  2. Иногда вам нужно настроить запрос, чтобы SQL Server не нужно было его распараллеливать так сильно или вообще.
  3. Добавление MAXDOP подсказки к запросу, чтобы заставить его выполнитьСерийно удалит любое изменение тупика параллелизма внутри запроса.

Другая распространенная причина тупика - это когда вы читаете данные с намерением обновить или удалить их позже, просто установив общую блокировку.Оператор UPDATE не может получить необходимые блокировки обновления, поскольку ресурс уже заблокирован другим процессом, вызывающим взаимоблокировку.

Чтобы устранить эту проблему, вы можете выбрать записи, используя WITH (SERIALIZABLE), например,

UPDATE  mytable WITH (SERIALIZABLE)
SET     UserID = @ToUserID
WHERE   UserID = @UserID

Это займет необходимую блокировку обновления для записи и остановит другой процесс для полученияЛюбая блокировка (разделяемая / исключительная) записи и предотвращает любые тупики.

Вам также нужно искать порядок ваших запросов, неправильный порядок может привести к Cycle Deadlock ,В этом случае запрос ожидает завершения другого запроса в других транзакциях.

...