Gibt es eine Möglichkeit, festzustellen, ob SQL Server-Abfragen im Arbeitsspeicher ausgeführt werden oder auf die Festplatte gehen?

13

Ich bin heute auf eine Reihe gespeicherter Prozeduren in einer Anwendung gestoßen, die innerhalb eines langen Prozesses wiederholt aufgerufen werden. Innerhalb jeder Prozedur fand ich mehrere verschiedene select-Anweisungen, einige innerhalb von Schleifen; Es überrascht nicht, dass die Ausführung dieser Routinen, wie sie derzeit verwendet werden, einige Minuten dauert, wenn die Intuition erwartet, dass sie in wenigen Sekunden abgeschlossen sind.

Es scheint ziemlich offensichtlich, dass die Leistung nicht berücksichtigt wurde, als diese Prozeduren geschrieben wurden. Es gibt mehrere Instanzen von Dingen, die einfach "keine gute Idee" sind.

Die Verarbeitung jeder Zeile beim Importieren von Daten dauert 300 ms pro Zeile, sodass relativ kleine Importe mehrere Minuten in Anspruch nehmen.

Die an den Verfahren beteiligten Tabellen sind jedoch größtenteils recht klein. Ich denke, wenn alle diese Tabellen vollständig im Arbeitsspeicher gespeichert sind, kann möglicherweise nicht so viel erreicht werden, wenn Sie irgendetwas davon umschreiben.

Ich versuche herauszufinden ... wie stark wirkt sich dieser offensichtlich ineffiziente Code wirklich aus? Lohnt es sich zu reparieren?

Die Frage ist also:
- Gibt es eine Möglichkeit, festzustellen, welche Tabellen vollständig im Speicher abgelegt sind?
- Gibt es eine Möglichkeit, die Ablaufverfolgung zu aktivieren, um verschachtelte gespeicherte Prozeduren zu überwachen, um die besonders teuren Teile zu finden?

Hinweis: Dies ist auf SQL Server 2008 R2

tbone
quelle

Antworten:

12

Sie können eine dieser beiden Abfragen verwenden, um die gesamten logischen Lesevorgänge und die gesamten physischen Lesevorgänge anzuzeigen.

SELECT  DB_NAME(st.dbid) Db,
        OBJECT_NAME(st.objectid, st.dbid) Prc,
        qs.execution_count,
        qs.total_logical_reads,
        qs.total_physical_reads,
        qs.statement_start_offset,
        qs.statement_end_offset,
        st.text
FROM    sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st;

SELECT  DB_NAME(database_id) Db,
        OBJECT_NAME(object_id, database_id) Prc,
        execution_count,
        total_logical_reads,
        total_physical_reads
FROM    sys.dm_exec_procedure_stats ps;

Der erste zerlegt dies nach Aussage, der zweite zählt im gesamten Verfahren.

Physische Lesevorgänge beziehen sich auf die Festplatte, logische Lesevorgänge auf den Speicher. Auf diese Weise können Sie herausfinden, welche Prozeduren oder Anweisungen in Ihrem System am teuersten sind, und versuchen, diese zu optimieren.

Denken Sie daran, dass logische Lesevorgänge zwar erheblich billiger als physische Lesevorgänge sind, sie jedoch immer noch teuer. Wenn Sie also die Anzahl der Lesevorgänge verringern (z. B. durch Hinzufügen eines entsprechenden Index), können Ihre Abfragen erheblich schneller ausgeführt werden.

Es gibt viele zusätzliche Spalten in den DMVs darüber, die Sie vielleicht auch interessieren.


Wie hilft ein Index, logische Lesevorgänge zu reduzieren?

In SQL Server sind alle Daten in Blöcken mit einer Größe von 8 KB organisiert. Diese Blöcke werden "Seiten" genannt.

Jede Tabelle enthält "Meta" -Seiten, die Informationen zur Struktur der Tabelle enthalten, sowie Pata-Seiten. Wenn kein Index vorhanden ist und Sie eine Abfrage wie SELECT * FROM tbl WHERE Id = 7SQL Server ausführen , müssen Sie nach dieser oder diesen Zeilen in der gesamten Tabelle suchen. Es liest also jeweils eine Seite nach der anderen und durchläuft alle Zeilen auf jeder Seite, um die Zeilen zu bestimmen, die in die WHEREKlausel passen . Wenn für die Tabelle 1.000.000 Seiten gespeichert werden müssen, erfordert diese Abfrage 1.000.000 logische Lesevorgänge.

Wenn Sie einen Index haben, sortiert SQL Server die Daten logisch innerhalb der Seiten und erstellt eine verknüpfte Liste zwischen den Seiten. Auf diese Weise können Abfragen ORDER BYausgeführt werden, ohne dass eine teure Sortieroperation erforderlich ist. Wichtig ist jedoch, dass SQL Server beim Sortieren der Tabelle einen B + Tree hinzufügt . Ein B + Tree ist eine Struktur, die mit dem Index in einem Buch vergleichbar ist. Durch die Suche nach einem bestimmten Schlüsselwort kann ich direkt zu der Seite springen, die das Schlüsselwort enthält. Das typische Buch hat nur eine Indexstufe, während ein B + Tree mehrere haben kann. Stellen Sie sich ein großes Buch vor, in dem der Index selbst mehrere Seiten umfasst. In einem solchen Fall ist es sinnvoll, eine zusätzliche Indexebene hinzuzufügen, die angibt, auf welcher Seite die Indexwörter Szu finden sind, die mit beginnen .

B + Trees sind so optimiert, dass sie so wenige Ebenen wie möglich haben. Gleichzeitig wird die Eigenschaft bereitgestellt, dass jeder Datensatz im Index gefunden werden kann, indem eine Seite pro Indexebene gelesen wird. WHERE Id = 7Nehmen Sie also die obige Abfrage an, wenn Sie einen Index haben, der nach sortiert ist Id. Angenommen, der Index hat 5 Ebenen. Um nun alle Datensätze zu finden, die dieser Abfrage entsprechen, muss ich eine Seite pro Indexebene (das sind 5 Seiten) lesen. Dies wird als "Indexsuche" bezeichnet. Wenn mehrere Datensätze zur Rechnung passen, muss ich möglicherweise eine Weile dem sortierten Index folgen, um alle abzurufen. Nehmen wir jedoch an, dass es nur einen Datensatz gibt.

Ohne den Index, der diese Abfrage ausführt, waren 1.000.000 Lesevorgänge erforderlich, mit indes waren 5 Lesevorgänge erforderlich. Auch wenn ein logischer Lesevorgang ein Vorgang im Speicher ist, sind die Kosten dennoch beträchtlich. Tatsächlich ist er der teuerste Vorgang in einer einfachen Abfrage wie der oben beschriebenen. Wenn Sie also die Anzahl der erforderlichen logischen Lesevorgänge um den Faktor 200.000 verringern, wird Ihre Abfrage um einen ähnlichen Faktor beschleunigt.

Ein logischer Lesevorgang entspricht also nicht einem Tabellenscan, aber ein Tabellenscan führt zu sehr viel mehr logischen Lesevorgängen als eine Indexsuche.

Sebastian Meine
quelle
> "Wenn Sie die Anzahl der Abfragen verringern (z. B. durch Hinzufügen eines entsprechenden Index), können Ihre Abfragen viel schneller ausgeführt werden." Können Sie erklären, wie das Hinzufügen eines Indexes die Anzahl der logischen Lesevorgänge verringert? Ist logisches Lesen gleichbedeutend mit einem Tabellenscan?
1
Fügte eine Erklärung zu meiner Antwort oben hinzu.
Sebastian Meine
Vielen Dank. Selbst wenn für alle betroffenen Tabellen richtige Indizes vorliegen ... Ich denke, es gibt immer noch einen großen Leistungsunterschied zwischen einer Tabelle, die im Arbeitsspeicher festgehalten ist, und dem Lesen von der Festplatte (in beiden Szenarien werden dieselben Indizes angenommen) ... oder in anderen Mit anderen Worten: Wenn Sie Indizes hinzufügen, erzielen Sie auf einem Computer mit viel RAM weniger Leistungssteigerungen als auf einem Computer mit weniger Arbeitsspeicher. Richtig?
1
Der physische Festplattenzugriff ist eindeutig um Größenordnungen teurer als der Speicherzugriff. Wenn Sie also Maßnahmen ergreifen, um dies zu vermeiden, werden Sie sehr weit kommen. Sie sollten immer noch zuerst die Anzahl der logischen Lesevorgänge prüfen, wenn Sie die Abfrage optimieren. Wenn Sie sie niedrig halten, bleiben die physischen Messwerte niedrig. Es besteht auch eine hohe Wahrscheinlichkeit, dass Seiten nicht aus dem Cache entfernt werden müssen, wodurch die erforderlichen physischen Lesevorgänge noch weiter reduziert werden.
Sebastian Meine
2
Kleiner Trottel - ich denke Seiten sind 8kb :-). Gute Antwort.
onupdatecascade
3
  • Gibt es eine Möglichkeit, die Ablaufverfolgung zu aktivieren, um verschachtelte gespeicherte Prozeduren zu überwachen, um die besonders teuren Teile zu finden?

Sie können SQL Profiler verwenden. Wenn Sie den Trace starten, sollten Sie RPC Completed, SP Starting, SP StmtStarting und SP StmtCompleted auswählen (siehe Abbildung unten).

Bildbeschreibung hier eingeben

Auf diese Weise können Sie jede Abfrage anzeigen, die in gespeicherten Prozeduren ausgeführt wird. Sie können sehen, wie oft eine verschachtelte gespeicherte Prozedur aufgerufen wird. Wenn der Trace beendet ist, sollten Sie ihn speichern. Öffnen Sie es dann erneut. Anschließend können Sie (mit der Schaltfläche "Spaltenfilter") filtern, um die Abfragen zu finden, die Ihr Problem verursachen. (Beispiel: die Abfragen, die mehr als x Lesevorgänge oder mehr als x Sekunden dauerten (Dauer) ...)

Die von mir gezeigten Profiler-Optionen zeigen auch den Ausführungsplan, was auch sehr hilfreich ist.

Danielle Paquette-Harvey
quelle
1

Es scheint eine allgemeine Frage zur Abfrageoptimierung zu sein. Nach Ihrer Beschreibung würde ich:

  1. Überprüfen Sie den Code, um festzustellen, ob er zeilenweise verarbeitet wird. Wenn dies der Fall ist, können oftmals Größenordnungen verbessert werden, indem dieselbe Logik unter Verwendung von Mengen implementiert wird (mehrere Zeilen werden gleichzeitig verarbeitet). Mit anderen Worten, wenn es sich wie "Schleife über jede Zeile" verhält, ändern Sie es in "Alle Zeilen verarbeiten". SQL zeichnet sich dadurch aus, dass das Optimierungsprogramm aus mehr möglichen Methoden auswählen kann, möglicherweise Parallelität verwendet und viel Overhead, der von einer Zeile nach der anderen stammt , entfernt .
  2. Stellen Sie als nächstes sicher, dass es Indizes gibt, die die Arbeit unterstützen. Oftmals kann eine Verbesserung um Größenordnungen mit korrekten Indizes erzielt werden, während dies nicht der Fall ist. Dies gilt sowohl für den Arbeitsspeicher als auch für den Festplattenzugriff. Prozesse können mit allem im RAM noch Stunden dauern, wenn für einen großen Datensatz keine geeigneten Indizes vorhanden sind.
  3. Als nächstes würde ich mit festgelegter Logik und Indizes prüfen, ob die betroffenen Datenseiten in den Speicher passen. An diesem Punkt ist es sinnvoll, die physischen Lesevorgänge und die Festplattenaktivität zu betrachten, wenn immer noch viel Festplattenzugriff besteht, da alle großen Optimierungsvorteile in den ersten beiden Schritten erzielt werden.
onupdatecascade
quelle