Dlaczego błąd zapytania z pustym zestawem wyników w SQL Server 2012?

31

Podczas uruchamiania następujących zapytań w MS SQL Server 2012 drugie zapytanie kończy się niepowodzeniem, ale nie pierwsze. Ponadto po uruchomieniu bez klauzul where oba zapytania zakończą się niepowodzeniem. Nie wiem, dlaczego któryś z nich poniósłby porażkę, ponieważ oba powinny mieć puste zestawy wyników. Każda pomoc / wgląd jest mile widziane.

create table #temp
(id     int primary key)

create table #temp2
(id     int)

select 1/0
from #temp
where id = 1

select 1/0
from #temp2
where id = 1
DavidN
źródło

Odpowiedzi:

39

Wstępne spojrzenie na plany wykonania pokazuje, że wyrażenie 1/0jest zdefiniowane w operatorach Compal Scalar:

Plany graficzne

Teraz, mimo że plany wykonania zaczynają się wykonywać po lewej stronie, iteracyjnie wywoływanie Openi GetRowmetody iteratorów potomnych w celu zwrócenia wyników, SQL Server 2005 i nowsze wersje zawierają optymalizację, w której wyrażenia są często definiowane tylko przez skalar obliczeniowy, a ocena jest odraczana do następnego operacja wymaga wyniku :

Operatory obliczania skalarnego pojawiające się w Showplans generowanych przez SET STATISTICS XML mogą nie zawierać elementu RunTimeInformation.  W graficznych planach, rzeczywiste wiersze, rzeczywiste przewijanie i rzeczywiste przewijanie mogą być nieobecne w oknie Właściwości, gdy opcja Uwzględnij rzeczywisty plan wykonania jest zaznaczona w SQL Server Management Studio.  Gdy to nastąpi, oznacza to, że chociaż operatory te były używane w skompilowanym planie zapytań, ich prace były wykonywane przez innych operatorów w planie zapytań w czasie wykonywania.  Zauważ również, że liczba uruchomień w danych wyjściowych Showplan wygenerowanych przez SET STATISTICS PROFILE jest równa sumie ponownych powiązań i przewinięć w Showplans wygenerowanych przez SET STATISTICS XML.  Od: MSDN Books Online

W takim przypadku wynik wyrażenia jest potrzebny tylko podczas zestawiania wiersza w celu zwrotu klientowi (co można pomyśleć o występowaniu przy zielonej SELECTikonie). Zgodnie z tą logiką odroczona ocena oznaczałaby, że wyrażenie nigdy nie jest oceniane, ponieważ żaden plan nie generuje wiersza zwracanego. Aby trochę się skupić na tym punkcie, ani wyszukiwanie klastrowe indeksu, ani skanowanie tabeli nie zwracają wiersza, więc nie ma żadnego wiersza do zebrania w celu zwrotu klientowi.

Istnieje jednak osobna optymalizacja, w której niektóre wyrażenia mogą zostać zidentyfikowane jako stałe środowiska wykonawczego, a więc ocenione raz przed rozpoczęciem wykonywania zapytania . W takim przypadku wskazanie, że tak się stało, można znaleźć w pliku XML showplan (Plan wyszukiwania indeksów klastrowych po lewej, Plan skanowania tabeli po prawej):

Showplan XML

W tym wpisie na blogu napisałem więcej o mechanizmach leżących u ich podstaw i o tym, jak mogą one wpłynąć na wydajność . Korzystając z informacji tam zawartych, możemy zmodyfikować pierwsze zapytanie, aby oba wyrażenia były oceniane i buforowane przed rozpoczęciem wykonywania:

select 1/0 * CONVERT(integer, @@DBTS)
from #temp
where id = 1

select 1/0
from #temp2
where id = 1

Teraz pierwszy plan zawiera również stałe odwołanie do wyrażenia, a oba zapytania powodują wyświetlenie komunikatu o błędzie. Kod XML pierwszego zapytania zawiera:

Wyrażenie stałe

Więcej informacji: Oblicz skalary, wyrażenia i wydajność

Paul White mówi GoFundMonica
źródło
21

Zamierzam inteligentnie zgadywać (a przy okazji prawdopodobnie przyciągnę guru SQL Servera, który może udzielić naprawdę szczegółowej odpowiedzi).

Pierwsze zapytanie zbliża się do wykonania jako:

  1. Zeskanuj indeks klucza podstawowego
  2. Wyszukaj wartości w tabeli danych potrzebne do zapytania

Wybiera tę ścieżkę, ponieważ masz whereklauzulę na kluczu podstawowym. Nigdy nie przechodzi do drugiego kroku, więc zapytanie nie kończy się niepowodzeniem.

Drugi nie ma klucza podstawowego do uruchomienia, więc podchodzi do zapytania jako:

  1. Wykonaj pełny skan danych tabeli i pobierz niezbędne wartości

Jedna z tych wartości 1/0powoduje problem.

To jest przykład optymalizacji zapytania przez SQL Server. W większości przypadków jest to dobra rzecz. SQL Server przeniesie warunki z selectoperacji skanowania tabeli. Często oszczędza to etapów oceny zapytania.

Jednak ta optymalizacja nie jest niczym dobrym. W rzeczywistości wydaje się, że narusza samą dokumentację SQL Server , która mówi, że whereklauzula jest oceniana przed select. Cóż, mogą mieć jakieś erudycyjne wyjaśnienie, co to oznacza. Jednak dla większości ludzi logiczne przetwarzanie whereprzed selectoznaczałoby (między innymi) „nie selectgeneruj błędów klauzulowych w wierszach, które nie zostały zwrócone do użytkownika”.

Gordon Linoff
źródło
1
+1 brak wskazówki, jeśli masz rację, ale najlepszą odpowiedź, jaką widzę, biorąc pod uwagę, że jedyną różnicą jest klucz podstawowy.
1
@GordonLinoff Paul Randal właśnie potwierdził za pośrednictwem Twittera, że ​​twoja odpowiedź była dobra.
SchmitzIT
4
@ Mimo to rzeczywista kolejność wykonywania, jakkolwiek inna, nie powinna prowadzić do takich komunikatów o błędach.
ypercubeᵀᴹ
7
@ypercube Erland Sommarskog zgodzi się z tobą (Połącz przedmiot)
Paul White mówi GoFundMonica
2
Dziękuję za wskaźnik - zalogowałem się i rozpatrzyłem prośbę.
Gordon Linoff