Piszę na jednym z moich nadchodzących postów na blogu o funkcjach okna rankingu i agregacji, w szczególności iteratorach projektu Segment i Sekwencja. Rozumiem, że Segment identyfikuje wiersze w strumieniu, które stanowią koniec / początek grupy, więc następujące zapytanie:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
Użyje Segmentu, aby określić, kiedy wiersz należy do innej grupy niż poprzedni. Następnie iterator projektu sekwencji wykonuje obliczenie rzeczywistej liczby wierszy na podstawie danych wyjściowych z iteratora segmentu.
Ale poniższe zapytanie, wykorzystujące tę logikę, nie powinno zawierać segmentu, ponieważ nie ma wyrażenia partycji.
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
Jednak gdy wypróbuję tę hipotezę, oba te zapytania wykorzystują operator segmentu. Jedyna różnica polega na tym, że drugie zapytanie nie wymaga GroupBy
segmentu. Czy to nie eliminuje potrzeby segmentu?
Przykład
CREATE TABLE dbo.someTable (
someGroup int NOT NULL,
someOrder int NOT NULL,
someValue numeric(8, 2) NOT NULL,
PRIMARY KEY CLUSTERED (someGroup, someOrder)
);
--- Query 1:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
FROM dbo.someTable;
--- Query 2:
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
FROM dbo.someTable;
źródło
<GroupBy />
więc segment naprawdę nic nie robi, prawie wysyła kolumnę segmentu do operatora projektu sekwencji. Przyczyną obecności operatora segmentu może być to, że operator projektu sekwencji potrzebuje tej wartości do wykonania swojej pracy.Odpowiedzi:
Znalazłem ten 6-letni wpis na blogu wspominający o tym samym zachowaniu.
Wygląda na to, że
ROW_NUMBER()
zawsze zawiera operator segmentu, niezależnie od tego, czyPARTITION BY
jest używany, czy nie. Gdybym musiał zgadywać, powiedziałbym, że to dlatego, że ułatwia to tworzenie planu zapytań w silniku.Jeśli segment jest potrzebny w większości przypadków, a w przypadkach, gdy nie jest potrzebny, jest to zasadniczo zerowy brak operacji, o wiele łatwiej jest po prostu zawsze włączyć go do planu, gdy używana jest funkcja okienkowania.
źródło
Zgodnie z showplan.xsd dla planu wykonania,
GroupBy
pojawia się bezminOccurs
lubmaxOccurs
atrybuty, które w związku z tym domyślnie [1..1] sprawiają, że element jest obowiązkowy, niekoniecznie treściowy. Element potomnyColumnReference
type (ColumnReferenceType
) maminOccurs
0 imaxOccurs
nieograniczony [0 .. *], co czyni go opcjonalnym , stąd dozwolony pusty element. Jeśli ręcznie spróbujesz usunąćGroupBy
plan i wymusić go, otrzymasz oczekiwany błąd:Co ciekawe, zauważyłem, że możesz ręcznie usunąć operatora segmentu, aby uzyskać prawidłowy plan wymuszania, który wygląda następująco:
Jednak gdy uruchomisz z tym planem (korzystasz
OPTION ( USE PLAN ... )
), Operator segmentu pojawi się magicznie. Po prostu pokazuje, że optymalizator przyjmuje jedynie plany XML jako przybliżony przewodnik.Mój zestaw testowy:
Wytnij plan XML ze stanowiska testowego i zapisz go jako .sqlplan, aby wyświetlić plan bez Segmentu.
PS Nie spędzałbym zbyt wiele czasu na ręcznym omijaniu planów SQL, tak jakbyś mnie znał, wiedziałbyś, że uważam to za czasochłonną pracę i coś, czego nigdy nie zrobiłbym. Och, poczekaj !? :)
źródło