it-swarm.com.de

Was sind die Best Practices für die Verwendung von a GUID als Primärschlüssel, speziell in Bezug auf die Leistung?

Ich habe eine Anwendung, die GUID als Primärschlüssel in fast allen Tabellen verwendet, und ich habe gelesen, dass es Probleme mit der Leistung gibt, wenn GUID als Primärschlüssel verwendet wird. Ehrlich gesagt habe ich kein Problem gesehen, aber ich bin dabei, eine neue Anwendung zu starten, und ich möchte immer noch die GUIDs als Primärschlüssel verwenden, aber ich dachte daran, einen zusammengesetzten Primärschlüssel zu verwenden (The GUID und vielleicht ein anderes Feld.)

Ich verwende eine GUID weil sie nett und einfach zu verwalten sind, wenn Sie unterschiedliche Umgebungen wie "Produktionsdaten", "Test" und "Dev" -Datenbanken haben und auch für Migrationsdaten zwischen Datenbanken.

Ich werde Entity Framework 4.3 verwenden und die Guid im Anwendungscode zuweisen, bevor sie in die Datenbank eingefügt wird. (Das heißt, ich möchte nicht, dass SQL die Guid generiert).

Was ist die beste Vorgehensweise zum Erstellen von GUID-basierten Primärschlüsseln, um die mit diesem Ansatz verbundenen vermeintlichen Leistungseinbußen zu vermeiden?

280
VAAA

GUIDs scheinen eine natürliche Wahl für Ihren Primärschlüssel zu sein - und wenn Sie wirklich müssen, könnten Sie wahrscheinlich argumentieren, sie für den PRIMARY KEY der Tabelle zu verwenden. Was ich dringend empfehlen würde , nicht zu tun , ist die Verwendung der GUID -Spalte als Clustering key , den SQL Server standardmäßig ausführt, es sei denn, Sie weisen ausdrücklich an, dies nicht zu tun.

Sie müssen wirklich zwei Punkte auseinanderhalten:

  1. der Primärschlüssel ist ein logisches Konstrukt - einer der Kandidatenschlüssel, der jede Zeile in Ihrer Tabelle eindeutig und zuverlässig identifiziert. Dies kann wirklich alles sein - ein INT, ein GUID, ein String - wählen Sie aus, was für Ihr Szenario am sinnvollsten ist.

  2. der Clustering-Schlüssel (die Spalte oder Spalten, die den "Clustered-Index" für die Tabelle definieren) - dies ist ein physischer speicherbezogene Sache, und hier ist ein kleiner, stabiler, immer größer werdender Datentyp die beste Wahl - INT oder BIGINT als Standardoption.

Standardmäßig wird der Primärschlüssel einer SQL Server-Tabelle auch als Clustering-Schlüssel verwendet - das muss aber nicht so sein! Ich persönlich habe massive Leistungssteigerungen gesehen, als ich den vorherigen GUID-basierten Primär-/Clustered-Schlüssel in zwei separate Schlüssel zerlegte - den primären (logischen) Schlüssel in der GUID und den Clustering-Schlüssel in einem separaten INT IDENTITY(1,1). Säule.

Als Kimberly Tripp - die Königin der Indizierung - und andere haben sehr oft angegeben - ein GUID, da der Clustering-Schlüssel nicht optimal ist, da er aufgrund seiner Zufälligkeit zu massiven Seiten und Indizes führt Fragmentierung und allgemein schlechte Leistung.

Ja, ich weiß - es gibt newsequentialid() in SQL Server 2005 und höher - aber auch das ist nicht wirklich und vollständig sequentiell und leidet daher auch unter den gleichen Problemen wie das GUID - nur ein bisschen weniger prominent.

Dann ist noch ein anderes Problem zu berücksichtigen: Der Clustering-Schlüssel einer Tabelle wird zu jedem einzelnen Eintrag in jedem nicht geclusterten Index Ihrer Tabelle hinzugefügt. Daher möchten Sie unbedingt sicherstellen, dass er so klein wie möglich ist. In der Regel sollte eine INT mit mehr als 2 Milliarden Zeilen für die meisten Tabellen ausreichen. Im Vergleich zu einer GUID als Clustering-Schlüssel können Sie sich Hunderte von Megabyte Speicherplatz auf der Festplatte und im Serverspeicher sparen.

Schnelle Berechnung - mit INT vs. GUID als Primär- und Clustering-Schlüssel:

  • Basistabelle mit 1'000'000 Zeilen (3,8 MB gegenüber 15,26 MB)
  • 6 nicht gruppierte Indizes (22,89 MB gegenüber 91,55 MB)

INSGESAMT: 25 MB vs. 106 MB - und das nur an einem einzigen Tisch!

Noch ein paar Denkanstöße - exzellente Sachen von Kimberly Tripp - lesen Sie es, lesen Sie es noch einmal, verdauen Sie es! Es ist wirklich das SQL Server-Indizierungs-Evangelium.

PS: Wenn Sie es nur mit ein paar Hundert oder ein paar Tausend Zeilen zu tun haben, werden die meisten dieser Argumente keinen großen Einfluss auf Sie haben. Jedoch: Wenn Sie in die Zehn- oder Hunderttausende von Reihen geraten, oder wenn Sie anfangen, in Millionen zu zählen - , dann werden diese Punkte sehr wichtig und sehr wichtig für verstehen.

Update: wenn Sie Ihre Spalte PKGUID als Primärschlüssel (aber nicht Ihren Clustering-Schlüssel) und eine andere Spalte MYINT (INT IDENTITY haben möchten ) als Clustering-Schlüssel verwenden:

CREATE TABLE dbo.MyTable
(PKGUID UNIQUEIDENTIFIER NOT NULL,
 MyINT INT IDENTITY(1,1) NOT NULL,
 .... add more columns as needed ...... )

ALTER TABLE dbo.MyTable
ADD CONSTRAINT PK_MyTable
PRIMARY KEY NONCLUSTERED (PKGUID)

CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT)

Grundsätzlich gilt: Sie müssen der Einschränkung PRIMARY KEY nur explizit mitteilen, dass es sich um NONCLUSTERED handelt (andernfalls wird es standardmäßig als Ihr Clustered-Index erstellt) - und Dann erstellen Sie einen zweiten Index, der als CLUSTERED definiert ist.

Dies wird funktionieren - und es ist eine gültige Option, wenn Sie ein vorhandenes System haben, das für die Leistung "überarbeitet" werden muss. Wenn Sie in einem neuen System bei Null anfangen und sich nicht in einem Replikationsszenario befinden, würde ich immer ID INT IDENTITY(1,1) als meinen gruppierten Primärschlüssel auswählen - viel effizienter als alles andere!

453
marc_s

Ich benutze GUIDs seit 2005 als PKs. In dieser verteilten Datenbankwelt ist es absolut der beste Weg, verteilte Daten zusammenzuführen. Sie können Tabellen zusammenführen und vergessen, ohne sich Gedanken darüber machen zu müssen, dass ints über verbundene Tabellen passen. GUIDs-Joins können problemlos kopiert werden.

Dies ist mein Setup für die Verwendung von GUIDs:

  1. PK = GUID. GUIDs werden ähnlich wie Zeichenfolgen indiziert, so dass Tabellen mit hohen Zeilen (über 50 Millionen Datensätze) möglicherweise eine Tabellenpartitionierung oder andere Leistungstechniken erfordern. SQL Server wird extrem effizient, so dass Leistungsprobleme immer weniger zutreffend sind.

  2. PK Guid ist ein nicht gruppierter Index. Cluster-Index niemals a GUID, es sei denn, es handelt sich um NewSequentialID. Aber selbst dann führt ein Neustart des Servers zu großen Bestellungsstörungen.

  3. Fügen Sie jeder Tabelle ClusterID Int hinzu. Dies ist Ihr CLUSTERED-Index ..., der Ihren Tisch bestellt.

  4. Der Beitritt zu ClusterIDs (int) ist effizienter, aber ich arbeite mit 20 bis 30 Millionen Datensatztabellen. Der Beitritt zu GUIDs wirkt sich daher nicht auf die Leistung aus. Wenn Sie maximale Leistung wünschen, verwenden Sie das ClusterID-Konzept als Primärschlüssel und nehmen Sie an ClusterID teil.

Hier ist meine E-Mail-Tabelle ...

CREATE TABLE [Core].[Email] (

[EmailID]      UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL,

[EmailAddress] NVARCHAR (50)    CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL,

[CreatedDate]  DATETIME         CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL,

[ClusterID] INT NOT NULL IDENTITY,
    CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC)
);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID])
GO

CREATE UNIQUE NonCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc)
40
Robert J. Good

Ich entwickle derzeit eine Webanwendung mit EF Core und hier ist das Muster, das ich verwende:

Alle meine Klassen (Tabellen) und eine int PK und FK . Ich habe eine zusätzliche Spalte vom Typ Guid (vom c # -Konstruktor generiert) mit einem nicht gruppierten Index darauf.

Alle Joins der Tabelle innerhalb von EF werden über die int-Schlüssel verwaltet, während der Zugriff von außen (Controller) mit den Guids erfolgt.

Diese Lösung ermöglicht es, die int-Schlüssel nicht auf URLs anzuzeigen, sondern das Modell aufgeräumt und schnell zu halten.

5
EricImhauser

Wenn Sie GUID als Primärschlüssel verwenden und einen gruppierten Index erstellen, empfiehlt es sich, den Standardwert NEWSEQUENTIALID () für diesen Wert zu verwenden

4
AnandPhadke

Dieser Link sagt es besser als ich konnte und half mir bei der Entscheidungsfindung. Normalerweise entscheide ich mich für ein int als Primärschlüssel, es sei denn, ich habe ein bestimmtes Bedürfnis, und ich lasse auch das SQL-Server automatisch dieses Feld generieren/pflegen, sofern ich keinen bestimmten Grund dafür habe. In der Realität müssen Leistungsbedenken anhand Ihrer spezifischen App ermittelt werden. Hier spielen viele Faktoren eine Rolle, darunter die erwartete Datenbankgröße, die richtige Indexierung, effiziente Abfrage und vieles mehr. Obwohl die Leute möglicherweise anderer Meinung sind, werden Sie in vielen Szenarien keinen Unterschied mit einer der beiden Optionen feststellen. Sie sollten wählen, was für Ihre App besser geeignet ist und was es Ihnen ermöglicht, einfacher, schneller und effektiver zu entwickeln (wenn Sie die App niemals abschließen Welchen Unterschied macht der Rest :).

https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

P.S. Ich bin nicht sicher, warum Sie eine Composite-PK verwenden oder welchen Nutzen Sie davon glauben.

3
Matt

Durch sequenzielle IDs wird es für einen Hacker oder Data Miner viel einfacher, Ihre Website und Ihre Daten zu gefährden. Denken Sie daran, wenn Sie einen PK für eine Website auswählen.

1
DaBlue

In den meisten Fällen sollte es nicht als Primärschlüssel für eine Tabelle verwendet werden, da dies die Leistung der Datenbank wirklich beeinträchtigt. Nützliche Links zu GUID Auswirkungen auf die Leistung und als Primärschlüssel.

  1. https://www.sqlskills.com/blogs/kimberly/disk-space-is-cheap/
  2. https://www.sqlskills.com/blogs/kimberly/guids-as-primary-keys-andor-the-clustering-key/
0