Chwalę się zazwyczaj, że jestem bardzo doświadczonym Bazylem (jak zwykłem określać ludków parających się bazami danych), jednak prawda jest taka, że poważnymi bazami zajmuję się może od czterech-pięciu lat, nie dłużej.
Przez poważną bazę rozumiem bazę, której nawet powieka nie drgnie przy słuchaniu kawału o zdechłym koniu. Nie zaszkodzi, jeżeli przy okazji ma rozmiar mierzony w terabajtach / miliardach rekordów.
Jako punkt zwrotny w mojej karierze Bazyla przyjmuję jeden z pierwszych dni pracy w pewnej firmie (tu, w Irlandii), kiedy to przykazano mi rzucić okiem na środowisko DEV jednego z serwerów baz danych i powiedzieć, co o nim myślę.
Bez wdawania się w zbędne szczegóły, przejdę od razu do sedna. Otóż namierzyłem tabelkę z parudziesięcioma milionami rekordów, w której zidentyfikowałem ciut ponad dwa miliony rekordów zbędnych (nie pamiętam już, może duplikaty, może z błędami, mniejsza o to). Upewniwszy się, że backupy są zrobione na bieżąco, a także, że jestem faktycznie w środowisku DEV a nie na ten przykład LIVE (nikt by nie dał takiemu greenhornowi dostępu do LIVE, nawet w trybie RO, ale strzyżonego pambuk strzyże...), zapuściłem co następuje:
DELETE FROM BARDZO_WAZNA_TABELA WHERE TRZEBA_SKASOWAC=1;
Po pięciu minutach zacząłem się zastanawiać co jest grane.
Po piętnastu minutach zacząłem myśleć o odświeżeniu swojego CV na monster.ie
Po ponad czterdziestu minutach wykonywanie komendy wreszcie dobiegło końca. Niestety, zamiast oczekiwanej informacji o usunięciu ponad dwóch milionów rekordów, ujrzałem jakiś czerwony komunikat błędu, w którym rzucało się w oczy "corrupt" jak również "space". Nie pamiętam dokładnie treści komunikatu, ale wynikało zeń jasno, że wskutek zeżarcia całej wolnej przestrzeni na dysku, serwer nie może zapisać danych do logu transakcyjnego w związku z czym transakcja została przerwana i baza jest teraz uszkodzona.
Hm.
Myślę sobie, spokojnie, bez paniki. Spróbujmy zajrzeć do bazy i...
Niestety, baza wisiała sobie w trybie "suspect" i ni chu-chu nie dało się z niej niczego wydusić.
Z ciężkim sercem oraz wizją rychłego zwolnienia dyscyplinarnego (niby to tylko DEV, ale zawsze...) wykonałem telefon do lokalnego mastahaka czyli szefa działu DBA:
- Halo Mastahaka,
sytuacja jest taka a taka,
chciałem skasować dane,
teraz mam przechlapane,
i generalnie dupa jest zimna a baza podejrzana.
Mastahaka podpytał mnie o szczegóły połączenia do bazy, coś tam w tle poklikał i powiedział, że za około 40 minut wszystko powinno wrócić do normy, że baza jest w trybie "autorecovery" i żebym się za bardzo nie przejmował. Dodał jeszcze, że następnym razem zanim spróbuję skasować miliony rekordów jednym strzałem, żebym się najpierw przebadał na głowę, bo to przecież trzeba robić we wsadach. Czyli w batch-ach. Po troszku, po troszku, i będzie gites. A tak jak się próbuje od razu całość to potem są cyrki.
Nieco uspokojony, oddaliwszy od siebie wizję dyscyplinarki, zasiadłem do końsoli, i z MSDN-em pod rękę, a z Guglem w charakterze ochroniarza, spłodziłem:
SET ROWCOUNT 10000; DELETE FROM BARDZO_WAZNA_TABELA WHERE TRZEBA_SKASOWAC=1;
Przed uruchomieniem upewniłem się jeszcze, że baza już nie jest "Suspect" i że mam do niej dostęp. Następnie zapętliłem powyższe zapytanie coś ze 200 razy i po chwili sprawa była zakończona.
Przy okazji, od wersji SQL 2008 zamiast SET ROWCOUNT XXX używamy TOP XXX, a więc:
DELETE TOP 10000 FROM BARDZO_WAZNA_TABELA WHERE TRZEBA_SKASOWAC=1;
Kilka lat później trafiłem na interview do firmy, która operowała Naprawdę Poważnymi Danymi (a więc, dziesiątki miliardów rekordów w głównych tabelach, dziesiątki terabajtów pojemności oraz setki rekordów na sekundę ciągłego obciążenia), i tam, jak już przemielili mnie wzdłuż i w poprzek, zamieniając mózg w gąbkę do naczyń, padło sakramentalne pytanie:
- Ma pan zaktualizować kolumnę w tabeli z miliardem rekordów. Jak pan to zrobi?
Myślę sobie, śrubokrętem, taka wasz mać. Ale zachowałem tę cenną myśl dla siebie.
- Podzielę - mówię - rekordy w tej tabeli na wsady po parędziesiąt tysięcy i zapuszczę aktualizację na każdym wsadzie osobno.
- Bingo, bardzo dobrze!
Potem moi kaci odeszli, pozostawiając mnie sam na sam z butelką wody, a za chwilę przyszedł ich (i mój przyszły) szef. Ten zamiast mnie męczyć merytorycznie, podpytał mnie o różne rzeczy nie bardzo związane z pracą. Na koniec zadał to samo pytanie, i usłyszawszy odpowiedź, że zrobię to wsadowo, pogratulował mi i wyszedł.
Potem sytuacja powtórzyła się raz jeszcze (przylazł szef tamtego szefa), i znów jedynym technicznym pytaniem było jak zaktualizować dane w wielkiej tabeli.
Domyślam się, że któryś z moich poprzedników musiał popełnić kosztowny błąd - podobny do tego, który mi przytrafił się dawno temu - i zapuścił jakąś dużą operację na danych produkcyjnych. Tylko że zamiast nędznych dwóch milionów rekordów próbował zmodyfikować dwadzieścia miliardów. Efekt łatwo przewidzieć...
Tak więc:
Pamiętaj, Bazylu młody
Nie rzucaj pod nogi kłody,
Skorzystaj z mojej porady,
I dziel rekordy na wsady.
O'le!
a jeszcze lepiej – na etapie projektowania partycjonuj poziomo tabele.
Zgadza się, tylko się nie rymuje 😉
się lepiej rekordy kasuje gdy tabele się pierwej partycjonuje.
Pewien zdolny Bazyl z miasta Dublin
Kasował rekordy z okolicznych gmin
ale pechowo pomyliły mu sie wsady
i wieczorem własnej żonie nie dał rady
więc z rozpaczy kupił kilka win
Wszystko fajnie, tylko gdzie stopy i daktyle? Jezeli to ma byc limeryk, ja bym to przerobil o tak:
Był raz pewien Bazyl w Dublinie
Rekordy kasował nagminnie.
Raz wsady pomieszał
Gdy żonę pocieszał
Utopił frustrację swą w winie.
No i od razu tak trza było.
Zapomniałem, pozdrowienia z Limerick 🙂
Baza na dziesiątki miliardów rekordów 😀 Ach, chciałbym raz sobie na takiej bazie zrobić jakieś DROP albo co…
No, taki DROP byłby słyszalny z wielkim hukiem w promieniu paru kilometrów…
Cos zblizonego miałem kiedyś na Oracle. Próbowałem skasować zaledwie kilka tys. rekordów z pewnej tabeli słownikowej. Oczywiście nic nie było pod te rekordy 'podwieszone'. Trwało to na tyle długo, że przerwałem operacje.
Na szczęście baza nadal była online.
System po prostu przed skasowaniem kazdego rekordu sprawdzał wszystkie constrainty (glownie Foreign Keys) zdefiniowane na tabeli, a że było ich sporo (słownik), no to można było sobie czekać…
Kiedy wyłaczyłem constrainty, poszło błyskawicznie.
Ale duszę miałem na 'ramieniu', bo co jesli skasuje przy okazji rownież i takie co nie byly 'orphant' ?
Ale baza też była DEV, więc spoko…
Oj, znam to. Sam niedawno pisałem skrypt zerujący bazę danych Oracle i musiałem wykumać kolejność tabel żeby nie naruszyć żadnych constraints. Do tego jeszcze trzeba było constraints kasować a potem odtwarzać, żeby szło szybciej. Mrówcza praca.