Самоблокировка в SQL Server

Во время процесса установки, запущенного в транзакции, я внезапно получаю следующую ошибку:

Транзакция (идентификатор процесса 61) заблокирована на ресурсах блокировки другим процессом и выбрана в качестве жертвы взаимоблокировки. Повторите транзакцию.

Это странно, так как нет других сеансов, обращающихся к БД. Я также отключил параллелизм на сервере. Это происходит на моей машине-разработчике, на которой работает Sql Server Developer 2017:

Граф взаимоблокировок выглядит так:

<deadlock-list>
 <deadlock victim="process23c22077088">
  <process-list>
   <process id="process23c22077088" taskpriority="0" logused="0" waitresource="METADATA: database_id = 40 SCHEMA(schema_id = 16), lockPartitionId = 0" waittime="3489" ownerId="19528332" transactionname="GetInitializedIMA" lasttranstarted="2019-09-30T18:40:58.847" XDES="0x23b6850fac0" lockMode="Sch-S" schedulerid="12" kpid="17636" status="suspended" spid="53" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2019-09-30T18:40:58.783" lastbatchcompleted="2019-09-30T18:40:58.783" lastattention="2019-09-30T18:36:47.943" clientapp=".Net SqlClient Data Provider" hostname="RND68" hostpid="29660" loginname="S-1-9-3-2459696885-1204846140-3013888703-3157444644" isolationlevel="read committed (2)" xactid="19528330" currentdb="40" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="unknown" line="129" stmtstart="-1" sqlhandle="0x03002800205b3c6bdde23301d8aa000001000000000000000000000000000000000000000000000000000000">
unknown     </frame>
     <frame procname="adhoc" line="1" stmtend="104" sqlhandle="0x01002800f50e5536807d84d63b02000000000000000000000000000000000000000000000000000000000000">
EXEC SoftadminMapQBIntegration.QueryModel_SyncWithMa     </frame>
    </executionStack>
    <inputbuf>
EXEC SoftadminMapQBIntegration.QueryModel_SyncWithMap
EXEC SoftadminMapQB.CacheDatabaseNames

    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <metadatalock subresource="SCHEMA" classid="schema_id = 16" dbid="40" lockPartition="0" id="lock23bb4ee9b00" mode="Sch-M">
    <owner-list>
     <owner id="process23c22077088" mode="Sch-M"/>
     <owner id="process23c22077088" mode="Sch-S" requestType="wait"/>
    </owner-list>
    <waiter-list>
     <waiter id="process23c22077088" mode="Sch-S" requestType="wait"/>
    </waiter-list>
   </metadatalock>
  </resource-list>
 </deadlock>
</deadlock-list>

Ошибка всегда возникает в одном и том же месте. Клиент — это приложение .NET, выполняющее серию пакетов sql с использованием SqlClient.

Я обнаружил ошибку в представлении, созданном во время транзакции. Ошибка возникает, когда ссылка на это представление появляется в более позднем пакете. Я могу изменить представление, чтобы устранить взаимоблокировку, удалив соединение в его определении (обычное соединение на FK равно PK).

Кто-нибудь видел что-то подобное раньше или знает, что происходит?

Полная информация о версии:

Microsoft SQL Server 2017 (RTM-GDR) (KB4505224) - 14.0.2027.2 (X64) Jun 15 2019 00:26:19 
Copyright (C) 2017 Microsoft Corporation
Developer Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 17763:) (Hypervisor)

person Robin Palm    schedule 01.10.2019    source источник
comment
Технически это ошибка, но на практике вы делаете очень неприятные вещи, если создаете представление в транзакции, а затем ссылаетесь на него позже из той же транзакции, но из другого пакета. Неудивительно, что это заставляет двигатель работать безобразно. Представление определено с SCHEMABINDING или без него? В нем указаны все столбцы или где-то используется *? Любая из этих вещей также может повлиять на результаты. Если возможно, отделите операторы DDL от остальных — только некоторые из них являются транзакционными для начала, и даже тогда движок не очень хорошо с ними справляется.   -  person Jeroen Mostert    schedule 01.10.2019
comment
Кто-нибудь видел что-нибудь подобное раньше? Да, я видел нечто подобное, когда системная транзакция выполняется в том же сеансе и блокирует себя от получения блокировки. stackoverflow.com/questions/20155337/   -  person Martin Smith    schedule 01.10.2019
comment
@JeroenMostert Мы не используем SCHEMABINDING, и все столбцы указаны явно. Это обновление существующей базы данных. Ему необходимо выполнить DDL и DML для преобразования данных в новую схему. Это должна быть атомарная операция, следовательно, транзакция. Я думаю, мне не нужно использовать представление для преобразования данных, но это определенно удобнее, и я не понимаю, почему это может вызвать проблему.   -  person Robin Palm    schedule 02.10.2019
comment
Потому что баги. Это не должно вызывать проблемы (один и тот же сеанс удерживает блокировки, поэтому движок должен видеть, что совместимость блокировок не является проблемой), но вызывает. Сценарий, в котором вы создаете объекты в транзакции, а затем используете их, вероятно, не особенно хорошо протестирован, поскольку это не является распространенным случаем (за исключением временных таблиц, но, согласно Мартину, даже в этом, по-видимому, есть свои проблемы).   -  person Jeroen Mostert    schedule 02.10.2019
comment
@JeroenMostert Спасибо! Я предполагаю, что мне придется обойти это и, возможно, подать отчет об ошибке, если мне удастся создать для него автономный случай.   -  person Robin Palm    schedule 02.10.2019


Ответы (2)


Я столкнулся с очень похожей проблемой на моей машине разработки, у меня есть скрипт, который работал хорошо несколько дней назад, и теперь я каждый раз получаю тупик... Как и вы, я нахожусь в транзакции (выполнение приложения .NET script с помощью SQL Client), и никакие другие соединения не устанавливаются. Единственным изменением в моей настройке был перенос моего экземпляра с 2017 на 2019 несколько часов назад. Мне удалось решить проблему, обновив режим совместимости целевой БД с 2017 (140) до 2019 (150) и больше нет взаимоблокировки!

Надеюсь, это поможет.

person DAGUE Benjamin    schedule 09.03.2020

Я столкнулся с точно такой же проблемой. У меня был Table-Value с некоторыми varchar столбцами, например

create type tt_my_type as table
(
  guid                       varchar(250) not null,
  name                       varchar(250)
  primary key (guid)
)

Однако в моем приложении я передавал в name значения, длина которых превышала 250 символов, что приводило к взаимоблокировке. Тупик процесса исчез, когда я увеличил длину varchar после повторной оценки данных.

person Abbas    schedule 17.02.2021