Podpowiedź Tablock wyzwala zakleszczenia

10

Wstawiałem dwa zestawy danych, używając minimalnego rejestrowania, do pustej tabeli sterty, używając dwóch zadań wykonywania SQL równolegle i za pomocą SQL o następującej formie.

INSERT INTO Table (TABLOCK) SELECT FROM ...

Po tym, jak zadanie trochę się zawiesiło, jedno z zadań SQL stało się ofiarą impasu. Poniżej znajduje się wyjście XML wykresu zakleszczenia.

Czy ktoś może wyjaśnić, co działo się pod maską?

  <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>

Sprawy stają się o wiele trudniejsze, ponieważ stwierdziłem, że w większości przypadków dwa zadania wykonywania SQL mogą działać równolegle z powodzeniem. Spróbuj poniżej:

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

Ponieważ jedyną różnicą jest instrukcja SELECT ... FROM ..., wygląda na to, że instrukcja SELECT ... FROM ... może mieć tutaj wpływ na tryb blokady?

SqlWhale
źródło
Możesz podać TABLOCKX zamiast TABLOCK, aby zapobiec zakleszczeniu. Chociaż spowodowałoby to również szeregowanie dostępu do tabeli, nadal można uzyskać minimalne rejestrowanie.
Dan Guzman

Odpowiedzi:

8

Danych Ładowanie Wydajność przewodnik został napisany dla SQL Server 2008, ale o ile mogę powiedzieć Microsoft nie dokonał żadnych ulepszeń w tej dziedzinie na stosach. Oto oferta Twojego scenariusza ładowania:

Zbiorcze ładowanie pustej, niepartycjonowanej tabeli

Ładowanie danych do niepodzielonej na partycje tabeli, podczas gdy prosta operacja, może być zoptymalizowana na kilka sposobów.

...

Wiele współbieżnych operacji wstawiania stosów jest możliwe tylko wtedy, gdy wybrana metoda zbiorcza wystawia blokady tabeli zbiorczej aktualizacji (BU). Dwie blokady aktualizacji zbiorczej (BU) są kompatybilne, dlatego dwie operacje zbiorcze mogą być uruchomione jednocześnie.

W tym scenariuszu zarówno WSTAW… WYBIERZ, jak i WYBIERZ WT mają wadę. Obie te operacje przyjmują blokadę na poziomie wyłączności (X) na miejscu docelowym. Oznacza to, że w danym momencie może działać tylko jedna operacja ładowania luzem, co ogranicza skalowalność. Jednak BCP, BULK INSERT i Integration Services są w stanie przyjmować blokady aktualizacji zbiorczej (BU) - jeśli podasz wskazówkę TABLOCK.

Ważne jest to, że nie dostajesz blokady BU INSERT ... SELECT. Zawsze otrzymasz ekskluzywną blokadę na stole, więc tylko jedna INSERTmoże działać jednocześnie.

W komentarzach powiedziałeś, że wstawisz 100 tys. Wierszy lub mniej i że inne procesy nie będą działały na tabelach podczas wstawiania. Podczas wysyłania dwóch zapytań INSERT do bazy danych oczekiwałbym jednej z trzech rzeczy:

  1. Jedna wkładka działa jako pierwsza i blokuje drugą. Druga wkładka czeka, aż pierwsza wkładka zostanie wykonana.
  2. Jedna wkładka kończy się przed uruchomieniem drugiej. Nie ma wyraźnego blokowania, ale nie są one uruchamiane jednocześnie.
  3. Otrzymujesz impas i tylko jedna wkładka kończy się pomyślnie.

We wszystkich przypadkach zyskujesz lub nie cierpisz, dodając TABLOCKXwskazówkę do zapytania, więc to moja rekomendacja obejścia impasu. Jeśli chcesz wiedzieć, dlaczego czasami występuje impas, musisz poszukać innej odpowiedzi.

W innym scenariuszu, w którym naprawdę potrzebujesz równoległego wstawiania, dwa sposoby obejścia problemu BU to podzielenie sterty i umieszczenie każdej sesji w osobnej partycji lub załadowanie danych przez BCP, BULK INSERT lub Integration Services .

Joe Obbish
źródło
Dzięki za odpowiedź, ale sytuacja, w której spotkałem impas, to jedyny przypadek, jaki do tej pory miałem. W większości przypadków, gdy wydasz polecenie INSERT INTO WITH (TABLOCK) SELECT FROM równolegle, zadanie nie powiedzie się. BTW, używam SQL SERVER 2008 R2. W swoim pytaniu dodałem udany przykład.
SqlWhale
@tec w przypadkach, w których nie zawiedzie, prawdopodobnie kończą się serią. Być może problem pojawia się tylko wtedy, gdy jest określony czas rozruchu, np. Do kompilacji planu.
Martin Smith,
@MartinSmith Zapytanie, w którym napotkałem problem w projekcie, jest znacznie bardziej złożone niż w przykładzie SELECT 1, który wymaga większego nakładu kompilacji, ale tylko czyta z kilku tabel. Próbuję odtworzyć tego typu zakleszczenie przez bardziej złożone zapytania.
SqlWhale
@TecKnowNothing O ile wierszy wstawisz? Ile razy dziennie proces jest uruchamiany? Czy inne zapytania WYBIERZ z tabeli podczas ładowania danych?
Joe Obbish
@JoeObbish 1. Nie sądzę, żeby liczba wierszy była tutaj problemem, mamy tylko 4000 - 70000 dla każdego zapytania, ale są to wysoce zagregowane dane do użycia w kostce. 2. Nadal jest w fazie testów, powinien działać raz dziennie. 3. Nic innego nie czyta z tabeli docelowej.
SqlWhale
4

Wstawiasz w dbo.TargetTabledwóch sesjach, używając obu TABLOCKpodpowiedzi. Oba process9609dc8i process5e13048przetrzymywanie procesów Sch-Soraz IXblokady, które są ze sobą kompatybilne, dzięki czemu oba procesy mogą odbywać się w tym samym czasie. Ale oboje chcą przekonwertować IXblokadę na Exclusive Xtyp. Xzamki nie są ze sobą kompatybilne. Dlatego serwer SQL wybrał jedną z sesji jako ofiarę impasu zamiast nieskończenie długo na siebie czekać.

Podstawowe informacje o zakleszczeniu.

Zablokuj wykres zgodności (aparat bazy danych).

Wykrywanie i kończenie zakleszczeń.

SqlWorldWide
źródło