web-dev-qa-db-fra.com

Quelles sont les meilleures pratiques pour utiliser un GUID en tant que clé primaire, en particulier en ce qui concerne les performances?

J'ai une application qui utilise GUID comme clé primaire dans presque toutes les tables et j'ai lu que des problèmes de performances se posaient lors de l'utilisation de GUID comme clé primaire. Honnêtement, je n'ai vu aucun problème, mais je suis sur le point de démarrer une nouvelle application et je souhaite toujours utiliser les GUID en tant que clés primaires, mais je pensais utiliser une clé primaire composite (le GUID et peut-être un autre domaine.)

J'utilise un GUID car ils sont agréables et faciles à gérer lorsque vous avez différents environnements tels que des bases de données "de production", "test" et "dev", ainsi que pour les données de migration entre bases de données.

Je vais utiliser Entity Framework 4.3 et je veux assigner le Guid dans le code de l'application, avant de l'insérer dans la base de données. (c’est-à-dire que je ne veux pas laisser SQL générer le Guid).

Quelle est la meilleure pratique pour créer des clés primaires basées sur un GUID, afin d'éviter les hits de performances supposés associés à cette approche?

280
VAAA

Les GUID peuvent sembler être un choix naturel pour votre clé primaire - et si vous en aviez vraiment besoin, vous pourriez probablement argumenter pour l'utiliser pour la CLE PRIMARY de la table. Ce que je recommanderais vivement de ne pas faire est d'utiliser la colonne GUID comme cluster key , que SQL Server fait par défaut, sauf indication contraire de votre part.

Vous devez vraiment séparer deux problèmes:

  1. la clé primaire est une construction logique - l'une des clés candidates qui identifie de manière unique et fiable chaque ligne de votre table. Cela peut être n'importe quoi, vraiment - un INT, un GUID, une chaîne - choisissez ce qui convient le mieux à votre scénario.

  2. la clé de clustering (la ou les colonnes qui définissent "l'index clusterisé" de la table) - il s'agit d'un physique chose liée au stockage, et ici, un type de données petit, stable et en augmentation constante est votre meilleur choix - INT ou BIGINT comme option par défaut.

Par défaut, la clé primaire d'une table SQL Server est également utilisée comme clé de clustering - mais cela n'a pas besoin d'être ainsi! J'ai personnellement constaté des gains de performances considérables lors de la scission de la clé principale/en cluster précédente basée sur un GUID en deux clés distinctes: la clé principale (logique) du GUID et la clé de clustering (classement) sur une INT IDENTITY(1,1) distincte. colonne.

Comme Kimberly Tripp - la reine de l'indexation - et d'autres l'ont déjà déclaré très souvent - un GUID, car la clé de regroupement n'est pas optimale car, en raison de son caractère aléatoire, elle fragmentation massive des pages et des index et performances généralement mauvaises.

Oui, je sais - il y a newsequentialid() dans SQL Server 2005 et versions ultérieures - mais même cela n'est pas véritablement séquentiel et souffre donc des mêmes problèmes que le GUID - mais de manière un peu moins visible.

Ensuite, il y a un autre problème à prendre en compte: la clé de clustering d'une table sera ajoutée à chaque entrée de chaque index non clusterisé de votre table. Vous voulez donc vraiment vous assurer qu'elle est aussi petite que possible. En règle générale, une INT avec plus de 2 milliards de lignes devrait suffire pour la grande majorité des tables - et par rapport à une GUID en tant que clé de clustering, vous pouvez économiser des centaines de mégaoctets de stockage sur disque et dans mémoire du serveur.

Calcul rapide - en utilisant INT vs. GUID comme clé primaire et clé de clustering:

  • Table de base avec 1 000 000 lignes (3,8 Mo contre 15,26 Mo)
  • 6 index non clusterisés (22,89 Mo contre 91,55 Mo)

TOTAL: 25 Mo contre 106 Mo - et ce n’est que sur une seule table!

Encore quelques pistes de réflexion - excellentes choses de Kimberly Tripp - lisez-les, relisez-les, digérez-les! C'est le gospel d'indexation de SQL Server, vraiment.

PS: Bien sûr, si vous avez seulement quelques centaines ou quelques milliers de lignes, la plupart de ces arguments n'auront pas vraiment d'impact sur vous. Cependant: si vous entrez dans les dizaines, voire les centaines de milliers de lignes, ou si vous commencez à compter par millions - , alors ces points deviennent très importants et très importants pour comprendre.

Mise à jour: si vous souhaitez que votre colonne PKGUID constitue votre clé primaire (mais pas votre clé de clustering), ainsi qu'une autre colonne MYINT (INT IDENTITY) comme clé de cluster - utilisez ceci:

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)

En gros: vous devez simplement explicitement indiquer à la contrainte PRIMARY KEY qu'il s'agit de NONCLUSTERED (sinon, il est créé en tant qu'index clusterisé, par par défaut) - et ensuite vous créez un deuxième index défini comme CLUSTERED

Cela fonctionnera - et c'est une option valable si vous avez un système existant qui doit être "repensé" pour améliorer les performances. Pour un nouveau système, si vous démarrez à partir de zéro et que vous n'êtes pas dans un scénario de réplication, je choisirais toujours ID INT IDENTITY(1,1) comme clé primaire en cluster - bien plus efficace qu'autre chose!

453
marc_s

J'utilise des GUID en tant que PC depuis 2005. Dans ce monde de bases de données distribuées, c'est absolument le meilleur moyen de fusionner des données distribuées. Vous pouvez déclencher et oublier les tables de fusion sans vous soucier des correspondances entre les tables jointes. Les jointures GUID peuvent être copiées sans souci.

Voici ma configuration pour utiliser les GUID:

  1. PK = GUID. Les GUID étant indexés de la même manière que les chaînes, les tables de rangées hautes (plus de 50 millions d'enregistrements) peuvent nécessiter un partitionnement de table ou d'autres techniques de performance. SQL Server devient extrêmement efficace, de sorte que les problèmes de performances sont de moins en moins applicables.

  2. PK Guid est un index non clusterisé. Ne jamais regrouper l'index a GUID sauf s'il s'agit de NewSequentialID. Mais même dans ce cas, un redémarrage du serveur entraînera des ruptures importantes dans les commandes.

  3. Ajoutez ClusterID Int à chaque table. Ceci est votre index CLUSTERED ... qui ordonne votre table.

  4. La jonction sur des ClusterIDs (int) est plus efficace, mais je travaille avec 20 à 30 millions de tables d’enregistrement. Par conséquent, la jonction sur des GUID n’affecte pas les performances. Si vous voulez des performances maximales, utilisez le concept ClusterID comme clé primaire et rejoignez ClusterID.

Voici mon tableau Email ...

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

Je développe actuellement une application Web avec EF Core et voici le modèle que j'utilise:

Toutes mes classes (tables) et un PK et un FK . Int. J'ai une colonne supplémentaire avec le type Guid (généré par le constructeur c #) avec un index non clusterisé dessus.

Toutes les jointures de table au sein de EF sont gérées via les touches int, tandis que tous les accès de l’extérieur (contrôleurs) se font avec les guids.

Cette solution permet de ne pas afficher les clés int sur les URL mais de garder le modèle ordonné et rapide.

5
EricImhauser

Si vous utilisez GUID comme clé primaire et créez un index clusterisé, nous vous suggérons d'utiliser la valeur par défaut de NEWSEQUENTIALID () pour celui-ci.

4
AnandPhadke

Ce lien le dit mieux que moi et m'a aidé dans ma prise de décision. J'opte généralement pour un int en tant que clé primaire, sauf si j'ai un besoin spécifique de ne pas le faire et je laisse également le serveur SQL générer/conserver ce champ automatiquement, sauf si j'ai une raison particulière de ne pas le faire. En réalité, les problèmes de performances doivent être résolus en fonction de votre application spécifique. De nombreux facteurs entrent en jeu ici, notamment la taille de base de données attendue, l’indexation appropriée, des requêtes efficaces, etc. Bien que les gens puissent ne pas être d’accord, je pense que dans de nombreux scénarios, vous ne remarquerez pas de différence avec l’une ou l’autre des options et vous devrez choisir ce qui est le plus approprié pour votre application et ce qui vous permettra de développer plus facilement, plus rapidement et plus efficacement ( Quelle différence le reste fait-il :).

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

P.S. Je ne suis pas sûr de savoir pourquoi vous utiliseriez un PK composite ou quel avantage vous en retireriez.

3
Matt

Avoir des identifiants séquentiels facilite beaucoup la tâche à un pirate informatique ou à un mineur de données de compromettre votre site et vos données. Gardez cela à l’esprit lorsque vous choisissez une PK pour un site Web.

1
DaBlue

La plupart du temps, il ne doit pas être utilisé comme clé primaire pour une table car il affecte réellement les performances de la base de données . Des liens utiles concernant l'impact de GUID sur les performances et comme clé primaire.

  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
Asrar Ahmad Ehsan