Problem oszacowania liczności przy złączeniu wewnętrznym

13

Próbuję zrozumieć, dlaczego szacowanie wierszy jest tak bardzo błędne, oto mój przypadek:

Proste dołączanie - przy użyciu SQL Server 2016 sp2 (ten sam problem na sp1), dbcompatiblity = 130.

select Amount_TransactionCurrency_id, CurrencyShareds.id 
from CurrencyShareds 
    INNER JOIN annexes ON Amount_TransactionCurrency_id = CurrencyShareds.Id 
option (QUERYTRACEON 3604, QUERYTRACEON 2363);

SQL szacuje 1 wiersz, podczas gdy jest to 107131 i wybiera wykonanie zagnieżdżonej pętli ( link do planu ). Po zaktualizowaniu statystyk CurrencyShareds oszacowanie jest w porządku i wybrano połączenie przez scalenie ( link do nowego planu ). Jak tylko jeden rekord zostanie dodany do CurrencyShareds, statystyki stają się „przestarzałe” i sql wraca do błędnego oszacowania.

Nie martwiłbym się tak bardzo tym prostym zapytaniem, ale to tylko część większego zapytania, a to początek domina ...

Dlaczego dodanie jednego wiersza do tabeli 100 rekordów powoduje takie uszkodzenie? Gdy patrzę na dane wyjściowe śladu szacowania liczności, widzę to ostrzeżenie, ***WARNING: badly-formed histogram ***ale nie mogę znaleźć nic więcej na ten temat.

Oto wynik pełnej oceny z oszacowania liczności:

Begin selectivity computation
Input tree:

LogOp_Join

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

ScaOp_Comp x_cmpEq

ScaOp_Identifier QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id

ScaOp_Identifier QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id

Plan for computation:

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1 *** WARNING: badly-formed histogram ***

Selectivity: 4.59503e-018

Stats collection generated:

CStCollJoin(ID=3, CARD=1 x_jtInner)

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

End selectivity computation

Estimating distinct count in utility function

Input stats collection:

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

Columns to distinct on:QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id

Plan for computation:

CDVCPlanLeaf

0 Multi-Column Stats, 1 Single-Column Stats, 0 Guesses

Covering multi-col stats id: 7

Using ambient cardinality 107131 to combine distinct counts:

5

Combined distinct count: 5

Result of computation: 5

Estimating distinct count in utility function

Input stats collection:

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

Columns to distinct on:QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id

Plan for computation:

CDVCPlanUniqueKey

Result of computation: 100

A kiedy aktualizuję statystyki CurrencyShareds, zmienia się część ze „źle sformułowanym histogramem”, a liczność jest obliczana poprawnie

Plan for computation:

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1

Selectivity: 0.01

Stats collection generated:

CStCollJoin(ID=3, CARD=107131 x_jtInner)

CStCollBaseTable(ID=1, CARD=107131 TBL: annexes)

CStCollBaseTable(ID=2, CARD=100 TBL: CurrencyShareds)

End selectivity computation

I statystyki dla tego „[CurrencyShareds]. Na podstawie statystyk o id 1” z ostrzeżeniem o histogramie, który wygląda mi dobrze ...

Name                                                                                                                             Updated              Rows                 Rows Sampled         Steps  Density       Average key length String Index Filter Expression                                                                                                                                                                                                                                                Unfiltered Rows      Persisted Sample Percent
-------------------------------------------------------------------------------------------------------------------------------- -------------------- -------------------- -------------------- ------ ------------- ------------------ ------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------- ------------------------
PK_CurrencyShareds_Id                                                                                                            May 23 2018 10:43PM  98                   98                   75     1             8                  NO           NULL                                                                                                                                                                                                                                                             98                   0

(1 row affected)

All density   Average Length Columns
------------- -------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0,01020408    8              Id

(1 row affected)

RANGE_HI_KEY         RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
-------------------- ------------- ------------- -------------------- --------------
119762190797406464   0             1             0                    1
119762190797406466   1             1             1                    1
119762190797406468   1             1             1                    1
119762190797406470   1             1             1                    1
119762190797406472   1             1             1                    1
119762190797406474   1             1             1                    1
119762190797406476   1             1             1                    1
119762190797406478   1             1             1                    1
119762190797406480   1             1             1                    1
119762190797406482   1             1             1                    1
119762190797406484   1             1             1                    1
119762190797406486   1             1             1                    1
119762190797406488   1             1             1                    1
119762190797406490   1             1             1                    1
119762190797406492   1             1             1                    1
119762190797406494   1             1             1                    1
119762190797406496   1             1             1                    1
119762190797406498   1             1             1                    1
119762190797406500   1             1             1                    1
119762190797406502   1             1             1                    1
119762190797406504   1             1             1                    1
119762190797406506   1             1             1                    1
119762190797406507   0             1             0                    1
478531702587687680   0             1             0                    1
478531702591881728   0             1             0                    1
478531702591881729   0             1             0                    1
478531702591881984   0             1             0                    1
478531702591881985   0             1             0                    1
478531702596076032   0             1             0                    1
478531702596076033   0             1             0                    1
478531702596076288   0             1             0                    1
478531702600270336   0             1             0                    1
478531702600270592   0             1             0                    1
478532235583062528   0             1             0                    1
478532235583062784   0             1             0                    1
478532235587256832   0             1             0                    1
530792464911467264   0             1             0                    1
530792464924049920   0             1             0                    1
530792464924050176   0             1             0                    1
530792464928244224   0             1             0                    1
530792464928244480   0             1             0                    1
530792464932438528   0             1             0                    1
530792464932438784   0             1             0                    1
530792464936632832   0             1             0                    1
530792464936632833   0             1             0                    1
530792464936633088   0             1             0                    1
530792464940827136   0             1             0                    1
530792464940827392   0             1             0                    1
530792464949216000   2             1             2                    1
530792464953410048   0             1             0                    1
530792464953410304   0             1             0                    1
530792464957604352   0             1             0                    1
530792464957604353   0             1             0                    1
530792464957604608   0             1             0                    1
530792464961798656   0             1             0                    1
530792464961798912   0             1             0                    1
530792464965992960   0             1             0                    1
530792464965993216   0             1             0                    1
530792464965993217   0             1             0                    1
530792464970187264   0             1             0                    1
530792464970187265   0             1             0                    1
530792464970187520   0             1             0                    1
530792464974381568   0             1             0                    1
530792464974381824   0             1             0                    1
530792464974381825   0             1             0                    1
530792464978575872   0             1             0                    1
530792464978575873   0             1             0                    1
530792464978576128   0             1             0                    1
867420708903354880   0             1             0                    1
867420708903355136   0             1             0                    1
867420708903355137   0             1             0                    1
960876568220042240   0             1             0                    1
976385263448130048   0             1             0                    1
977302121709864192   0             1             0                    1
977955748426318592   0             1             0                    1

i informacje dla drugiego indeksu:

Name                                                                                                                             Updated              Rows                 Rows Sampled         Steps  Density       Average key length String Index Filter Expression                                                                                                                                                                                                                                                Unfiltered Rows      Persisted Sample Percent
-------------------------------------------------------------------------------------------------------------------------------- -------------------- -------------------- -------------------- ------ ------------- ------------------ ------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------- ------------------------
IX_FK_Amount_TransactionCurrency                                                                                                 May 21 2018  3:29PM  107204               107204               5      0             16                 NO           NULL                                                                                                                                                                                                                                                             107204               0

(1 row affected)

All density   Average Length Columns
------------- -------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0,2           8              Amount_TransactionCurrency_id
9,32801E-06   16             Amount_TransactionCurrency_id, Id

(2 rows affected)

RANGE_HI_KEY         RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
-------------------- ------------- ------------- -------------------- --------------
119762190797406475   0             160           0                    1
119762190797406478   0             867           0                    1
119762190797406481   0             106           0                    1
119762190797406494   0             105742        0                    1
119762190797406496   0             329           0                    1
LeMaciek
źródło

Odpowiedzi:

10

Na podstawie twoich histogramów udało mi się powtórzyć problem w 2017 CU6. Nie powiedziałbym, że robisz coś złego. Coś idzie nie tak z oszacowaniem liczności. Oto, co otrzymuję przed wstawieniem wiersza:

wprowadź opis zdjęcia tutaj

Ostateczne oszacowanie liczności spada dość po wstawieniu wiersza:

wprowadź opis zdjęcia tutaj

Masz tutaj dość proste repro, więc radzę przesłać opinię o produkcie lub otworzyć zgłoszenie do pomocy technicznej w firmie Microsoft. Udało mi się znaleźć kilka obejść, które działały na twoich przykładowych danych, i jedno z nich może być dla ciebie akceptowalne.

  1. Upuść unikalny indeks na CurrencyShareds.Id. Nie mogę zmusić repro do działania bez unikalnego indeksu. Stół jest mały, więc może poradzisz sobie bez indeksu. Oczywiście możesz mieć bardzo dobre powody, aby go zatrzymać.
  2. Zmaterializuj wyniki łączenia w tabeli tymczasowej. W oparciu o twoje pytanie ważne jest, aby uzyskać rozsądne oszacowanie na tym etapie, aby większe zapytanie działało dobrze. Tabela temp jest jednym ze sposobów, aby tak się stało.
  3. Użyj starszej wersji CE. Nie mogę zmusić problemu do odtworzenia się z nim. Oczywiście może to mieć negatywne konsekwencje dla pozostałej części zapytania.
  4. Oszukać optymalizator zapytań głupim kodem. Na przykład w moich testach następujące przepisywanie działa świetnie:

.

select Amount_TransactionCurrency_id, CurrencyShareds.id
from CurrencyShareds 
INNER JOIN annexes
ON Amount_TransactionCurrency_id % 9223372036854775809 = CurrencyShareds.Id % 9223372036854775809

Podejrzewam, że to działa, ponieważ wydaje się, że CE używa gęstości zamiast histogramu. Inne podobne przepisywania mogą mieć ten sam efekt. Nie ma gwarancji, że ten typ zapytania będzie działał dobrze w przyszłości. Właśnie dlatego powinieneś skontaktować się z firmą Microsoft, aby zwiększyć szanse, że pewnego dnia poprawka problemu pojawi się w wydanym produkcie.

Joe Obbish
źródło
8

Ok, mam nadzieję, że teraz to rozumiem - więc to nasza sprawa

Dany

  1. Tabela referencyjna (CurrencyShareds) z ~ 100 wierszami, ale identyfikatory są duże, a wartości min, max różnią się bardzo - min: 119 762,190,797,406,464 w porównaniu do maks .: 977,955,748,426,318,592
  2. Tabela (załączniki) z prostym FK do CurrencyShared, ale używanych jest tylko kilka Walut - możesz zobaczyć, że histogram dla IX_FK_Amount_TransactionCurrency zawiera 5 identyfikatorów - a co ważne, tylko te „niskie” identyfikatory, ponieważ inne nie są używane.

Kiedy wszystkie statystyki są aktualne

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1

Selectivity: 0.01

Wtedy selektywność obliczona dla złączenia jest w porządku, ponieważ 100 * 107 131 * 0,01 = 107 131

Kiedy statystyki wymiany walut nie są aktualne, to

CSelCalcExpressionComparedToExpression( QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id x_cmpEq QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id )

Loaded histogram for column QCOL: [test.MasterData].[dbo].[Annexes].Amount_TransactionCurrency_id from stats with id 7

Loaded histogram for column QCOL: [test.MasterData].[dbo].[CurrencyShareds].Id from stats with id 1 *** WARNING: badly-formed histogram ***

Selectivity: 4.59503e-018

Selektywność spada dramatycznie, a zatem szacowana liczba rzędów sprzężenia wynosi 1.

Kiedy zmienia się histogram

Po dodaniu pojedynczego wiersza do załączników, który odświeża CurrencyShared o wysokim identyfikatorze, w rezultacie histogram dla IX_FK_Amount_TransactionCurrency zmienia się na

RANGE_HI_KEY         RANGE_ROWS    EQ_ROWS       DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
-------------------- ------------- ------------- -------------------- --------------
119762190797406475   0             173           0                    1
119762190797406478   0             868           0                    1
119762190797406481   0             107           0                    1
119762190797406494   0             105745        0                    1
119762190797406496   0             330           0                    1
119762190797406618   0             1             0                    1
119762190797406628   0             1             0                    1
977955748426318623   0             1             0                    1

Z tym histogramem problem znika, a teraz dodanie nowego wiersza do wymiany walut nie powoduje dramatycznego spadku oszacowania liczności.

Dlaczego?

Podejrzewam, że tak działa algorytm szacowania zgrubnego histogramu w sql2014 + i zgaduję na podstawie tego wspaniałego postu https://www.sqlshack.com/join-estimation-internals/

Szacowanie zgrubnego histogramu jest nowym algorytmem i mniej udokumentowanym, nawet pod względem ogólnych pojęć. Wiadomo, że zamiast wyrównywać histogramy krok po kroku, wyrównuje je tylko z minimalnymi i maksymalnymi granicami histogramu. Ta metoda potencjalnie wprowadza mniej błędów CE (nie zawsze jednak, ponieważ pamiętamy, że to tylko model).

Żeby wszystko było jasne - dlaczego mamy takie dziwne identyfikatory w wymianach walut?

To dość proste - nasze identyfikatory są globalnie unikalne i częściowo oparte są na znaczniku czasu (implementacja oparta na płatku śniegu ). Najpopularniejsze waluty zostały dodane na początku aplikacji kilka lat temu i tylko te nieliczne są naprawdę używane w produkcji, dlatego na histogramie są tylko te o „niskim” id.

Problem pojawił się w naszych środowiskach testowych, w których niektóre automatyczne testy zaczęły dodawać waluty testowe, powodując, że niektóre zapytania działały dłużej lub upłynęły limity czasu ...

Jak rozwiązać problem?

Będziemy częściej aktualizować statystyki dla tych tabel referencyjnych (możemy mieć podobny problem z innymi podobnymi tabelami danych referencyjnych) częściej - te tabele są małe, więc aktualizacja statystyk nie stanowi problemu

Zdobyta wiedza

  • Ważne są aktualne statystyki !!!
  • zwykła stara kolumna tożsamości nie spowodowałaby tych problemów :)
LeMaciek
źródło
Odnośnie zgrubnego wyrównania: sqlperformance.com/2018/11/sql-optimizer/…
Paul White 9