Підказка про блокування запускає тупики


10

Я вставляв два набори даних, використовуючи мінімальний журнал, у порожню таблицю купи за допомогою двох Execute SQL Tasks, що працюють паралельно та з 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 можуть паралельно працювати паралельно. Спробуйте нижче:

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 ... може вплинути на режим блокування тут?


Ви можете вказати TABLOCKX замість TABLOCK, щоб запобігти тупиковій ситуації. Хоча це також би серіалізувало доступ до таблиці, ви все одно отримаєте мінімальний журнал.
Дан Гузман

Відповіді:


8

Дана Завантаження Керівництво по продуктивності було написано для SQL Server 2008 , але, наскільки я можу сказати , Microsoft не зробили якісь - або поліпшень у цій галузі для куп. Ось ціна сценарію завантаження:

Масове завантаження порожньої, нерозділеної таблиці

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

...

Кілька одночасних операцій вставки для купи можливі лише тоді, коли обраний об'ємний метод видає блоки масового оновлення (BU) на столі. Два замки масового оновлення (BU) сумісні, і, отже, дві операції масового оновлення можуть працювати одночасно.

У цьому випадку і INSERT… SELECT, і SELECT INTO мають недолік. Обидві ці операції приймають ексклюзивне (X), блокування рівня таблиці в пункті призначення. Це означає, що за один час може виконуватися лише одна операція насипного навантаження, що обмежує масштабованість. Однак BCP, BULK INSERT та Integration Services здатні приймати блоки масового оновлення (BU) - якщо вказати підказку TABLOCK.

Важлива частина полягає в тому, що ви не отримаєте замок BU INSERT ... SELECT. Ви завжди отримаєте ексклюзивний замок на столі, тому одночасно INSERTможе працювати лише один .

У коментарях ви сказали, що ви будете вставляти 100 к рядків або менше і що інші процеси не будуть працювати над таблицями під час вставок. Надсилаючи два запити INSERT до бази даних, я очікую, що трапиться одна з трьох речей:

  1. Одна вставка працює першою та блокує іншу. Друга вставка чекає, поки буде виконана перша вставка.
  2. Одна вставка закінчується до початку другої вставки. Явного блокування немає, але вони не виконуються одночасно.
  3. Ви отримуєте тупик, і лише одна вставка успішно виконана.

У всіх випадках ви або приносите користь, або не травмуєтесь, додаючи TABLOCKXпідказку до запиту, так що це моя рекомендація працювати над тупиком. Якщо ви хочете знати, чому іноді трапляється тупик, вам потрібно звернутися до іншої відповіді.

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


Дякую за відповідь, але ситуація, з якою я стикався з тупиком, є єдиним випадком, який я маю досі. У більшості випадків, коли ви вводите INSERT INTO (TABLOCK) SELECT FROM паралельно, завдання не вийде з ладу. До речі, я використовую SQL SERVER 2008 R2. Я додав успішний приклад у своєму питанні.
SqlWhale

@tec у випадках, коли він не виходить з ладу, імовірно, вони насправді працюють серійно. Можливо, ви потрапляєте на проблему лише тоді, коли є певний час запуску, наприклад, для складання плану.
Мартін Сміт

@MartinSmith Запит, з яким я стикався з проблемою в проекті, набагато складніший, ніж приклад SELECT 1, який вимагає більшої накладної компіляції, але він просто читає з двох таблиць. Я намагаюся відтворити цей тип тупикової ситуації більш складними запитами.
SqlWhale

@TecKnowNothing Про те, скільки рядків ви вставляєте? Скільки разів на день запускається процес? Чи інші запити ВИБРАТИ з таблиці під час завантаження даних?
Джо Оббіш

@JoeObbish 1. Я не думаю, що # рядків тут не проблема, у нас є лише 4000 - 70000 для кожного запиту, але вони є високо агрегованими даними для використання кубів. 2. Це все ще знаходиться на стадії тестування, і він повинен працювати один раз на день. 3. Ніщо інше не читається з цільової таблиці.
SqlWhale

4

Ви вставляєте dbo.TargetTableз двох сеансів, і обидва використовуєте TABLOCKhint.Both process9609dc8та process5e13048тримання процесів Sch-Sта IXблокування, сумісні між собою, щоб обидва процеси могли відбуватися одночасно. Але обидва хочуть перетворити IXзамок у Exclusive Xтип. Xзамки не сумісні між собою. Тому сервер SQL вибрав один із сеансів як жертву тупикової ситуації, а не чекати нескінченно один для одного.

Основна інформація про тупик.

Таблиця сумісності блокування (Engine Engine Engine).

Виявлення та припинення тупиків.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.