Oszacowanie liczności dla> = i> dla wartości statystyki wewnątrz kroku

9

Próbuję zrozumieć, w jaki sposób SQL Server próbuje oszacować „większe niż” i „większe niż równe” gdzie klauzule w SQL Server 2014.

Wydaje mi się, że rozumiem oszacowanie liczności, kiedy osiąga krok, na przykład, jeśli tak

    select * from charge where charge_dt >= '1999-10-13 10:47:38.550'

Szacunkowa liczność wynosi 6672, którą można łatwo obliczyć jako 32 (EQ_ROWS) + 6624 (RANGE_ROWS) + 16 (EQ_ROWS) = 6672 (histogram na zrzucie ekranu poniżej)

wprowadź opis zdjęcia tutaj

Ale kiedy robię

    select * from charge where charge_dt >= '1999-10-13 10:48:38.550' 

(zwiększyłem czas do 10:48, więc to nie jest krok)

szacunkowa wartość to 4844,13.

Jak to jest obliczane?

jesijesi
źródło

Odpowiedzi:

9

Jedyną trudnością jest podjęcie decyzji o tym, jak obsługiwać etapy histogramu częściowo objęte przedziałem predykatu zapytania. Całe kroki histogramu objęte zakresem predykatu są banalne, jak zauważono w pytaniu.

Narzędzie szacowania liczebności starszej wersji

F = ułamek (od 0 do 1) zakresu kroków objętych predykatem zapytania.

Podstawową ideą jest użycie F(interpolacja liniowa) w celu ustalenia, ile różnych wartości międzyetapowych jest objętych predykatem. Pomnożenie tego wyniku przez średnią liczbę wierszy na odrębną wartość (przy założeniu jednorodności) i dodanie kroku równych rzędów daje oszacowanie liczności:

Kardynalność = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)

Ta sama formuła jest stosowana w CE >i >=w starszej wersji.

Nowy estymator liczności

Nowy CE nieznacznie modyfikuje poprzedni algorytm, aby rozróżnić między >i >=.

Po >pierwsze, formuła jest następująca:

Kardynalność = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1)))

Bo >=to jest:

Kardynalność = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))

+ 1Odzwierciedla że gdy porównanie dotyczy równości, mecz zakłada (założenie integracji).

W przykładzie pytania Fmożna obliczyć jako:

DECLARE 
    @Q datetime = '1999-10-13T10:48:38.550',
    @K1 datetime = '1999-10-13T10:47:38.550',
    @K2 datetime = '1999-10-13T10:51:19.317';

DECLARE
    @QR float = DATEDIFF(MILLISECOND, @Q, @K2), -- predicate range
    @SR float = DATEDIFF(MILLISECOND, @K1, @K2) -- whole step range

SELECT
    F = @QR / @SR;

Wynik to 0,728219019233034 . Podłączając to do formuły dla >=innych znanych wartości:

Kardynalność = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) + 1))
            = 16 + (16,1956 * ((0,728219019233034 * (409 - 1)) + 1))
            = 16 + (16,1956 * ((0,728219019233034 * 408) + 1))
            = 16 + (16,1956 * (297,113359847077872 + 1))
            = 16 + (16,1956 * 298,113359847077872)
            = 16 + 4828.1247307393343837632
            = 4844,127307393343837632
            = 4844.12473073933 (do precyzji pływaka)

Ten wynik zgadza się z szacunkiem 4844,13 przedstawionym w pytaniu.

To samo zapytanie przy użyciu starszej wersji CE (np. Przy użyciu flagi śledzenia 9481) powinno dać oszacowanie:

Kardynalność = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)
            = 16 + (16,1956 * 0,728219019233034 * 409)
            = 16 + 4823.72307468722
            = 4839.72307468722

Należy pamiętać, że szacunek byłby taki sam dla starszej wersji CE >i >=korzystania z niej.

Paul White 9
źródło
4

Wzór na szacowanie wierszy staje się trochę głupi, gdy filtr jest „większy niż” lub „mniejszy niż”, ale jest to liczba, do której można dojść.

Liczby

Korzystając z kroku 193, oto odpowiednie numery:

RANGE_ROWS = 6624

EQ_ROWS = 16

AVG_RANGE_ROWS = 16,1956

RANGE_HI_KEY z poprzedniego kroku = 1999-10-13 10: 47: 38.550

RANGE_HI_KEY z bieżącego kroku = 1999-10-13 10: 51: 19.317

Wartość z klauzuli WHERE = 1999-10-13 10: 48: 38.550

Formuła

1) Znajdź ms między dwoma klawiszami hi zakresu

SELECT DATEDIFF (ms, '1999-10-13 10:47:38.550', '1999-10-13 10:51:19.317')

Wynik to 220767 ms.

2) Dostosuj liczbę rzędów

Musimy znaleźć wiersze na milisekundę, ale zanim to zrobimy, musimy odjąć AVG_RANGE_ROWS od RANGE_ROWS:

6624 - 16,1956 = 6607,8044 wierszy

3) Oblicz liczbę wierszy na ms z dostosowaną liczbą wierszy:

6607,8044 wierszy / 220767 ms = .0299311 wierszy na ms

4) Oblicz ms między wartością z klauzuli WHERE a bieżącym krokiem RANGE_HI_KEY

SELECT DATEDIFF (ms, '1999-10-13 10:48:38.550', '1999-10-13 10:51:19.317')

To daje nam 160767 ms.

5) Oblicz rzędy w tym kroku na podstawie rzędów na sekundę:

.0299311 wierszy / ms * 160767 ms = 4811.9332 wierszy

6) Pamiętasz, jak wcześniej odjęliśmy AVG_RANGE_ROWS? Czas je dodać. Teraz, gdy zakończyliśmy obliczanie liczb związanych z rzędami na sekundę, możemy również bezpiecznie dodać EQ_ROWS:

4811.9332 + 16,1956 + 16 = 4844,1288

Zaokrąglając w górę, to jest nasz szacunek 4844,13.

Testowanie formuły

Nie mogłem znaleźć żadnych artykułów ani postów na blogu o tym, dlaczego AVG_RANGE_ROWS jest odejmowany przed obliczeniem wierszy na ms. I był w stanie potwierdzić, są one uwzględnione w szacunkach, ale dopiero w ostatniej milisekundy - dosłownie.

Korzystając z bazy danych WideWorldImporters , przeprowadziłem pewne testy przyrostowe i stwierdziłem, że zmniejszenie szacunków w wierszach jest liniowe do końca kroku, gdzie nagle uwzględnia się 1x AVG_RANGE_ROWS.

Oto moje przykładowe zapytanie:

SELECT PickingCompletedWhen
FROM Sales.Orders
WHERE PickingCompletedWhen >= '2016-05-24 11:00:01.000000'

Zaktualizowałem statystyki dla PickingCompletedWhen, a następnie otrzymałem histogram:

DBCC SHOW_STATISTICS([sales.orders], '_WA_Sys_0000000E_44CA3770')

Histogram dla _WA_Sys_0000000E_44CA3770 (ostatnie 3 kroki)

Aby zobaczyć, jak szacowane rzędy zmniejszają się, gdy zbliżamy się do RANGE_HI_KEY, zbierałem próbki przez cały krok. Zmniejszenie jest liniowe, ale zachowuje się tak, jakby liczba wierszy równa wartości AVG_RANGE_ROWS po prostu nie była częścią trendu ... dopóki nie trafisz na RANGE_HI_KEY i nagle spadną one jak nieściągalny dług odpisany. Możesz to zobaczyć w przykładowych danych, szczególnie na wykresie.

wprowadź opis zdjęcia tutaj

Zwróć uwagę na stały spadek wierszy, dopóki nie trafimy w RANGE_HI_KEY, a następnie BOOM, że ostatnia część AVG_RANGE_ROWS jest nagle odejmowana. Łatwo jest też zauważyć na wykresie.

wprowadź opis zdjęcia tutaj

Podsumowując, nieparzyste traktowanie AVG_RANGE_ROWS sprawia, że ​​obliczanie oszacowań wierszy jest bardziej złożone, ale zawsze można pogodzić to, co robi CE.

Co z wykładniczym wycofaniem?

Wykładnicze wycofanie to metoda, którą nowy (od SQL Server 2014) Szacunek liczności służy do uzyskiwania lepszych szacunków przy użyciu wielu statystyk jednokolumnowych. Ponieważ pytanie dotyczyło jednej statystyki jednokolumnowej, nie wymaga formuły EB.

Doug Lane
źródło