2009-09-25 12 views
5

Ich versuche, eine ziemlich komplexe gespeicherte Prozedur zu debuggen, die über viele Tabellen (10-11) verbindet. Ich sehe, dass für einen Teil des Baumes die geschätzte Anzahl der Zeilen drastisch von der tatsächlichen Anzahl der Zeilen abweicht - im schlechtesten Fall schätzt der SQL Server, dass 1 Zeile zurückgegeben wird, wenn tatsächlich 55.000 Zeilen zurückgegeben werden!Wie berechnet SQL Server die geschätzte Anzahl der Zeilen?

Ich versuche herauszufinden, warum das ist - alle meine Statistiken sind auf dem neuesten Stand, und ich habe Statistiken mit einem FULLSCAN auf mehreren Tabellen aktualisiert. Ich verwende keine benutzerdefinierten Funktionen oder Tabellenvariablen. Soweit ich sehen kann, sollte SQL Server in der Lage sein, genau abzuschätzen, wie viele Zeilen zurückgegeben werden, aber es wählt weiterhin einen Plan aus, der Zehntausende von RDI-Abfragen durchführt (wenn erwartet wird, dass nur 1 ausgeführt wird) oder 2).

Was kann ich tun, um zu verstehen, warum die geschätzte Anzahl von Zeilen um so viel zu klein ist?

UPDATE: Also auf dem Plan suchen ich einen Knoten insbesondere gefunden haben, die suspicous scheint - es ist ein Tisch auf einem Tisch scannen Sie den folgenden predecate mit:

status <> 5 
AND [type] = 1 
OR [type] = 2 

Dieses Prädikat die gesamte Tabelle zurück (630 Zeilen - die Tabelle scannt sich selbst nicht die Quelle der schlechten Leistung), aber SQL Server hat die geschätzte Anzahl der Zeilen bei nur 37. SQL Server fährt dann fort, mehrere verschachtelte Schleifen mit diesem auf RDI-Lookups, Index-Scans und Index zu tun sucht. Könnte dies die Ursache für meine massive Fehleinschätzung sein? Wie kann ich eine vernünftigere Anzahl von Zeilen schätzen?

+0

Könnten Sie bitte Ihre Tabellendefinition und die vollständige Abfrage veröffentlichen? – Quassnoi

+0

Sorry, aber nicht wirklich - es ist zu groß (250 Zeilen sp + 10 Tabellen). – Justin

+3

Wenn Ihr Prädikat genau so ist (ohne Klammern), haben Sie möglicherweise ein logisches Problem. UND hat Vorrang vor ODER. Sollte [status] <> 5 AND sein (type = 1 OR type = 2) – GilaMonster

Antwort

8

SQL Server Splits jeder Index in bis zu 200 Bereiche mit den folgenden Daten (von here):

  • RANGE_HI_KEY

    Ein Schlüsselwert, der die obere Grenze eines Histogrammschritts zeigt.

  • RANGE_ROWS

    Gibt an, wie viele Zeilen innerhalb des Bereichs sind (sie sind kleiner als dieser RANGE_HI_KEY, aber größer als die vorherige kleinere RANGE_HI_KEY).

  • EQ_ROWS

    Gibt an, wie viele Zeilen RANGE_HI_KEY genau gleich sind.

  • AVG_RANGE_ROWS

    Durchschnittliche Anzahl der Zeilen pro eindeutigen Wert innerhalb des Bereichs.

  • DISTINCT_RANGE_ROWS

    Gibt an, wie viele verschiedene Schlüsselwerte innerhalb dieses Bereichs sind (ohne den vorherigen Schlüssel vor RANGE_HI_KEY und RANGE_HI_KEY selbst); Normalerweise

, am dichtesten bevölkerten Werte gehen in RANGE_HI_KEY.

Sie können jedoch in den Bereich gelangen und dies kann zu einer Verschiebung der Verteilung führen.

diese Daten Imagine (unter dem anderen):

Schlüsselwert Anzahl der Zeilen

1   1 
2   1 
3   10000 
4   1 

SQL Server in der Regel baut zwei Bereiche: 1-3 und 4 zum nächsten besiedelten Wert, der diese Statistiken macht :

RANGE_HI_KEY RANGE_ROWS EQ_ROWS AVG_RANGE_ROWS DISTINCT_RANGE_ROWS 
3    2   10000 1    2 

, was die Suche nach, zum Beispiel,bedeutet, gibt es aber 1 Zeile und es ist besser, den Indexzugriff zu verwenden.

Aber wenn 3 innerhalb des Bereichs geht, sind die Statistiken dieser:

RANGE_HI_KEY RANGE_ROWS EQ_ROWS AVG_RANGE_ROWS DISTINCT_RANGE_ROWS 
4    10002  1  3334   3 

Der Optimierer denkt es gibt 3334 Zeilen für den Schlüssel 2 und Indexzugriff ist zu teuer.

+0

Wie können wir dieses Problem lösen, auch wenn das Aktualisieren von Statistiken mit voller Abtastung es nicht lösen könnte? – Meysam

+0

@Maysam: Sie können 'CREATE STATISTICS' für die Prädikate verwenden, die Sie häufig verwenden. – Quassnoi

3

Es Statistiken verwendet, die es für jeden Index hält.

(Sie können auch Statistiken über nicht-indizierten Spalten erstellen)

in einer Datenbank (WARNUNG auf jedem Tisch alle Ihre Statistiken zu aktualisieren. Wird noch einige Zeit auf sehr große Datenbanken nehmen Sie dies nicht tun auf Produktionsservern, ohne mit Ihrem DBA Überprüfung ...):

exec sp_msforeachtable 'UPDATE STATISTICS ?' 

Wenn Sie Ihre aktivste Indizes (dh viele Einsätze oder Löschungen) keine planmässige Job neu zu erstellen, sollten Sie Ihren Wiederaufbau Indizes (gleicher Vorbehalt wie oben):

exec sp_msforeachtable "DBCC DBREINDEX('?')" 
0

Wiederaufbau Ihrer Indizes möglicherweise die falsche geschätzte Zeilen Wert Problem beheben

Verwandte Themen