Clustered Index Selection - PK oder FK?


11

Ich habe eine SQL Server 2014- Tabelle, die wie folgt aussieht:

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

Einige Leute in meinem Team haben vorgeschlagen, dass der Clustered-Index aktiviert sein sollte OrderId, aber ich denke, dass das CustomerId+ OrderIdaus folgenden Gründen eine bessere Wahl wäre:

  • Fast alle Anfragen werden gesucht WHERE CustomerId = @param, nichtOrderId
  • CustomerIdist ein Fremdschlüssel für die CustomerTabelle, daher sollte ein Clustered-Index mit die CustomerIdVerknüpfungen beschleunigen
  • Obwohl dies CustomerIdnicht eindeutig ist, wird durch die OrderIdAngabe der zusätzlichen Spalte im Index die Eindeutigkeit sichergestellt. (Wir können das UNIQUESchlüsselwort beim Erstellen des Clustered-Index für diese beiden Spalten verwenden, um den Aufwand zu vermeiden, dass keine Eindeutigkeit vorliegt.)
  • Sobald Daten eingefügt wurden, ändern sich die CustomerIdund OrderIdnie mehr, sodass sich diese Zeilen nach dem ersten Schreiben nicht mehr bewegen.
  • Der Datenzugriff erfolgt über ein ORM, das standardmäßig alle Spalten anfordert. Wenn also eine Abfrage basierend auf CustomerIdeingeht, kann der Clustered-Index alle Spalten ohne zusätzliche Arbeit bereitstellen.

Klingt der CustomerIdund OrderId-Ansatz nach der oben genannten Option am besten? Oder ist es OrderIdfür sich genommen besser, da es sich um eine einzelne Spalte handelt, die die Einzigartigkeit von sich aus garantiert?

Derzeit hat die Tabelle einen Clustered-Index OrderIdund einen nicht-Clustered-Index CustomerId, der jedoch nicht behandelt wird. Da wir also ein ORM verwenden und alle Spalten angefordert werden, ist es zusätzliche Arbeit, sie abzurufen. Mit diesem Beitrag versuche ich, die Leistung mit einem besseren CI zu verbessern.

Die Aktivität in unserer Datenbank beträgt ca. 85% Lese- und 15% Schreibvorgänge.

Antworten:


5

Antwort des Community-Wikis :

Ich denke, ein zusammengesetzter Clustered-Indexschlüssel mit CustomerID als erster Spalte ist am besten geeignet, da dies in der WHEREKlausel fast aller Abfragen enthalten ist.

Im Vergleich zu einem inkrementellen Schlüssel kann es zu mehr Teilungen kommen (oder wahrscheinlich zu einer zeitlich suboptimalen Seitendichte, wenn Sie den Füllfaktor verwalten und beibehalten , um "schlechte" Teilungen zu vermeiden). Die allgemeine Leistungsverbesserung bei Kundenanfragen ist jedoch erheblich, da die Schlüsselsuche vermieden wird.

OrderID oder OrderDate eignen sich je nach Ihren kritischsten Abfragen möglicherweise am besten für die zweite Spalte.

Wenn Kunden beispielsweise nach dem Anmelden auf einer Website eine chronologische Liste der letzten Bestellungen sehen, sollte OrderDate als Nächstes angezeigt werden, um die Optimierung zu optimieren ORDER BY OrderDate DESC.

Wenn Sie OrderID als Clustered-Index mit einem nicht-Clustered-Index für CustomerID auswählen , werden Splits und Fragmentierungen nur im nicht-Clustered-Index angezeigt.


3

Wenn diese Tabelle stark schreibintensiv ist (z. B. INSERTtreten viel mehr Aussagen auf als SELECTAussagen dagegen), werde ich der Wiki-Antwort nicht zustimmen .

Wenn Sie CustomerID als erste Spalte eines zusammengesetzten Clusterschlüssels auswählen, werden viele Teilungen auf der Mitte der Seite generiert . Sie haben hoffentlich viele bestehende Kunden und bekommen auch ständig viele neue Kunden. Da Kunden (hoffentlich) mehrere Bestellungen aufgeben, während Ihr Unternehmen weiter wächst, weist dieser Ansatz eine ganze Reihe von Mid-Page-Splits auf, die die Leistung nicht nur beim Schreiben, sondern auch beim Lesen beeinträchtigen, da Ihre Indizes stark fragmentiert sind und wahrscheinlich höhere Mengen an Leerraum enthalten (was bedeutet, dass Speicherplatz und Speicher verschwendet werden).

Wenn Sie der Meinung sind, dass CustomerID eine führende Spalte eines zusammengesetzten Clustered-Index sein sollte, können Sie die Auswirkungen der Aufteilung FILLFACTORauf die mittlere Seite verringern, indem Sie alle Indizes für diese Tabelle anpassen . Dadurch wird die Anzahl der Teilungen in der Mitte der Seite verringert, indem die Größe der Tabelle / des Index erhöht wird. Wenn Sie diesen Weg gehen möchten, würde ich vorschlagen, mit einem Wert von 80 zu testen und zu reduzieren, wenn die Analyse ergibt, dass Splits in der Mitte der Seite immer noch die Leistung beeinträchtigen.

Mein Vorschlag ist, OrderId zu verwenden. OrderID sollte natürlich sequentiell sein und mehr End-Page-Splits generieren, die gut sind und mit dem Tabellenwachstum erwartet werden. Darüber hinaus eignet sich dieser Ansatz besser für die Tabellenpartitionierung, wenn Sie die OrderDate-Spalte als Partitionsschlüssel verwenden. Erstellen Sie für Abfragen, die ständig das Feld CustomerID verwenden, einen nicht gruppierten Index, um diese Abfragen zu verarbeiten. Dieser Index müsste mit dem richtigen Index definiert werden, FILLFACTORda er unter den oben erwähnten Teilungen in der Mitte der Seite leidet, obwohl diese insgesamt nicht so schlecht sind, im Gegensatz dazu, wenn die Teilungen gegenüber dem Clustered-Index auftreten würden.

Die Aktivität in unserer Datenbank beträgt ca. 85% Lese- und 15% Schreibvorgänge.

CustomerID+ OrderID(und die Angabe eines Füllfaktors, um Wachstum ohne Spaltungen zu ermöglichen) ist wahrscheinlich besser, wenn diese Einschätzung zutrifft. Stellen Sie einfach sicher, dass die Bewertung korrekt ist. Test Test Test.


1
Beachten Sie, dass das Einfügen einer Bestellung für den letzten (oder einzigen) Kunden auf einer Seite kein "Mid-Page-Split" ist. Wenn also die Bestellungen pro Kunde hoch oder die Zeilenbreite groß sind, erfordern weniger Auftragsbeilagen "mittlere Seitenaufteilungen".
David Browne - Microsoft
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.