Database
 sql >> Datenbank >  >> RDS >> Database

Ein Ansatz zum Index-Tuning – Teil 2

In meinem letzten Beitrag habe ich damit begonnen, den Prozess zu skizzieren, den ich beim Optimieren von Abfragen durchlaufe – insbesondere, wenn ich feststelle, dass ich einen neuen Index hinzufügen oder einen vorhandenen ändern muss. Bis zu diesem Punkt haben wir die problematische Abfrage, den Index, den ich benötige, identifiziert, welche Indizes derzeit in der Tabelle vorhanden sind und ob diese Indizes verwendet werden oder nicht. Sobald wir diese Daten haben, können wir mit den nächsten Schritten im Prozess fortfahren.

Schritt 5:Was verwendet einen Index

Neben der Anzeige, wie oft ein Index verwendet wird (oder nicht), ist es von Vorteil zu wissen, welche Suchanfragen ausgeführt werden Verwenden Sie einen Index, insbesondere wenn ich ihn mit einem anderen Index zusammenführen möchte. Glücklicherweise hat Jonathan Kehayias bereits eine Abfrage geschrieben, um zu ermitteln, welche Pläne einen bestimmten Index verwenden. Seine Version kann für den Plan-Cache verwendet werden – die einzige Herausforderung besteht darin, dass die Informationen vorübergehend sind, sodass Sie möglicherweise nicht jede Abfrage erfassen, die einen bestimmten Index verwendet. Query Store kann dabei helfen – ich habe seine Abfrage geändert, um dieselben Informationen aus den Plänen im Query Store zu erhalten:

  SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
  DECLARE @IndexName AS NVARCHAR(128) = N'[IX_Sales_OrderLines_AllocatedStockItems]',
          @lb AS nchar(1) = N'[', @rb AS nchar(1) = N']';
 
  -- Make sure the name passed is appropriately quoted
  IF (LEFT(@IndexName, 1) <> @lb AND RIGHT(@IndexName, 1) <> @rb) SET @IndexName = QUOTENAME(@IndexName);
 
  --Handle the case where the left or right was quoted manually but not the opposite side
  IF LEFT(@IndexName, 1)  <> @lb SET @IndexName = @rb + @IndexName;
  IF RIGHT(@IndexName, 1) <> @rb SET @IndexName = @IndexName + @rb;
 
  ;WITH XMLNAMESPACES (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')   
  SELECT
    stmt.value('(@StatementText)[1]', 'varchar(max)') AS SQL_Text,
    obj.value('(@Database)[1]', 'varchar(128)') AS DatabaseName,
    obj.value('(@Schema)[1]', 'varchar(128)') AS SchemaName,
    obj.value('(@Table)[1]', 'varchar(128)') AS TableName,
    obj.value('(@Index)[1]', 'varchar(128)') AS IndexName,
    obj.value('(@IndexKind)[1]', 'varchar(128)') AS IndexKind,
    query_plan
  FROM 	
  (
    SELECT query_plan
    FROM
    (
      SELECT TRY_CONVERT(XML, [qsp].[query_plan]) AS [query_plan]
      FROM sys.query_store_plan [qsp]
    ) tp
  ) AS tab (query_plan)
  CROSS APPLY query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt)
  CROSS APPLY stmt.nodes('.//IndexScan/Object[@Index=sql:variable("@IndexName")]') AS idx(obj)
  OPTION(MAXDOP 1, RECOMPILE);

Es ist erwähnenswert, dass dies ein weiterer Punkt ist, an dem ich mich sehr tief in einem Kaninchenbau wiederfinden kann, abhängig von der Anzahl der Indizes, die ich überprüfe, und der Anzahl der Abfragen, die sie verwenden. Wenn möglich, werde ich auch Ausführungszahlen (aus dem Abfragespeicher oder dem Plan-Cache) berücksichtigen, um nicht nur zu verstehen, was Abfrage einen Index verwendet, aber wie oft diese Abfrage ausgeführt wird. Hier wird Index-Tuning zur Kunst. Ich kann eine lächerliche Menge an Daten sammeln … aber ich habe nicht unendlich Zeit für Analysen, also muss ich entscheiden, wie viele Anfragen ich überprüfen werde.

Schritt 6:Testen

Im einfachsten Fall bedeutet das Testen eines Index, die problematische Abfrage zu nehmen und die Plan- und Leistungsdaten (Dauer, E/A, CPU usw.) zu erfassen und dann den Index zu erstellen, die Abfrage erneut auszuführen und dieselben Informationen zu erfassen. Wenn sich die Leistung verbessert, können Sie loslegen!

So einfach ist es selten.

Am Anfang habe ich oft mindestens zwei Variationen eines Indexes, die ich testen möchte, manchmal auch mehr. Ich beginne mit meiner Baseline, dann erstelle ich alle Indexvariationen, lösche den Plan-Cache und schaue, was SQL Server auswählt. Dann gehe ich durch und erzwinge jeden Index mit einem Hinweis, wobei ich den Plan und die Leistungskennzahlen für jede Ausführung erfasse. Hinweis:Dies setzt voraus, dass ich genügend Speicherplatz für alle Indizes habe. Wenn nicht, erstelle ich sie einzeln und teste sie. Zum Schluss vergleiche ich die Zahlen. Wenn ich nur einen neuen Index hinzufüge, bin ich fast fertig. Aber wenn ich einen Index ändere oder mehrere zusammenführe, kann es kompliziert werden.

In einer idealen Welt finde ich, wenn ich einen vorhandenen Index ändere, die häufigsten/wichtigsten Abfragen, die den aktuellen Index verwenden, und erhalte ihre Pläne und Leistungsmetriken (das ist mit Query Store einfach). Dann ändere ich den Index, führe alle diese Abfragen erneut aus und sehe, ob ich signifikante Änderungen in der Form und/oder Leistung des Plans erhalte.

Wenn ich zwei Indizes zusammenführe, mache ich dasselbe, aber mit allen Abfragen, die einen der beiden Indizes verwenden, und teste dann erneut mit dem zusammengeführten Index.

Wenn ich mehrere Indizes für eine Tabelle hinzufüge/ändere/zusammenführe, muss ich alle relevanten Abfragen und ihre Pläne und Metriken abrufen, die Indizes ändern, dann alle Informationen erneut abrufen und vergleichen. Dies kann sehr zeitaufwändig sein, je nachdem, wie viele unterschiedliche Abfragen es gibt. Hier ist es eine Kunstform und Sie müssen bestimmen, wie viele Abfragen Sie wirklich testen müssen. Es ist eine Funktion der Häufigkeit der Ausführung, der Wichtigkeit/Relevanz der Abfrage und der Zeit, die mir zur Verfügung steht/zugewiesen wurde.

Wenn ich schließlich einen Index zu einer Tabelle hinzufüge und keine vorhandenen entferne, dann habe ich Overhead für INSERTs, DELETEs und möglicherweise UPDATEs hinzugefügt. Leistungstests dieser Änderung sind möglich, aber Sie benötigen eine Testumgebung und die Möglichkeit, einen Lasttest durchzuführen und Metriken vor und nach der Änderung in Bezug auf Dauer, E/A und CPU zu erfassen.

Es sind viele Freunde, weshalb es ironisch ist, dass ich anfangs darüber nachdachte, zu sagen, dass das Index-Tuning einfach sei. Es ist vielleicht nicht immer einfach, aber es ist möglich. Es ist eine Frage der Sorgfalt und des Überblicks.

Schritt 7:Implementierung

Nachdem ich die neuen Indizes so gut wie möglich überprüft habe, sind wir bereit für die Produktion. Ich gebe zu, dass ich Indexänderungen als geringes Risiko ansehe, insbesondere neue. Wenn es ein Problem gibt, können Sie es sofort löschen und zum ursprünglichen Zustand zurückkehren. Bei einem Änderungs-/Zusammenführungs-/Löschszenario möchten Sie alles skriptgesteuert haben, damit Sie Indizes nach Bedarf ändern und neu erstellen können, um die Indizes zurückzusetzen. Ich empfehle immer, Indexe zunächst zu deaktivieren, anstatt sie zu löschen, da Sie sich dann nicht um die Definition kümmern müssen – wenn Sie den Index wieder hinzufügen müssen, bauen Sie ihn einfach neu auf.

Zusammenfassung

Ihre Methode zum Hinzufügen und/oder Konsolidieren von Indizes kann anders sein! Genau wie bei der Abfrageoptimierung gibt es keinen perfekten Prozess. Für alle, die neu in der Indexoptimierung sind, bietet dies hoffentlich einen Einstieg in die Punkte, die überprüft werden müssen, und wichtige Überlegungen. Es ist unmöglich, Indizes hinzuzufügen, ohne einen gewissen Overhead hinzuzufügen – und hier kommt wieder die Kunst ins Spiel:Sie müssen feststellen, ob der Nutzen des Index die Kosten für Änderungen aufwiegt.

Index-Tuning ist ein fortwährender, iterativer Prozess – ich glaube nicht, dass Sie jemals fertig sind, weil sich Code ändert, neue Tabellen oder Funktionen hinzugefügt werden und Daten in den Tabellen sich ändern. Kimberly hat zwei Beiträge (https://www.sqlskills.com/blogs/kimberly/spring-cleaning-your-indexes-part-i/ und https://www.sqlskills.com/blogs/kimberly/spring-cleaning- your-indexes-part-ii/), die über das Bereinigen Ihrer Indizes sprechen – jetzt ist die beste Zeit, um loszulegen! Und schließlich, wenn jemand fragt:"Wie viele Indizes sollte es für eine Tabelle geben?" Ich antworte mit etwas wie:„Die niedrigste Zahl, die Sie brauchen, um so viele Anfragen wie möglich zu beantworten.“ Es gibt keine magische Zahl – ich habe Tabellen mit Null-Indizes gesehen, und ich habe Tabellen mit über 100 gesehen (ich bin sicher, einige von Ihnen haben höhere Zahlen gesehen). Weder null noch 100 ist gut, aber die „richtige“ Zahl müssen Sie anhand der verfügbaren Daten und Ihrer Erfahrung herausfinden.