Dlaczego te podobne zapytania wykorzystują różne fazy optymalizacji (przetwarzanie transakcji vs. szybki plan)?

12

Przykładowy kod w tym elemencie łączenia

Pokazuje błąd gdzie

SELECT COUNT(*)
FROM   dbo.my_splitter_1('2') L1
       INNER JOIN dbo.my_splitter_1('') L2
         ON L1.csv_item = L2.csv_item

Zwraca prawidłowe wyniki. Jednak poniższe wyniki zwracają niepoprawne wyniki (w 2014 r. Przy użyciu nowego narzędzia Kardynalność)

SELECT
    (SELECT COUNT(*)
    FROM dbo.my_splitter_1('2') L1
     INNER JOIN dbo.my_splitter_1('') L2
        ON L1.csv_item = L2.csv_item)

Ponieważ niepoprawnie ładuje wyniki dla L2 do wspólnej bufora podwyrażeń, następnie odtwarza wynik tego dla wyniku L1.

Byłem ciekawy, dlaczego różnica w zachowaniu między tymi dwoma zapytaniami. Flaga śledzenia 8675 pokazuje, że ten, który działa, wchodzi, search(0) - transaction processinga ten, który zawodzi search(1) - quick plan.

Zakładam więc, że dostępność dodatkowych reguł transformacji kryje się za różnicą w zachowaniu (na przykład wyłączenie BuildGbApply lub GenGbApplySimple to naprawia).

Ale dlaczego dwa plany dotyczące tych bardzo podobnych zapytań napotykają różne fazy optymalizacji? Z tego, co przeczytałem, search (0)wymagane są co najmniej trzy tabele, a warunek ten z pewnością nie jest spełniony w pierwszym przykładzie.

Martin Smith
źródło

Odpowiedzi:

7

Każdy etap ma warunki wejścia. „Posiadanie co najmniej trzech odniesień do tabeli” jest jednym z warunków wejścia, o którym mówimy, gdy podajemy proste przykłady, ale nie jest to jedyny.

Zasadniczo tylko podstawowe sprzężenia i związki są dozwolone dla wyszukiwania 0; skalarne podzapytania, połączenia częściowe itp. uniemożliwiają wejście do wyszukiwania 0. Ten etap naprawdę dotyczy bardzo popularnych kształtów zapytań typu OLTP. Reguły niezbędne do odkrywania mniej popularnych rzeczy po prostu nie są włączone. Twoje przykładowe zapytanie ma podkwerendę skalarną, więc nie można wprowadzić wpisu.

Zależy to również od sposobu liczenia odniesień do tabeli. Nigdy nie zagłębiałem się w to z funkcjami, ale możliwe, że logika liczy funkcje cenione w tabeli, a także zmienne w tabeli, które wytwarzają. Może nawet liczyć odwołanie do tabeli wewnątrz samej funkcji - nie jestem pewien; choć wiem, że funkcje są po prostu ciężką pracą.

Błąd z GenGbApplySimplejest brzydki. Ten kształt planu był zawsze możliwy, ale był odrzucany ze względów kosztowych, dopóki nie pojawiła się zmiana na 100-rzędową zmienną liczność tabeli. Możliwe jest narzucenie problematycznego kształtu planu na CE przed 2014 rokiem z USE PLANpodpowiedź, na przykład.

Masz rację, że nowy element Connect jest tym samym zgłoszonym wcześniej problemem .

Aby podać przykład, następujące zapytanie kwalifikuje się do wyszukiwania 0:

DECLARE @T AS table (c1 integer NULL);

SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY U.c1) 
FROM 
(
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
) AS U;

Wprowadzenie niewielkiej zmiany w celu uwzględnienia podkwerendy skalarnej oznacza, że ​​przechodzi ona bezpośrednio do wyszukiwania 1:

DECLARE @T AS table (c1 integer NULL);

SELECT U.c1, rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -- Changed!
FROM 
(
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
    UNION
    SELECT c1 FROM @T AS T
) AS U;
Paul White 9
źródło