2010-01-20 11 views
10

Czy ktoś może mi pomóc w impasie w SQL Server 2005?Zakleszczenie programu SQL Server 2005 z nieklastrowanym indeksem

Dla prostego testu, mam tabelę "Book", która ma klucz podstawowy (id) i nazwę kolumny. Domyślnym indeksem tego klucza podstawowego jest nieklastrowany.

Zakleszczenie występuje, gdy dwie sesje są uruchamiane w tym samym czasie. Monitor aktywności pokazuje pierwszą sesję "// krok 1" blokuje wiersz (pozbywanie się blokady) za pomocą X-lock. Druga sesja utrzymuje wiersz U lock i klawisz U lock. Obraz zakleszczenia pokazuje "// krok 2" pierwszej sesji wymaga klucza U lock.

Jeśli indeks to w klastrze, nie ma w tym przypadku żadnego zakleszczenia. "// step 1" będzie przechowywać wiersz i blokadę klucza w tym samym czasie, więc nie ma problemu. Rozumiem, że blokowanie wiersza spowoduje również zablokowanie indeksu, ponieważ węzeł liścia indeksu klastrowego to dane wiersza.

Ale dlaczego jest nieklastrowany indeks w ten sposób? Jeśli druga sesja zawiera klucz U lock, to dlaczego "krok 1" pierwszej sesji nie posiada tej blokady, ponieważ są one takie same jak instrukcja aktualizacji.

--// first session 
BEGIN TRAN 
    update Book set name = name where id = 1 //step 1 
    WaitFor Delay '00:00:20' 
    update Book set name = 'trans' where id = 1 //step2 
COMMIT 

--// second session 
BEGIN TRAN 
--// this statement will keep both RID(U lock) and KEY(U lock) if first session did not use HOLDLOCK 
    update Book set name = name where id = 1 
COMMIT 
+0

Czy w ogóle masz klucz klastrowany na swoim próbnym stole książki? Nie sądzę, że chodzi o to, czy twój PK jest skupiony, czy nie - myślę, że chodzi bardziej o to, czy faktycznie masz klucz klastrowany (i tym samym tabelę w klastrze), czy też masz do czynienia z stertą (bez indeksu klastrowego) –

+0

Czy możesz dodać odpowiednie wyjście 'exec sp_lock', gdy jest w impasie? – Andomar

+0

Od sqlprofiler obraz zakleszczenia pokazuje "// krok2" pierwszej sesji wymaga klucza U lock, ale jest on przechowywany przez seesion2. –

Odpowiedz

10

Istotny jest tutaj fakt, że używasz kolumny w klauzuli where, która ma indeks nieklastrowy. Kiedy SQL Server przetwarza aktualizacji, to idzie tak:

  1. Znajdź wiersze do aktualizacji, biorąc U zamki dotykanych danych
  2. wierszy aktualizacji biorąc X zamki zmodyfikowanych danych

Po instrukcja kończy się (pod domyślną izolacją READ COMMITTED), blokady U są zwalniane, ale blokady X są utrzymywane do końca transakcji, aby utrzymać izolację.

W sytuacji bez klastrów indeks SQL Server szuka indeksu na id i używa go do wyszukiwania rzeczywistego wiersza.Blokujący odtwarza się w następujący sposób:

  1. (Session 1, etap 1) U zamek odebrany na wskaźnik wartości klucza dla ID = 1
  2. (Session 1, etap 1) blokady X podjęte w RID rzędu id = 1
  3. (Session 1, etap 1) U zamek wydany
  4. (Session 2) u-lock odebrany na wskaźnik wartości klucza dla ID = 1
  5. (Session 2) zamka X zablokowane RID rzędu id = 1
  6. (Sesja 1, krok 2) Blokada U zablokowana na wartości klucza indeksu dla id = 1 - DEADLOCK

Jednakże, gdy wskaźnik jest wskaźnikiem klastra, nie jest oddzielny etap przekształcania klucza indeksem wiersza - zgrupowanych Indeks jest identyfikator wiersza. Dlatego też, blokowanie kończy się w następujący sposób:

  1. (Session 1, etap 1) U zamek odebrany na wskaźnik wartości klucza dla ID = 1
  2. (Session 1, etap 1) U zamek przeniesieni do X zamka
  3. (Session 2) U zamek blokowany indeksu wartości klucza dla ID = 1
  4. (Session 1, etap 2) blokady już w dniu indeksu wartości klucza dla ID = 1
  5. (Session 1, zmian) blokady wydany
  6. (Sesja 2) U lock przyznano
  7. (Session 2) U lock przeniesieni do X zamka
  8. (Session 2) Blokada wydany

Jak zawsze, należy pamiętać, że choć może to być plan kwerend stosowany w tym przypadku, optymalizator może swobodnie robić różne rzeczy. Na przykład może wybrać skanowanie tabeli lub wyjąć więcej gruboziarnistych zamków. W takich przypadkach impas może się nie zdarzyć.

+0

Dziękuję bardzo, to ma dla mnie sens. Problem wydaje się być "osobnym krokiem do konwersji klucza indeksu do wiersza" w indeksie nieklastrowanym. –

+0

Jeśli dodam blokadę podpowiedzi w instrukcji aktualizacji dla obu sesji, jest to rozwiązane, ponieważ blokady U i X są nadal przechowywane w sesji 1. Rozumiem, że blokada tylko żąda blokady S, zastanawiam się, dlaczego blokada może pozwolić sesji 1 zachować Blokada U dla klucza i blokada X dla RID? Dziękuję. –

+0

Czy blokada może spowodować inne potencjalne problemy (np. Inny impas, obniżenie wydajności)? –

0

Ten link ma wiele przydatnych sugestii: SQL Server deadlocks between select/update or multiple selects.

Oto kilka punktów do rozważenia, które mogą pomóc ludziom, aby odpowiedzieć na pytanie:

  1. Co transakcja poziom izolacji używasz?
  2. Czy dozwolona jest eskalacja blokady (na przykład od wiersza do strony)?
  3. Czy istnieje kolumna "nazwa"?
+0

1.read comitted 2. użyj domyślnego ustawienia przez SQLServer 3. Brak innego indeksu. –

0

Twoja pierwsza aktualizacja nie faktycznie niczego modyfikować:

update Book set name = name where id = 1 

Thy polecenie, które faktycznie zmienia swoją kolumnę, następnie wyłącznym blokada odbędzie się w wierszu.

Powiązane problemy