2009-06-19 5 views
7

Mam dość duży stół: ponad 20 milionów wierszy i muszę zaktualizować około 5% tego - lub 1 milion wierszy.Jak przyspieszyć masywną aktualizację do kolumny w klastrze?

Niestety, aktualizuję kolumnę (int), która jest używana jako indeks klastrowany.

Moje pytanie brzmi: Jaki jest najszybszy sposób aktualizacji tych wierszy?

Próbowałem aktualizacji wierszy bezpośrednio:

update t1 
set t1.groupId = t2.groupId 
from 
    table t1 
join newtable t2 on t1.email = t2.email 

ale to trwa zbyt długo (I zatrzymał go po 3 godzinach)

Przypuszczam, że to dlatego, że cały rząd (który ma 2 datetimes, 2 varchars i 2 ints) są przenoszone po każdej aktualizacji.

Co zrobić, jeśli najpierw usunięto indeks klastrowy, a następnie zaktualizowano, a następnie ponownie utworzono indeks klastrowy? Czy to byłoby szybciej?

Uwaga: Mam indeks klastrowy w wiadomościach e-mail, w przypadku, gdy ktoś uważa, że ​​jest to wybrana część zapytania, która jest wolna. To nie jest.

+2

Myślę, że odpowiedziałeś na własne pytanie. Oprócz upuszczenia indeksu klastrowanego można również upuścić inne indeksy i odtworzyć je po zakończeniu aktualizacji. –

Odpowiedz

8

Oto co zrobiłem (i to znacznie szybciej):

  1. rzuciłem indeksu klastrowego.
  2. I RÓWNIEŻ usunięto klucze obce odniesienia (dwa inne kolumny int ).
  3. Uruchomiłem aktualizację
  4. Odtworzyłem indeks, który był szybszy niż oczekiwano. (To jest pierwotny powód, dla którego najpierw zapytałem SO).

To spowodowało, że cały proces spadł do kilku sekund. Tak, ~ 1 milion wierszy w około 15 sekund.

Drugi krok miał kluczowe znaczenie, ponieważ klucze obce wymuszały aktualizację, aby wykonać jakieś buforowanie w powiązanych tabelach, z których każda ma również dużą liczbę wierszy.

Liczba fizycznych odczytów została potrojona z powodu tych wyszukiwań klucza obcego.

Nie jestem pewien, dlaczego SQL Server musi to zrobić, ale przypuszczam, że nadal wykonuje kontrolę integralności, nawet jeśli nie aktualizuję tej kolumny, ale przenoszę cały wiersz (aktualizację kolumny klastrowej).


Na marginesie, ja też próbowałem uruchamiając aktualizację w partiach:

update top(1000) t1 
set t1.groupId = t2.groupId 
from 
    table t1 
join newtable t2 on t1.email = t2.email 

To było w porządku (i wydawało się skalować do około 10K jednej partii), ale to wciąż było na rzędu 1-2 minut każda partia.


Podsumowując, dowiedziałem się, że w przypadku aktualizacji zbiorczych tymczasowe usuwanie indeksów może być bardzo pomocne.

-1

Dlaczego nie można wykonać następujące czynności:

  • Dodać inną kolumnę (jeden z varchar'S) indeksu klastrowego
  • Tworzenie indeksu na GroupID
  • aktualizacji
  • Następnie odwrócić proces.

To powinno być szybsze.

+1

Dlaczego miałbym utworzyć inną kolumnę indeks klastrowany? Czy nie spowoduje to przypadkowego losowania moich identyfikatorów grup i spowolnienia ponownego utworzenia indeksu klastrowego groupId? To był mój strach. –

2

Myślę, że komentarz wcześniej ma rację. Odpowiadałeś na własne pytanie.

Ponieważ

indeksów klastrowanych sortowania i przechowywania wierszy danych w tabeli w oparciu o ich kluczowych wartości (źródło MSDN),

może być lepiej tylko upuszczenie indeksu klastrowego (zachowaj indeks w wiadomości e-mail). Po zakończeniu operacji ponownie utwórz indeks klastrowany. Dopóki groupid nie uczestniczy w żadnych innych indeksach, nie będę ich dotykał. Jeśli identyfikator grupy jest zaangażowany w inne indeksy, upuść je. Zostawiłbym przynajmniej indeks na e-mailu, aby szybko dołączyć.