In che modo l'ottimizzatore di SQL Server stima il numero di righe in una tabella unita?


13

Sto eseguendo questa query nel database AdventureWorks2012 :

SELECT 
    s.SalesOrderID,
    d.CarrierTrackingNumber,
    d.ProductID,
    d.OrderQty
FROM Sales.SalesOrderHeader s 
JOIN Sales.SalesOrderDetail d 
    ON s.SalesOrderID = d.SalesOrderID
WHERE s.CustomerID = 11077

Se guardo il piano di esecuzione stimato, vedo quanto segue:

inserisci qui la descrizione dell'immagine

La ricerca dell'indice iniziale (in alto a destra) sta utilizzando l'indice IX_SalesOrderHeader_CustomerID e la ricerca nel letterale 11077. Ha una stima di 2.6192 righe.

inserisci qui la descrizione dell'immagine

Se uso DBCC SHOW_STATISTICS ('Sales.SalesOrderHeader', 'IX_SalesOrderHeader_CustomerID') WITH HISTOGRAM, mostra che il valore 11077 è compreso tra le due chiavi campionate 11019 e 11091.

inserisci qui la descrizione dell'immagine

Il numero medio di righe distinte tra 11019 e 11091 è 2.619718 o arrotondato a 2.61972 che è il valore delle righe stimate visualizzate per la ricerca dell'indice.

La parte che non capisco è il numero stimato di righe per la ricerca dell'indice cluster rispetto alla tabella SalesOrderDetail.

inserisci qui la descrizione dell'immagine

Se corro DBCC SHOW_STATISTICS ('Sales.SalesOrderDetail', 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID'):

inserisci qui la descrizione dell'immagine

Quindi la densità di SalesOrderID (a cui mi sto unendo) è 3.178134E-05. Ciò significa che 1 / 3.178134E-05 (31465) è uguale al numero di valori SalesOrderID univoci nella tabella SalesOrderDetail.

Se ci sono 31465 SalesIDderID univoci in SalesOrderDetail, quindi con una distribuzione uniforme, il numero medio di righe per SalesOrderID è 121317 (numero totale di righe) diviso per 31465. La media è 3.85561

Quindi, se il numero stimato di righe da ripetere è 2.61972 e la media da restituire in 3.85561, penso che il numero stimato di righe sarebbe 2.61972 * 3.85561 = 10.10062.

Ma il numero stimato di righe è 11.4867.

Penso che la mia comprensione della seconda stima sia errata e i numeri diversi sembrano indicarlo. Cosa mi sto perdendo?

Risposte:


20

Penso che la mia comprensione della seconda stima sia errata e i numeri diversi sembrano indicarlo. Cosa mi sto perdendo?

Utilizzando lo stimatore di cardinalità di SQL Server 2012, la selettività del join determina il numero stimato di righe sul lato interno dei loop di loop nidificati e non viceversa.

Il numero 11.4867 viene derivato (per la visualizzazione in showplan) dividendo la cardinalità stimata calcolata dell'output del join (30.0919) per il numero di iterazioni (2.61972). Il risultato, usando l'aritmetica in virgola mobile a precisione singola, è 11.4867 .

È davvero così semplice. Si noti che la selettività (logica) di join è indipendente dalla scelta dell'operatore di join fisico. Rimane lo stesso indipendentemente dal fatto che il join venga infine eseguito utilizzando un operatore fisico Nested Loops, Hash o Merge Join.

In SQL Server 2012 e versioni precedenti, la selettività del join (nel suo insieme) viene stimata utilizzando gli SalesOrderIDistogrammi di ciascuna tabella (calcolata per ogni passaggio dell'istogramma, dopo l'allineamento del limite del passaggio utilizzando l'interpolazione lineare, se necessario). L' SalesOrderIDistogramma associato alla SalesOrderHeadertabella viene inoltre regolato per l'effetto di ridimensionamento del CustomerIDfiltro indipendente .

Ciò non significa che ci sia qualcosa di fondamentalmente "sbagliato" nel calcolo alternativo proposto nella domanda; fa solo una diversa serie di ipotesi. Ci saranno sempre diversi modi per calcolare o combinare le stime per una determinata sequenza di operazioni logiche. Non vi è alcuna garanzia generale che metodi statistici diversi applicati agli stessi dati produrranno le stesse risposte, o che un metodo sia sempre superiore all'altro. Incoerenze risultanti dall'applicazione di diversi metodi statistici possono anche apparire all'interno di un unico piano di esecuzione finale, anche se raramente vengono notate.

Come nota a margine, lo stimatore di cardinalità di SQL Server 2014 adotta un approccio diverso per combinare le informazioni sull'istogramma regolate dal filtro indipendente ( "allineamento approssimativo " ), che risulta in una stima finale diversa di 10.1006 righe per questa query:

Plan for computation:

  CSelCalcExpressionComparedToExpression
  (QCOL: [s].SalesOrderID x_cmpEq QCOL: [d].SalesOrderID)

Loaded histogram for column QCOL: [s].SalesOrderID from stats with id 1
Loaded histogram for column QCOL: [d].SalesOrderID from stats with id 1

Stats collection generated: 

  CStCollJoin(ID=4, **CARD=10.1006** x_jtInner)
      CStCollFilter(ID=3, CARD=2.61972)
          CStCollBaseTable(ID=1, CARD=31465 TBL: Sales.SalesOrderHeader AS TBL: s)
      CStCollBaseTable(ID=2, CARD=121317 TBL: Sales.SalesOrderDetail AS TBL: d)

Questo sembra essere lo stesso risultato del calcolo nella domanda, sebbene il ragionamento dettagliato sia diverso (cioè non si basa su un'implementazione di cicli nidificati ipotizzati).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.