AKTUALIZACJA z JOIN na płytach 100 mm, jak to zrobić lepiej? (w T-SQL)

11

Muszę zaktualizować 100 milionów rekordów w jednej tabeli, w efekcie normalizując tabelę, zastępując wartość varchar kolumny zwykłym identyfikatorem. (Mówię „zastępuję”, ale tak naprawdę piszę identyfikator w innej kolumnie).

Staram się znormalizować zestaw danych. Dane jeszcze nie znormalizowane nie mają indeksowania. Myślałem, że nie będę budował indeksów na wartościach surowych, czekając, zamiast indeksować klucze obce, które zastąpią wartości varchar wartościami tinyint po zakończeniu aktualizacji.

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

tło

  • za pomocą MSSQL 2008 R2 na Server 2008 R2
  • serwer ma 8 GB pamięci RAM
  • serwer ma jeden RAID10, 7200 RPM SATA (nie wspaniale, wiem, w produkcji to będzie tylko czytać dane, a nie zapisywać dane; plus niedawny brak HD spowodował, że było to konieczne)
  • Serwer ma podwójny czterordzeniowy procesor Xeon
  • maszyna nie robi nic innego (obecnie poświęcony programowaniu, tylko ten proces)
  • proste logowanie włączone (? - ale czy nadal się loguje, aby móc przywrócić?)
  • zwróć uwagę, że zapytanie odwołuje się do dwóch różnych baz danych dla tego, co jest warte
  • „szerokość” rekordu w aktualizowanej tabeli wynosi 455 bajtów

Zasoby podczas wykonywania

  • fizyczna pamięć RAM jest maksymalna
  • dysk we / wy jest maksymalny
  • Procesor prawie nic nie robi (dławik to We / Wy)
  • czas działania wyniósł 14 godzin i wciąż rośnie!

Podejrzewam kilka rzeczy, takich jak potrzebuję indeksu na surowych danych, nawet jeśli po aktualizacji normalizacji będę upuszczał kolumnę (AutoClassName). Zastanawiam się również, czy powinienem po prostu zapętlać jeden rekord na raz zamiast JOIN, co wydawało się śmieszne w momencie, gdy to zaczynałem, ale teraz wydaje się, że byłoby szybciej.

Jak powinienem zmienić metodologię pozostałych aktualizacji normalizacyjnych (podobnych do tej) szybciej?

Chris Adragna
źródło

Odpowiedzi:

7

Próbujesz to zrobić jako pojedynczą (bardzo dużą) transakcję. Zamiast tego wykonaj aktualizację w mniejszych partiach.

Będziesz także korzystać z:

  • Tymczasowy indeks na AutoData.dbo.AutoClass.AutoClassName
  • Więcej pamięci RAM. Dużo więcej pamięci RAM.
Mark Storey-Smith
źródło
1
+1 Zgadzam się z aktualizacją partii przy użyciu TOPklauzuli. To byłoby moje podejście.
Thomas Stringer
Jeśli wykonam UPDATE TOP, potrzebuję klauzuli WHERE (GDZIE AutoClassID ma wartość NULL)? Czy klauzula WHERE nie wprowadziłaby nowego działania związanego z wydajnością (nie skanuję teraz tabeli). Bez wątpienia zmniejszy to problem z pamięcią RAM, który mam z JOIN.
Chris Adragna
Moja odpowiedź jest już dawno spóźniona, ale w moim przypadku SET ROWCOUNT okazało się najbardziej skuteczne.
Chris Adragna,
10

Przyjąłbym inne podejście.

Zamiast aktualizować istniejące tabele, po prostu stwórz nową tabelę, która ma w sobie to, czego potrzebujesz.

Będzie to prawie na pewno szybsze:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

Jak obecnie napisano, dzieje się wiele logicznych operacji:

  • Przeczytaj wszystkie wartości A.AutoClassName
  • Przeczytaj wszystkie wartości B.AutoClassName
  • Porównaj wartości A i B.
  • Z pasującego zestawu przeczytaj wszystkie wartości B.AutoClassID
  • Zaktualizuj istniejące wartości A.AutoClassId, aby były wartością B.AutoClassId, niezależnie od istniejących indeksów
JNK
źródło
To brzmi jak przyjemne, proste podejście, szczególnie biorąc pod uwagę problem z dyskowymi dyskami we / wy. Dziękujemy za tak szybką odpowiedź.
Chris Adragna
1
Sugeruję, aby dokładnie sprawdzić, czy masz wystarczającą ilość wolnego miejsca w plikach dziennika i danych. Jeśli pliki rosną automatycznie, wydajność spadnie. Często widzę ludzi, którzy przeprowadzają dużą, jednorazową aktualizację i automatycznie powiększają swój plik dziennika, nie zdając sobie z tego sprawy.
cieśnina darina
5

Zapętlanie stołu po jednym rzędzie na raz nie będzie szybsze!

Jak podejrzewasz i potwierdzasz, będzie to związane we / wy - jeden dysk, odczyt, zapis, dzienniki transakcji i (dowolna) temp. Miejsca pracy będą konkurować o ten sam we / wy.

Proste odzyskiwanie będzie nadal rejestrować transakcje, ale dziennik zostanie wyczyszczony przez punkt kontrolny. Możliwe, że początkowy rozmiar dziennika i ustawienia automatycznego wzrostu powodują pewne spowolnienie operacji we / wy - dziennik transakcji będzie musiał wzrosnąć, aby uwzględnić zmiany.

Czy próbowałeś zaindeksować pole AutoClassName? Ile jest różnych wartości AutoClass?

Konieczne może być grupowanie aktualizacji w zależności od ograniczeń we / wy. Więc zaktualizuj 1 milion, punkt kontrolny, powtórz ....

Kev Riley
źródło
Istnieje tylko 15 różnych wartości AutoClass. Twoje komentarze potwierdzają wiele moich podejrzeń (i bólów!). Dziękuje za odpowiadanie.
Chris Adragna
3

Utwórz indeksy dla pól łączących.

Zawsze możesz upuścić indeksy po zakończeniu.

Byłbym bardzo zaskoczony, gdyby indeksy nie poprawiły znacząco wydajności aktualizacji.

Jimbo
źródło
Jestem pewien, że indeksy poprawiłyby się. Przypuszczam, że pytanie brzmi, czy poprawią się one więcej niż czas potrzebny do utworzenia indeksu (tylko do jednego użytku). Prawdopodobnie tak. :)
Chris Adragna,
3

Wyeksportuj tak, jak chcesz, utwórz nową tabelę i zaimportuj ponownie. Jako bonus, będziesz mieć kopię danych jako kopię zapasową, na wypadek cudów.

srini.venigalla
źródło