Подсказка табло вызывает взаимоблокировки

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

INSERT INTO Table (TABLOCK) SELECT FROM ...

После того, как задание немного зависает, одна из задач SQL стала жертвой взаимоблокировки. Ниже приведен XML-вывод графика взаимоблокировки.

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

  <resource-list>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process9609dc8" mode="Sch-S"/>
     <owner id="process9609dc8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5e13048" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process5e13048" mode="Sch-S"/>
     <owner id="process5e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9609dc8" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
  </resource-list>

Все становится намного сложнее, потому что я обнаружил, что в большинстве случаев две задачи Execute SQL Tasks могут выполняться параллельно. Попробуйте ниже:

Create table dbo.TablockInsert (c1 int, c2 int, c3 int)

--then issue the script in two Execute Sql Task in parallel you won't fail:
insert into dbo.TablockInsert(TABLOCK) SELECT 1, 1, 1

С той лишь разницей, что инструкция SELECT ... FROM ... выглядит так: инструкция SELECT ... FROM ... может повлиять на режим блокировки здесь?

10 голосов | спросил SqlWhale 5 Maypm17 2017, 22:39:19

1 ответ


8

Руководство по эффективности загрузки данных был написан для SQL Server 2008, но, насколько я могу судить, Microsoft не сделала никаких улучшений в этой области для куч. Вот цитата для сценария загрузки:

  

Массовая загрузка пустой, нераспределенной таблицы

     

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

     

...

     

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

     

В этом случае оба INSERT ... SELECT и SELECT INTO имеют   недостаток. Обе эти операции берут эксклюзивный (X), табличный уровень   заблокировать место назначения. Это означает, что только одна операция объемной загрузки   может работать в заданное время, ограничивая масштабируемость. Однако BCP, BULK   INSERT и Integration Services способны выполнять массовое обновление   (BU) - если вы укажете подсказку TABLOCK.

Важная часть состоит в том, что вы не получаете блокировку BU с помощью INSERT ... SELECT. Вы всегда получите эксклюзивную блокировку для таблицы, поэтому только один INSERT может запускаться одновременно.

В комментариях вы сказали, что будете вставлять строки 100k или меньше, а другие процессы не будут выполняться в таблицах во время вставок. При отправке двух запросов INSERT в базу данных я ожидал бы одного из трех событий:

  1. Одна вставка запускается первой и блокирует другую вставку. Вторая вставка ждет, пока не будет выполнена первая вставка.
  2. Одна вставка заканчивается до начала второй вставки. Нет явной блокировки, но они не запускаются одновременно.
  3. Вы получаете тупик, и только одна вставка завершается успешно.

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

В другом сценарии, в котором вам действительно нужна параллельная вставка, два способа работы с проблемой BU - разбивать вашу кучу и вставлять каждый сеанс в отдельный раздел или загружать ваши данные через BCP, BULK INSERT, или служб интеграции.

ответил Joe Obbish 5 Maypm17 2017, 23:44:48

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132