Autorytatywne źródło, które <> i! = Są identyczne pod względem wydajności w SQL Server

74

Rozważ tę odpowiedź na piśmie SO, która zapewnia pytającego o <>operatora, że:

<>jest ... taki sam jak !=.

Ale potem komentator wypowiada się i mówi:

Prawdą jest, że są funkcjonalnie takie same. Jednak sposób ich wykorzystania przez optymalizator SQL jest zupełnie inny. = /! = są po prostu oceniane jako prawda / fałsz, podczas gdy <> oznacza, że ​​silnik musi spojrzeć i zobaczyć, czy wartość jest większa czy mniejsza niż, co oznacza większy narzut wydajności. Tylko coś do rozważenia przy pisaniu zapytań, które mogą być drogie.

Jestem pewien, że to nieprawda, ale w celu zajęcia się potencjalnymi sceptykami zastanawiam się, czy ktoś może dostarczyć wiarygodne lub kanoniczne źródło, aby udowodnić, że operatorzy nie są funkcjonalnie tacy sami, ale we wszystkich aspektach identyczni?

ErikE
źródło

Odpowiedzi:

144

Podczas analizowania wywołania programu SQL Server w sqllang!DecodeCompOpcelu ustalenia rodzaju obecnego operatora porównania:

Stos wywołań

Dzieje się to na długo przed zaangażowaniem się w optymalizator.

Od operatorów porównania (Transact-SQL)

Operatory porównania i znaczenia

Śledzenie kodu za pomocą debugera i symboli publicznych * sqllang!DecodeCompOpzwraca wartość w rejestrze eax** w następujący sposób:

╔════╦══════╗
║ Op ║ Code ║
╠════╬══════╣
║ <  ║    1 ║
║ =  ║    2 ║
║ <= ║    3 ║
║ !> ║    3 ║
║ >  ║    4 ║
║ <> ║    5 ║
║ != ║    5 ║
║ >= ║    6 ║
║ !< ║    6 ║
╚════╩══════╝

!=i <>oba zwracają 5, więc są nierozróżnialne we wszystkich późniejszych operacjach (łącznie z kompilacją i optymalizacją).


Chociaż wtórne do powyższego punktu, możliwe jest również (np. Użycie nieudokumentowanej flagi śledzenia 8605) spojrzenie na drzewo logiczne przekazane do optymalizatora w celu potwierdzenia tego !=i <>odwzorowania na ScaOp_Comp x_cmpNe(nierównomierne porównanie operatorów skalarnych).

Na przykład:

SELECT P.ProductID FROM Production.Product AS P
WHERE P.ProductID != 4
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);

SELECT P.ProductID FROM Production.Product AS P
WHERE P.ProductID <> 4
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);

oba wytwarzają:

LogOp_Project QCOL: [P] .ProductID
    LogOp_Select
        LogOp_Get TBL: Production.Product (alias TBL: P)
        ScaOp_Comp x_cmpNe
            ScaOp_Identifier QCOL: [P] .ProductID
            ScaOp_Const TI (int, ML = 4) XVAR (int, Not Owned, Value = 4)
    AncOp_PrjList 

Przypisy

* Używam WinDbg ; dostępne są inne debugery. Symbole publiczne są dostępne za pośrednictwem zwykłego serwera symboli Microsoft. Aby uzyskać więcej informacji, zobacz Zagłębianie się w SQL Server przy użyciu programu Minidumps przez zespół doradców klienta SQL Server i debugowanie programu SQL Server za pomocą WinDbg - wprowadzenie Klausa Aschenbrennera.

** Używanie EAX w 32-bitowych instrumentach pochodnych Intela do zwracania wartości z funkcji jest powszechne. Z pewnością Win32 ABI robi to w ten sposób i jestem pewien, że dziedziczy tę praktykę po dawnych czasach MS-DOS, w których AX był używany do tego samego celu - Michael Kjörling

Paul White
źródło
58

Pracuję w Microsoft w dziale obsługi SQL i zapytałem Jacka Li, starszego inżyniera ds. Eskalacji i eksperta w temacie wydajności SQL Server: „Czy SQL traktuje! = Inaczej niż <>?” i powiedział: „Są tacy sami”.

stacylaray
źródło
8

Myślę, że następujące dowodzi, że <>nie wykonuje 2 porównań.

  1. SQL Standard 92 definiuje <>jako operator nie równy ( http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt ). Technicznie !=jest rozszerzeniem standardu (chociaż nie mogę myśleć o żadnym systemie RDBMS, który go nie implementuje).
  2. Gdyby SQLServer był traktowany <>jak 2 operatory, a nie jeden, zrobiłby to samo, ><co w rzeczywistości jest błędem składni.
a1ex07
źródło
1

To nieprawda, Books Online (BOL) twierdzi, że są funkcjonalnie takie same:

! = (Not Equal To) (Transact-SQL)

A jeśli spojrzysz na plan wykonania, w którym !=jest używany, w Predicate zmienia się != na <>.

Ryan Cooper
źródło
2
Problem polega na tym, że język „funkcjonalnie ten sam” jest już dopuszczony w cytowanym komentarzu, ale wprowadza dodatkowe rozróżnienie dotyczące wydajności, pomimo twojej i mojej wiedzy, że „funkcjonalnie ten sam” obejmuje to, jak faktycznie działa i wszelkie jego cechy wydajnościowe. Gdyby ktoś chciał udowodnić, że jest to ponad wszelką determinację, to co by zrobił?
ErikE