Jestem tylko ciekawy, dlaczego zapytanie zagregowane działa o wiele szybciej z GROUP BY
klauzulą niż bez niej.
Na przykład uruchomienie tego zapytania zajmuje prawie 10 sekund
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
Podczas gdy ten zajmuje mniej niż sekundę
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate
W CreatedDate
tym przypadku jest tylko jeden , więc zgrupowane zapytanie zwraca te same wyniki, co zgrupowane.
Zauważyłem, że plany wykonania dwóch zapytań są różne - drugie zapytanie korzysta z równoległości, a pierwsze nie.
Czy to normalne, że SQL Server inaczej ocenia zapytanie zagregowane, jeśli nie ma klauzuli GROUP BY? Czy jest coś, co mogę zrobić, aby poprawić wydajność pierwszego zapytania bez użycia GROUP BY
klauzuli?
Edytować
Właśnie się nauczyłem, że mogę OPTION(querytraceon 8649)
ustawić narzut kosztów równoległości na 0, co sprawia, że zapytanie korzysta z pewnej równoległości i skraca czas działania do 2 sekund, chociaż nie wiem, czy jest jakaś wada korzystania z tej wskazówki zapytania.
SELECT MIN(CreatedDate)
FROM MyTable
WHERE SomeIndexedValue = 1
OPTION(querytraceon 8649)
Wciąż wolę krótszy czas wykonywania, ponieważ zapytanie ma wypełniać wartość po wybraniu użytkownika, więc idealnie powinno być natychmiastowe, tak jak zapytanie zgrupowane. W tej chwili właśnie kończę moje zapytanie, ale wiem, że to nie jest idealne rozwiązanie.
SELECT Min(CreatedDate)
FROM
(
SELECT Min(CreatedDate) as CreatedDate
FROM MyTable WITH (NOLOCK)
WHERE SomeIndexedValue = 1
GROUP BY CreatedDate
) as T
Edytuj # 2
W odpowiedzi na prośbę Martina o dodatkowe informacje :
Zarówno CreatedDate
i SomeIndexedValue
mają oddzielny non-unikalny, nieklastrowanym indeks na nich. SomeIndexedValue
jest właściwie polem varchar (7), mimo że przechowuje wartość liczbową wskazującą na PK (int) innej tabeli. Relacja między dwiema tabelami nie jest zdefiniowana w bazie danych. Nie mam w ogóle zmieniać bazy danych i mogę pisać tylko zapytania, które wyszukują dane.
MyTable
zawiera ponad 3 miliony rekordów, a do każdego rekordu przypisana jest grupa, do której należy ( SomeIndexedValue
). Grupy mogą mieć od 1 do 200 000 rekordów
MAXDOP
ustawia maksymalny stopień równoległości, który ogranicza liczbę procesorów, których może użyć zapytanie. Zasadniczo spowodowałoby to, że drugie zapytanie działałoby tak wolno, jak pierwsze, ponieważ usuwa ono możliwości korzystania z równoległości, czego nie chcę.Moim zdaniem przyczyną problemu jest to, że optymalizator serwera SQL nie szuka planu BEST, a raczej dobrego planu, co widać po tym, że po wymuszeniu równoległości zapytanie wykonało się znacznie szybciej, coś, co optymalizator miał nie zrobione na własną rękę.
Widziałem także wiele sytuacji, w których przepisywanie zapytania w innym formacie stanowiło różnicę między równoległością (na przykład chociaż większość artykułów na temat SQL poleca parametryzację, zauważyłem, że czasami powoduje to paralelizację, nawet jeśli parametry wąchane były takie same jak inne - zrównoleglenie jednego lub połączenie dwóch zapytań z UNION ALL może czasem wyeliminować równoległość).
W związku z tym poprawnym rozwiązaniem może być wypróbowanie różnych sposobów pisania zapytania, takich jak wypróbowanie tabel tymczasowych, zmiennych tabel, cte, tabel pochodnych, parametryzacji itd., A także odtwarzanie indeksów, widoków indeksowanych lub indeksów filtrowanych w aby uzyskać najlepszy plan.
źródło