SELECT TOP 1 aus einer sehr großen Tabelle in einer Indexspalte ist sehr langsam, jedoch nicht in umgekehrter Reihenfolge ("desc")

16

Wir haben eine große Datenbank (ca. 1 TB), in der SQL Server 2014 auf einem leistungsstarken Server ausgeführt wird. Für ein paar Jahre hat alles gut funktioniert. Vor ungefähr 2 Wochen haben wir eine vollständige Wartung durchgeführt, die Folgendes beinhaltete: Alle Software-Updates installieren; Erstellen Sie alle Indizes und kompakten DB-Dateien neu. Wir hatten jedoch nicht erwartet, dass die CPU-Auslastung der DB zu einem bestimmten Zeitpunkt um über 100% auf 150% anstieg, wenn die tatsächliche Auslastung gleich war.

Nach einer Menge Fehlerbehebung haben wir es auf eine sehr einfache Abfrage eingegrenzt, aber wir konnten keine Lösung finden. Die Abfrage ist denkbar einfach:

select top 1 EventID from EventLog with (nolock) order by EventID

Es dauert immer ca. 1,5 Sekunden! Eine ähnliche Abfrage mit "desc" dauert jedoch immer ungefähr 0 ms:

select top 1 EventID from EventLog with (nolock) order by EventID desc

PTable hat ungefähr 500 Millionen Zeilen; EventIDist die primäre gruppierte ASCIndexspalte ( geordnet ) mit dem Datentyp bigint (Identitätsspalte). Es gibt mehrere Threads, die Daten in die Tabelle oben einfügen (größere EventIDs), und es gibt einen Thread, der Daten von unten löscht (kleinere EventIDs).

In SMSS haben wir überprüft, dass die beiden Abfragen immer denselben Ausführungsplan verwenden:

  • Clustered Index Scan;

  • Geschätzte und tatsächliche Zeilennummern sind beide 1;

  • Geschätzte und tatsächliche Anzahl der Hinrichtungen sind beide 1;

  • Geschätzte I / O-Kosten sind 8500 (scheint hoch zu sein)

  • Bei fortlaufender Ausführung betragen die Abfragekosten für beide die gleichen 50%.

Ich habe die Indexstatistik aktualisiert with fullscan, das Problem blieb bestehen. Ich habe den Index erneut erstellt, und das Problem schien einen halben Tag lang nicht mehr zu bestehen, kam aber zurück.

Ich habe die E / A-Statistik aktiviert mit:

set statistics io on

Dann wurden die beiden Abfragen nacheinander ausgeführt und die folgenden Informationen gefunden:

(Für die erste Abfrage, die langsame)

Tabelle 'PTable'. Scan-Anzahl 1, logische Lesevorgänge 407670, physische Lesevorgänge 0, Vorauslesevorgänge 0, logische Lobs-Lesevorgänge 0, physische Lobs-Vorauslesevorgänge 0.

(Für die zweite Frage, die schnelle)

Tabelle 'PTable'. Scananzahl 1, logische Lesevorgänge 4, physische Lesevorgänge 0, Vorauslesevorgänge 0, logische Lobs-Lesevorgänge 0, physikalische Lobs-Lesevorgänge 0, Lobs-Vorauslesevorgänge 0.

Beachten Sie den großen Unterschied bei den logischen Lesevorgängen. Der Index wird in beiden Fällen verwendet.

Indexfragmentierung könnte ein wenig erklären, aber ich glaube, die Auswirkung ist sehr gering. und das Problem ist noch nie passiert. Ein weiterer Beweis ist, wenn ich eine Abfrage wie folgt ausführe:

select * from EventLog with (nolock) where EventID=xxxx   

Auch wenn ich xxxx auf die kleinsten EventIDs in der Tabelle gesetzt habe, ist die Abfrage immer blitzschnell.

Wir haben es überprüft und es gibt kein Problem mit dem Sperren / Sperren.

Hinweis: Ich habe gerade versucht, das Problem oben zu vereinfachen. Die "PTable" ist eigentlich "EventLog"; das PIDist EventID.

Ich bekomme das selbe Testergebnis ohne den NOLOCKHinweis.

Kann jemand helfen?

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Detailliertere Abfrageausführungspläne in XML wie folgt:

https://www.brentozar.com/pastetheplan/?id=SJ3eiVnob

https://www.brentozar.com/pastetheplan/?id=r1rOjVhoZ

Ich denke nicht, dass es wichtig ist, die Anweisung create table bereitzustellen. Es ist eine alte Datenbank und läuft seit langer Zeit bis zur Wartung einwandfrei. Wir haben selbst viel recherchiert und es auf die in meiner Frage angegebenen Informationen eingegrenzt.

Die Tabelle wurde normalerweise mit der EventIDSpalte als Primärschlüssel erstellt, bei der es sich um eine identityTypspalte handelt bigint. Zu diesem Zeitpunkt liegt das Problem vermutlich bei der Indexfragmentierung. Unmittelbar nach der Indexwiederherstellung schien das Problem einen halben Tag lang nicht mehr zu bestehen. aber warum kam es so schnell zurück ...?

TiffanyP
quelle

Antworten:

17

Der Clustered Index Scan zeigt 423.723 logische Lesevorgänge an, um die erste Zeile zurückzugeben, was 1926 ms dauert:

NÜSSE

Dies scheint ziemlich viel zu sein, um die erste Zeile in der Indexreihenfolge zu lokalisieren.

Höchstwahrscheinlich ist Ihre Ghost-Bereinigungsaufgabe weit hinterhergelaufen oder wurde gestoppt. Sie sollten ghost_record_countden Clustered-Index einchecken sys.dm_db_index_physical_statsund Änderungen im Zeitverlauf überwachen.

Die geordnete Suche ab dem Ende des Index, bei der eine konstante Löschaktivität festgestellt wird, muss eine Vielzahl von Geisterdatensätzen durchsuchen, bevor die erste "lebendige" Zeile gefunden wird, die zurückgegeben wird. Dies erklärt die zusätzlichen logischen Lesevorgänge. Beim Durchsuchen des B-Baums bis zum niedrigsten Wert des Index werden viel weniger Geisterbilder angezeigt.

Ein weiterer leistungsbeeinträchtigender Faktor besteht darin, dass der Scan selbst für das Entfernen der Geisteraufzeichnungen verantwortlich ist, wie in Inside the Storage Engine: Geisterbereinigung von Paul Randal beschrieben.

Sie sollten überprüfen, ob das Ablaufverfolgungsflag 661 (Deaktivieren der Geisterbereinigung) nicht aktiv ist.

Lösungen

Wenn die Ghost-Bereinigung vollständig gestoppt wurde, besteht die effektivste Lösung normalerweise darin, die SQL Server-Instanz neu zu starten. Sie sollten auch sicherstellen, dass auf dem SQL Server eines der neuesten kumulativen Updates ausgeführt wird. Im Laufe der Jahre gab es viele Fehler bei der Bereinigung von Geistern.

In Ihrem speziellen Fall:

Es stellte sich heraus, dass das Problem durch eine andere Testdatenbank auf demselben Server verursacht wurde. Diese Testdatenbank wurde mit "Datenverlust" wiederhergestellt und ist beschädigt. Überraschenderweise steckte der Prozess der Geisterbereinigung anscheinend in dieser Datenbank fest. Nachdem wir diese beschädigte Datenbank aus SMSS gelöscht hatten, löste sich das Problem von selbst (es dauerte lange und führte möglicherweise dazu, dass die Datenbank für kurze Zeit abstürzte).

Paul White sagt GoFundMonica
quelle