środa, 26 maja 2010

Klauzula TOP.

Jakiś czas temu miałem dziwny przypadek podczas kasowania rekordów. Z uwagi na fakt, że w tabeli było kilkaset tysięcy rekordów, algorytm kasujący nie usuwał ich wszystkich od razu, ale robił to paczkami po 100 000. Na początek wyliczał sobie ile razy ma się wykonać DELETE aby skasować wszystkie rekordy. Jeżeli w tabeli było 500 000 rekordów to DELETE wykonywał się 5 razy. Polecenie DELETE było napisane następująco :

DELETE FROM TABELA
WHERE TABELA_ID IN (SELECT TOP 100000 TABELA_ID
                    FROM TABELA)

Na jednym z serwerów (tylko na jednym) algorytm nie kasował wszystkich danych. Nie dlatego, że polecenie DELETE wykonywało się za mało razy, ale dlatego, że powyższe polecenie nie kasowało 100 000 rekordów tylko mniej. Raz 30 000, raz 5000, raz 70 000, ale nigdy 100 000. Powodowało to, że na koniec zostawały dane w tabeli. Do tej pory nie wiem dlaczego tak się to zachowało. Na innych instancjach DELETE kasował po 100 000.

Problem rozwiązaliśmy dodając do SELECT TOP 100000 ... klauzulę ORDER BY. Po jej dodaniu DELETE zachowywał się zgodnie z oczekiwaniami. Co prawda osobiście uważam, że zawsze przy TOP powinno być ORDER BY (no chyba, że rzeczywiście chcemy wyciągnąć przypadkowe dane).

Można było oczywiście przepisać tego DELETE inaczej np. kasując przedziałami, tzn. TABLA_ID BETWEEN ... AND ..., ale to i tak nie rozwiązuje zagadki dlaczego pierwotny DELETE nie zadziałał tak jakby się tego można było po nim spodziewać.

Czy ktoś z Was zna może rozwiązanie tej zagadki ?