2008-11-10 2 views
29

Ich arbeite an einer Datenbank, die in der Regel GUIDs als Primärschlüssel verwendet.Sollte ich Clustered-Indizes auf Guid-Spalten loswerden

Standardmäßig platziert SQL Server einen Clustered-Index für Primärschlüsselspalten. Ich verstehe, dass dies eine dumme Idee für GUID-Spalten ist und dass nicht gruppierte Indizes besser sind.

Was denkst du - sollte ich alle Clustered-Indizes loswerden und sie durch nicht gruppierte Indizes ersetzen?

Warum würde SQL Performance Tuner dies nicht als Empfehlung anbieten?

+0

Werfen Sie einen Blick auf den folgenden Beitrag von Paul Randal. [Clustered oder Nonclustered-Index für eine zufällige GUID?] (Http://www.sqlskills.com/blogs/paul/clustered-or-nonclustered-index-on-a-random-guid/) – Lijo

Antwort

25

Ein großer Grund für einen gruppierten Index ist, wenn Sie häufig Zeilen für einen Bereich von Werten für eine bestimmte Spalte abrufen möchten. Da die Daten physisch in dieser Reihenfolge angeordnet sind, können die Zeilen sehr effizient extrahiert werden.

So etwas wie eine GUID, die zwar hervorragend für einen Primärschlüssel ist, kann sich jedoch positiv auf die Leistung auswirken, da zusätzliche Kosten für die Einsätze und kein spürbarer Vorteil für die Auswahlen entstehen.

Also ja, Cluster nicht einen Index auf GUID.

Warum es nicht als Empfehlung angeboten wird, würde ich vorschlagen, der Tuner ist sich dieser Tatsache bewusst.

+2

Mit SQL 2005 und newsequentialid() verschwindet das Fragmentierungsproblem weitgehend. Am besten messen Sie mit sys.dm_db_index_physical_stats und sys_indexes. – RoadWarrior

+0

Sie erhalten jedoch immer noch keinen Vorteil in Ihren Abfragen. Sie sollten nur auf "UNIQUEIDENTIFIER" clustern, wenn Sie, z.B. für die Replikation. –

4

Das Problem mit Clustered-Indizes in einem GUID-Feld sind, dass die GUIDs zufällig sind. Wenn ein neuer Datensatz eingefügt wird, muss daher ein erheblicher Teil der Daten verschoben werden, um die Datensätze in die Mitte der Tabelle einzufügen .

Bei Ganzzahl-Clustered-Indizes sind die Ganzzahlen jedoch normalerweise sequenziell (wie bei einer IDENTITY-Spezifikation), sodass sie nur am Ende hinzugefügt werden und keine Daten verschoben werden müssen.

Auf der anderen Seite sind Clustered-Indizes nicht immer schlecht für GUIDs ... alles hängt von den Anforderungen Ihrer Anwendung ab. Wenn Sie SELECT Datensätze schnell aufnehmen können, verwenden Sie einen gruppierten Index ... die INSERT Geschwindigkeit leidet, aber die SELECT Geschwindigkeit wird verbessert.

0

Ja, Sie sollten den Clustered-Index auf GUID-Primärschlüssel aus den oben genannten Gründen Galwegian entfernen. Wir haben dies in unseren Anwendungen getan.

0

Es hängt davon ab, ob Sie viele Einfügungen machen oder wenn Sie eine sehr schnelle Suche von PK benötigen.

+0

Clustering wirkt sich nicht auf Lookup aus Geschwindigkeit - ein eindeutiger, nicht gruppierter Index sollte die Aufgabe erfüllen. –

4

Wenn Sie NewId() verwenden, können Sie zu NewSequentialId() wechseln. Das sollte der Einlage perf helfen.

5

Während Clustering auf einer GUID normalerweise eine schlechte Idee ist, beachten Sie, dass GUIDs unter bestimmten Umständen cause fragmentation even in non-clustered indexes.

Beachten Sie, dass die newsequentialid()-Funktion sequenzielle GUIDs erzeugt, wenn Sie SQL Server 2005 verwenden. Dies hilft, das Fragmentierungsproblem zu vermeiden.

Ich schlage vor, eine SQL-Abfrage wie die Verwendung von folgenden Fragmentierung zu messen, bevor eine Entscheidung getroffen wird (entschuldigen Sie die Nicht-ANSI-Syntax):

SELECT OBJECT_NAME (ips.[object_id]) AS 'Object Name', 
     si.name AS 'Index Name', 
     ROUND (ips.avg_fragmentation_in_percent, 2) AS 'Fragmentation', 
     ips.page_count AS 'Pages', 
     ROUND (ips.avg_page_space_used_in_percent, 2) AS 'Page Density' 
FROM sys.dm_db_index_physical_stats 
    (DB_ID ('MyDatabase'), NULL, NULL, NULL, 'DETAILED') ips 
CROSS APPLY sys.indexes si 
WHERE si.object_id = ips.object_id 
AND si.index_id = ips.index_id 
AND ips.index_level = 0; 
2

Ja, es hat keinen Sinn, einen Clustered-Index auf einen zufälligen Wert in mit .

Wahrscheinlich möchten Sie Clustered-Indizes SOMEWHERE in Ihrer Datenbank. Wenn Sie beispielsweise eine "Author" -Tabelle und eine "Book" -Tabelle mit einem Fremdschlüssel zu "Author" haben und in Ihrer Anwendung eine Abfrage haben, die besagt: "Wählen Sie ... aus Buch aus, wobei AuthorId = .. "Dann würden Sie eine Reihe von Büchern lesen. Es wird schneller sein, wenn diese Bücher physisch nebeneinander auf der Platte sind, so dass der Plattenkopf nicht von Sektor zu Sektor springen muss, um alle Bücher dieses Autors zu sammeln.

Sie müssen also über Ihre Anwendung nachdenken, wie sie die Datenbank abfragt.

Nehmen Sie die Änderungen vor.

Und dann testen, weil man nie wissen ...

24

Sie wollen an Sicherheit grenzender Wahrscheinlichkeit einen Clustered-Index für jede Tabelle in der Datenbank zu etablieren. Wenn eine Tabelle keinen Clustered-Index hat, handelt es sich um einen sogenannten "Heap", und die Leistung der meisten gängigen Abfragen ist less for a heap than for a clustered index table.

Welche Felder für den Clustered-Index festgelegt werden müssen, hängt von der Tabelle selbst und den erwarteten Verwendungsmustern von Abfragen für die Tabelle ab. In fast allen Fällen möchten Sie wahrscheinlich, dass sich der Clustered-Index in einer Spalte oder einer Kombination von Spalten befindet, die eindeutig ist, dh (ein alternativer Schlüssel), denn wenn dies nicht der Fall ist, fügt SQL einen eindeutigen Wert am Ende von was auch immer hinzu Felder, die Sie trotzdem auswählen. Wenn in Ihrer Tabelle Spalten oder Spalten enthalten sind, die häufig von Abfragen verwendet werden, um mehrere Datensätze auszuwählen oder zu filtern (z. B. wenn Ihre Tabelle Verkaufstransaktionen enthält und Ihre Anwendung häufig Verkaufstransaktionen nach Produkt-ID oder noch besser anfordert, eine Tabelle mit Rechnungsdetails, in der Sie in fast jedem Fall alle Detailsätze für eine bestimmte Rechnung oder eine Rechnungstabelle abrufen, in der Sie häufig alle Rechnungen für einen bestimmten Kunden abrufen ... Dies gilt unabhängig davon, ob Sie als Großbuchstabe ausgewählt werden Anzahl der Datensätze nach einem einzelnen Wert oder nach einem Bereich von Werten)

Diese Spalten sind Kandidaten für den Clustered-Index. Die Reihenfolge der Spalten im Clustered-Index ist kritisch. Die erste im Index definierte Spalte sollte die Spalte sein, die in den erwarteten Abfragen zuerst ausgewählt oder gefiltert wird.

Der Grund für all dies basiert auf dem Verständnis der internen Struktur eines Datenbankindex. Diese Indizes werden Balanced-Tree-Indizes (B-Tree) genannt. Sie sind irgendwie wie ein Binärbaum, außer dass jeder Knoten im Baum eine beliebige Anzahl von Einträgen (und Kindknoten) statt nur zwei haben kann. Was einen Clustered-Index unterscheidet, ist, dass die Blattknoten in einem Clustered-Index die tatsächlichen Datenseite der physischen Festplatte der Tabelle selbst sind. während die Blattknoten des nicht geclusterten Index nur auf die Datenseiten der Tabellen "zeigen".

Wenn eine Tabelle einen clustered-Index enthält, sind die Datenseiten der Tabellen daher die Blattebene dieses Index, und jeder hat einen Zeiger auf die vorherige Seite und die nächste Seite in der Indexreihenfolge (sie bilden eine doppelt verknüpfte Liste).

Wenn Ihre Abfrage also einen Zeilenbereich anfordert, der in der gleichen Reihenfolge wie der Clustered Index liegt ... muss der Prozessor den Index nur einmal (oder vielleicht zweimal) durchlaufen, um die Startseite der Daten zu finden. und folgen Sie dann den verketteten Listenzeigern, um zur nächsten Seite und zur nächsten Seite zu gelangen, bis sie alle Datenseiten gelesen hat, die sie benötigt.

Bei einem nicht gruppierten Index muss er den Index für jede Zeile, die er abruft, einmal durchqueren ...

HINWEIS: EDIT
Um das sequentielle Problem für Guid Key-Spalten zu adressieren, beachten Sie, dass SQL2k5 hat NEWSEQUENTIALID(), die tatsächlich Guids die "alte" sequenzielle Weise generiert.

oder Sie können Jimmy Nielsens KAMM guid algotithm untersuchen, die in Client-Seite Code implementiert wird:

COMB Guids

+3

Aber was ist mit GUIDs? Wenn es sich nicht um sequenzielle GUIDs handelt, werden Sie nie einen Bereich von Zeilen in derselben Reihenfolge abrufen wie der gruppierte Index. Also meine Frage – cbp

+0

Nun, Sie haben Recht, im Allgemeinen ist ein nicht = Clustered-Index etwas schneller als ein Clustered-Index für den Zugriff auf eine Zeile, wenn Non-Index-Spalten abgerufen werden müssen. Um Indizes zu "bedecken", sollte es nicht wichtig sein. (Fortsetzung) –

+2

Ein Clustered-Index kann jedoch bei Abfragen nach "Gruppen" von Daten helfen, selbst wenn Sie nicht sequenzielle Guids verwenden. Wenn die GUID beispielsweise PK in einer übergeordneten Tabelle und die erste (FK) Spalte eines zusammengesetzten Clustered-Index PK in einer untergeordneten Tabelle ist, dann gelten alle Clustered-Index-Vorteile. –

0

Wie die meisten erwähnt haben Vermeiden Sie die Verwendung eines zufälligen Bezeichners in einem Clustered-Index - Sie profitieren nicht von den Vorteilen des Clustering. Tatsächlich werden Sie eine erhöhte Verzögerung erfahren. Sie alle loszuwerden, ist ein solider Rat. Denken Sie auch daran, dass newsequentialid() in einem Multimaster-Replikationsszenario äußerst problematisch sein kann. Wenn Datenbank A und B vor der Replikation newsequentialid() aufrufen, liegt ein Konflikt vor.