Jest to z pewnością błąd w produkcie.
Podobny błąd został już zgłoszony i zamknięty jako „Nie naprawi” .
W tym to pytanie, połączony element połączenia i inny
dwa
pytania w tej witrynie Widziałem cztery przypadki tego typu zachowań z wbudowanymi funkcjami TVF i OUTER APPLY
- Wszystkie miały format
OUTER APPLY dbo.SomeFunction(...) F
I zwrócił poprawne wyniki, gdy został zapisany jako
OUTER APPLY (SELECT * FROM dbo.SomeFunction(...)) F
To wygląda na możliwe obejście.
Dla zapytania
WITH Test AS
(
SELECT 12 AS PropertyID,
$350000 AS Ap1,
350000 AS Ap2
)
SELECT LP.*
FROM Test T
OUTER APPLY dbo.TVFTest
(
T.PropertyID,
T.Ap1,
T.Ap2
) LP;
Plan wykonania wygląda tak
A lista kolumn wyjściowych w końcowej projekcji jest. Wyr1000, Wyr1001, Wyr1003, Wyr1004.
Jednak tylko dwie z tych kolumn są zdefiniowane w tabeli stałych w prawym dolnym rogu.
Dosłowne $350000
jest zdefiniowana w tabeli stałych w prawym górnym rogu (Expr1001). To następnie zostaje połączone na zewnątrz do tabeli stałych w prawym dolnym rogu. Ponieważ żaden wiersz nie pasuje do warunku złączenia, dwie zdefiniowane tam kolumny (Wyr1003, Wyr1004) są poprawnie oceniane jako NULL. następnie w końcu skalar obliczeniowy dodaje literał 12
do przepływu danych jako nowa kolumna (Expr1000) niezależnie od wyniku połączenia zewnętrznego.
To wcale nie jest poprawna semantyka. Porównaj z (prawidłowym) planem, gdy wbudowany TVF jest wstawiany ręcznie.
WITH Test
AS (SELECT 12 AS PropertyID,
$350000 AS Ap1,
350000 AS Ap2)
SELECT LP.*
FROM Test T
OUTER APPLY (SELECT KeyID,
MatchValue1,
MatchValue2,
CASE
WHEN MatchValue1 <> MatchValue2
THEN 'Not equal'
ELSE 'Something else'
END AS MatchTest
FROM (SELECT T.PropertyID AS KeyID,
T.Ap1 AS MatchValue1,
T.Ap2 AS MatchValue2) TestRow
WHERE MatchValue1 <> MatchValue2) LP
Tutaj kolumny użyte w końcowej projekcji to Expr1003, Expr1004, Expr1005, Expr1006
. Wszystkie te elementy są zdefiniowane w prawym dolnym rogu stałego skanowania.
W przypadku TVF wszystko wydaje się bardzo wcześnie pójść źle.
Dodanie OPTION (RECOMPILE, QUERYTRACEON 3604, QUERYTRACEON 8606);
pokazuje, że drzewo wejściowe do procesu jest już nieprawidłowe. Wyrażone w SQL jest to coś w rodzaju.
SELECT Expr1000,
Expr1001,
Expr1003,
Expr1004
FROM (VALUES (12,
$350000,
350000)) V1(Expr1000, Expr1001, Expr1002)
OUTER APPLY (SELECT Expr1003,
IIF(Expr1001 <> Expr1003,
'Not equal',
'Something else') AS Expr1004
FROM (SELECT CAST(Expr1002 AS MONEY) AS Expr1003) D
WHERE Expr1001 <> Expr1003) OA
Pełne dane wyjściowe tej flagi śledzenia są następujące (8605 pokazuje w zasadzie to samo drzewo).
*** Input Tree: ***
LogOp_Project COL: Expr1000 COL: Expr1001 COL: Expr1003 COL: Expr1004
LogOp_Apply (x_jtLeftOuter)
LogOp_Project
LogOp_ConstTableGet (1) [empty]
AncOp_PrjList
AncOp_PrjEl COL: Expr1000
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=12)
AncOp_PrjEl COL: Expr1001
ScaOp_Const TI(money,ML=8) XVAR(money,Not Owned,Value=(10000units)=(-794967296))
AncOp_PrjEl COL: Expr1002
ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=350000)
LogOp_Project
LogOp_Select
LogOp_Project
LogOp_ConstTableGet (1) [empty]
AncOp_PrjList
AncOp_PrjEl COL: Expr1003
ScaOp_Convert money,Null,ML=8
ScaOp_Identifier COL: Expr1002
ScaOp_Comp x_cmpNe
ScaOp_Identifier COL: Expr1001
ScaOp_Identifier COL: Expr1003
AncOp_PrjList
AncOp_PrjEl COL: Expr1004
ScaOp_IIF varchar collate 53256,Var,Trim,ML=14
ScaOp_Comp x_cmpNe
ScaOp_Identifier COL: Expr1001
ScaOp_Identifier COL: Expr1003
ScaOp_Const TI(varchar collate 53256,Var,Trim,ML=9) XVAR(varchar,Owned,Value=Len,Data = (9,Not equal))
ScaOp_Const TI(varchar collate 53256,Var,Trim,ML=14) XVAR(varchar,Owned,Value=Len,Data = (14,Something else))
AncOp_PrjList
*******************