Pytanie, które pojawiło się podczas dyskusji na czacie:
Wiem, że skróty łączą pakiety ratunkowe wewnętrznie do czegoś w rodzaju zagnieżdżonych pętli.
Co robi SQL Server dla ratowania agregacji skrótów (jeśli w ogóle może się to zdarzyć)?
Pytanie, które pojawiło się podczas dyskusji na czacie:
Wiem, że skróty łączą pakiety ratunkowe wewnętrznie do czegoś w rodzaju zagnieżdżonych pętli.
Co robi SQL Server dla ratowania agregacji skrótów (jeśli w ogóle może się to zdarzyć)?
Odpowiedzi:
Łączenie skrótów i agregacja skrótów używają tego samego kodu operatora wewnętrznie, chociaż agregat skrótu używa tylko jednego wejścia (kompilacji). Podstawowa operacja mieszania kruszywa jest opisany przez Craig Freedman :
Podobnie jak w przypadku łączenia skrótu, agregat skrótu wymaga pamięci. Przed wykonaniem zapytania z agregacją skrótu SQL Server używa oszacowań liczności w celu oszacowania ilości pamięci potrzebnej do wykonania zapytania. W przypadku łączenia mieszającego przechowujemy każdy wiersz kompilacji, więc całkowite zapotrzebowanie na pamięć jest proporcjonalne do liczby i wielkości wierszy kompilacji. Liczba połączonych wierszy i wyjściowa liczność sprzężenia nie mają wpływu na wymaganą pamięć połączenia. Dzięki agregacji skrótów przechowujemy jeden wiersz dla każdej grupy, więc całkowite zapotrzebowanie na pamięć jest w rzeczywistości proporcjonalne do liczby i wielkości grup wyjściowych lub wierszy. Jeśli mamy mniej unikalnych wartości grupy według kolumn (kolumn) i mniej grup, potrzebujemy mniej pamięci. Jeśli mamy więcej unikalnych wartości grupy według kolumn i więcej grup, potrzebujemy więcej pamięci.
Następnie mówi o rekurencji skrótu:
Co się stanie, jeśli zabraknie nam pamięci? Ponownie, podobnie jak łączenie mieszające, jeśli zabraknie nam pamięci, musimy zacząć rozlewać wiersze do tempdb. Rozlewamy jeden lub więcej segmentów lub partycji, w tym wyniki częściowo zagregowane wraz z wszelkimi dodatkowymi nowymi wierszami łączącymi się z rozlanymi segmentami lub partycjami. Chociaż nie próbujemy agregować rozlanych nowych wierszy, robimy je mieszając i dzielimy na kilka segmentów lub partycji. Po zakończeniu przetwarzania wszystkich grup wejściowych wysyłamy gotowe grupy w pamięci i powtarzamy algorytm, odczytując i agregując jedną rozlaną partycję na raz. Dzieląc rozlane wiersze na wiele partycji, zmniejszamy rozmiar każdej partycji, a tym samym zmniejszamy ryzyko, że algorytm będzie musiał wiele razy powtarzać.
Pakiet ratunkowy Hash jest lekko udokumentowany, ale wspomniany przez Nacho Alonso Portillo w Jaki jest maksymalny poziom rekurencji dla iteratora skrótu przed wymuszeniem ratowania?
Wartość jest stała, zakodowana na stałe w produkcie, a jej wartość wynosi pięć (5). Oznacza to, że zanim operator skanowania skrótu zastosuje algorytm oparty na sortowaniu dla dowolnej podsekcji, która nie mieści się w przyznanej pamięci z obszaru roboczego, musiało się zdarzyć pięć poprzednich prób podzielenia oryginalnej partycji na mniejsze partycje.
„Operator skanowania skrótu” wspomniał, że istnieje odniesienie do klasy wewnętrznej CQScanHash
w sqlmin.dll
. Ta klasa kieruje implementacją operatora skrótu (we wszystkich jego postaciach, w tym w częściowych agregatach i odrębnych przepływach), co widzimy w planach wykonania.
To prowadzi nas do sedna twoich pytań - co dokładnie robi algorytm ratowania? Czy jest to „oparte na sortowaniu” czy oparte na „rodzaju zagnieżdżonej pętli”?
Jest to prawdopodobnie jedno i drugie, w zależności od twojego punktu widzenia. Kiedy rekursja skrótu osiągnie poziom 5, partycja skrótu w pamięci zmienia się z tabeli skrótów w początkowo pusty indeks b-drzewa wartości skrótu. Każdy wiersz z jednej wcześniej rozlanej partycji mieszającej jest sprawdzany w indeksie b-drzewa i odpowiednio wstawiany (nowa grupa) lub aktualizowany (zachowując agregacje).
Ta seria nieuporządkowanych wstawek do b-drzewa może być równie dobrze postrzegana jako rodzaj wstawiania lub jako indeksowane wyszukiwanie zagnieżdżonych pętli.
W każdym razie gwarantuje się, że ten algorytm rezerwowy zostanie ostatecznie ukończony bez przydzielania większej ilości pamięci. Może to wymagać wielu przejść, jeśli przestrzeń dostępna dla b-drzewa nie jest wystarczająca do przechowywania wszystkich kluczy i agregatów grupowania z partycji przepełnienia.
Po wyczerpaniu pamięci dostępnej do przechowywania indeksu b-drzewa wszelkie dalsze wiersze (z bieżącej rozlanej partycji) są wysyłane do pojedynczej nowej partycji tempdb (która z pewnością jest mniejsza) i proces powtarza się w razie potrzeby. Poziom wycieku pozostaje na poziomie 5, ponieważ zakończyła się rekurencja mieszania . Niektóre szczegóły przetwarzania można zaobserwować za pomocą nieudokumentowanej flagi śledzenia 7357.