Clustered Index Help, wo bin ich falsch gelaufen?

7

Ich wurde gebeten, eine sehr belebte Tabelle zu überprüfen und Verbesserungsmöglichkeiten zu ermitteln.
Ich habe nur sehr begrenzte Möglichkeiten, die Tabelle nur die Indizes zu ändern.

Tabelleninformationen

  • 240 Spalten
  • ~ 5 Millionen Zeilen
  • Gelesen und aktualisiert von etwa 30 Anwendungen, die von Websites bis zu Abfrageanwendungen reichen.
  • Jede Zeile repräsentiert einen Vertrag und seinen Status basierend auf drei Flags (Varchars der Größe 5, 8 und 8).
  • Der Lebenszyklus einer Zeile verläuft von Anfang bis Ende durch diese drei Flags und ist schließlich abgeschlossen.
  • Eine Zeile wird normalerweise 10 bis 30 Mal während dieses Lebenszyklus aktualisiert oder geändert.
  • Der Primärschlüssel ist eine Kombination aus einer ID-Spalte, einer Guid-Spalte und einer Unternehmensspalte.
  • Die Tabelle enthält mehr als 40 Indizes, von denen die meisten doppelt vorhanden und nicht verwendet sind. Dies basiert auf der sys.dm_db_index_usage_statsDMV , die in den letzten 7 Wochen zweimal pro Woche ausgeführt wurde.

Der aktuelle Clustered-Index für diese Tabelle enthält fünf Spalten:

  1. Unternehmensspalte (50 verschiedene Werte)
  2. Regionsspalte (21 verschiedene Werte)
  3. FlagA-Spalte (8 verschiedene Werte)
  4. FlagB-Spalte (24 verschiedene Werte)
  5. FlagC-Spalte (5 verschiedene Werte)

Nach meinem Verständnis sollte ein Clustered-Index den folgenden Eigenschaften entsprechen. Quelle

  1. Einzigartig
  2. Statisch
  3. Eng
  4. Immer größer.

Der aktuelle Clustered-Index ist keiner davon.

  1. Es gibt keine eindeutige ID.
  2. Die drei Flags werden ständig aktualisiert.
  3. Zu jedem Zeitpunkt können 5000 Zeilen vorhanden sein, die für alle 5 Spalten dieselben Werte haben.

Daher ging ich davon aus, dies mit einem Clustered-Index für die IdSpalte zu korrigieren - einer Ganzzahl, die KEINE Identität ist, sondern über eine Zählertabelle verwaltet wird (Wert lesen, 1 hinzufügen, Zählertabelle aktualisieren).

Ich habe einen Clustered-Index für das erstellt Id, ohne den Primärschlüssel zu verwenden, da ich der Meinung war, dass das Hinzufügen der Guid- und Company-Spalte keinen Nutzen bringen würde.

Ich habe dann einen nicht gruppierten Index erstellt, der das Unternehmen, die Region und 3 Flags enthält. In einer Testumgebung sahen die Statistiken gut aus, user_updateswaren niedriger usw. Aber die Gesamtleistung der Anwendungen für diese Tabelle war schrecklich. Die häufigsten Abfragen für diese Tabelle sind:

SELECT * 
FROM table 
WHERE ID = 1234;

Und

SELECT * 
FROM table 
WHERE Company = 'company' 
AND Region = 'region' 
AND flagA= 'A'
AND flagB = 'B'
AND flagC = 'C';
  • Was habe ich vermisst? Gibt es Ausnahmen zu den oben genannten Clustered-Index-Regeln?
  • Würde der Clustered-Index davon profitieren, das Unternehmen und die Region zur ID hinzuzufügen?

Ich verstehe, wenn der Clustered-Index nicht statische Werte enthält, muss er sich selbst und die anderen nicht gruppierten Indizes ständig neu organisieren. Zu diesem Zeitpunkt haben wir noch 40 plus ..., um später entfernt zu werden. Hätte ich dort nicht einen Gewinn gesehen?

Informationen hinzugefügt.

  • Beide Umgebungen sind SQL Server 2008 R2
  • Haben Sie das gleiche Betriebssystem, Speicher usw.
  • Der einzige Unterschied war der Clustered-Index.
  • Ich habe das geschrieben SELECT *, um im obigen Beispiel kurz zu sein.
  • Test- und Produktionsumgebung sind "gleich", so gut sie können: Die Produktion war einer höheren Last ausgesetzt, aber auf beiden wurden dieselben Anwendungen ausgeführt, die Last wurde ausgeglichen usw. Der Test war erheblich langsamer.
  • Wir haben anderthalb Wochen mit dem neuen Cluster gearbeitet, bevor wir zum ursprünglichen Setup zurückgekehrt sind. Zu Beginn wurden die Statistiken aktualisiert und bestimmte gespeicherte Prozesse neu kompiliert, als die langsame Leistung einsetzte.
  • Ich bin damit einverstanden, dass mit dem mehrspaltigen Index zumindest die Tabelle besser organisiert war als nur auf Id. Ich möchte erneut versuchen, Unternehmen, Region und ID als CI zu verwenden, aber die drei Flaggen weglassen.

Was habe ich vermisst?

treeNinja
quelle

Antworten:

3

Gibt es Ausnahmen zu den oben genannten Clustered-Index-Regeln?

Die allgemeinen Richtlinien für die Auswahl eines Clustered-Index sind gut, aber manchmal müssen zusätzliche Überlegungen berücksichtigt werden. Gelegentlich können diese zusätzlichen Faktoren wichtiger sein als die allgemeinen „Regeln“.

Ihr Szenario ist insofern etwas "Besonderes", als Sie eine sehr breite Tabelle mit einer Reihe von Abfragen haben, die eine (vermutlich) unvorhersehbare Menge von Spalten anfordern, obwohl die Abfrageprädikate normalerweise gleich sind.

Die ursprüngliche Clustered-Index-Anordnung war wahrscheinlich teuer für Vorgänge, bei denen Daten geändert werden, da das Ändern eines Teils des Clustering-Schlüssels auch das Ändern aller nicht-Clustered-Indizes bedeutet. Darüber hinaus ist das physische Verschieben ganzer Zeilen im Hinblick auf die Protokollgenerierung kostspielig, insbesondere wenn ein Seitenteilung auftritt.

Das heißt, sobald ein Clustered-Index geändert und ein gutes Stück geteilt wurde, wird er ziemlich viel freien Speicherplatz enthalten, wodurch zukünftige Bewegungen weniger intensiv werden, als ob überhaupt ein vernünftiger Füllfaktor festgelegt und beibehalten worden wäre Teil der normalen Indexpflege.

Es ist wahrscheinlich, dass Ihr Produktionssystem in eine Art Gleichgewicht geraten ist, in dem die Seitenteilung mit einer konstanten, angemessenen Geschwindigkeit erfolgte. Eine nicht gruppierte Indexpflege wäre immer noch relativ teuer, aber es scheint, dass dies kein dominierender Faktor war.

Die entscheidenden Vorteile der ursprünglichen Indexierungsanordnung waren:

  1. Der Clustered-Index (Firma, Region, FlagA, FlagB, FlagC) entspricht dem Prädikat von:

    SELECT {unpredictable column list}
    FROM table 
    WHERE Company = 'company' 
    AND Region = 'region' 
    AND flagA= 'A'
    AND flagB = 'B'
    AND flagC = 'C';

    ... und gleichzeitig Zugriff auf die in der Auswahlliste aufgeführten Spalten gewähren.

  2. Abfragen des Formulars:

    SELECT * 
    FROM table 
    WHERE ID = 1234;

    ... wurden durch den nicht gruppierten Primärschlüssel angemessen unterstützt. Diese Abfrage gibt immer eine einzelne Zeile zurück, sodass nur eine einzelne Suche über den Clustered-Index erforderlich ist, nachdem sich die Zeile im Nonclustered-Index befindet.

Durch das Wechseln zu einem Clustered-Index für IDund einem nicht-Clustered-Index für (Unternehmen, Region, FlagA, FlagB, FlagC) wird die zweite Abfrage etwas effizienter (eine Suche pro Abfrage entfällt), die erste Abfrage jedoch weniger effizient (Null ersetzen) Lookups mit ~ 5000).

Darüber hinaus ist es sehr wahrscheinlich, dass der Optimierer sich dafür entscheidet, den nicht gruppierten Index überhaupt nicht zu verwenden, und schätzt, dass ein vollständiger Scan der Tabelle billiger wäre als die 5000 Suchvorgänge.

Es ist wahrscheinlich besser, die beiden Hauptindizes so zu belassen, wie sie vorerst sind, während Sie die 40 ungeraden nicht gruppierten Indizes sortieren und die Arbeitslast auf die minimale Menge an abdeckenden nicht gruppierten Indizes analysieren, die erforderlich wären. Sobald diese Daten verfügbar sind, können Sie grundlegende Indexierungsänderungen besser berücksichtigen.

Möglicherweise möchten Sie auch die vorhandenen Überwachungs- und Wartungsroutinen für diese Tabelle überprüfen. In vielen Szenarien ist der Clustered-Index, der gegen Regeln verstößt, in Ordnung, wenn der Tabelle ein Füllfaktor zugewiesen wird, der nur eine signifikante Seitenaufteilung verhindert, bevor das nächste Wartungsfenster angezeigt wird.

Paul White 9
quelle