2009-07-23 11 views
4

Jusqu'à maintenant j'utilisais le C# "Guid = Guid.NewGuid();" méthode pour générer un ID unique qui peut être stocké en tant que champ ID dans certaines de mes tables de base de données SQL Server à l'aide de Linq to SQL. J'ai été informé que pour des raisons d'indexation, l'utilisation d'un GUID est une mauvaise idée et que je devrais utiliser un Long auto-incrémenté à la place. Est-ce que l'utilisation d'une longue accélération de mes transactions de base de données? Si oui, comment puis-je générer des ID uniques de type Long?SQL Server - Guid VS. Long

Cordialement,

+0

"J'ai été informé que pour des raisons d'indexation, en utilisant un GUID est une mauvaise idée" - Si vous avez un index clusterisé sur votre domaine d'identité, un GUID nuira à la performance des insertions. SQL Server stocke la table dans un ordre basé sur l'index cluster. Comme les nouveaux GUID ne sont pas séquentiels, l'insertion d'une nouvelle ligne devra être insérée au milieu de la table plutôt qu'à la fin, provoquant beaucoup d'E/S. Tant que le type de colonne d'index clusterisé évite ce problème. – adrianbanks

+1

juste pour ajouter - si le GUID est la clé primaire, alors par défaut le GUID sera mis en cluster - ceci peut être non-cluster, mais nécessite une intervention manuelle –

+0

Voir http://sqlblogcasts.com/blogs/martinbell/archive/2009/ 05/25/GUID-Fragmentation-dans-SQL-Server.aspx - et http://www.dotnetrocks.com/default.aspx?showNum=455 pour un podcast avec beaucoup de contenu sur le sujet. –

Répondre

8

Les deux ont des avantages et des inconvénients Cela dépend entièrement de la façon dont vous les utilisez.

Dès le départ, si vous avez besoin d'identificateurs pouvant fonctionner sur plusieurs bases de données, vous avez besoin de GUID. Il y a quelques astuces avec Long (assignant manuellement à chaque base de données une graine/un incrément différent), mais celles-ci ne sont pas bien à l'échelle. En ce qui concerne l'indexation, Long donnera de meilleures performances d'insertion si l'index est en cluster (par défaut, les clés primaires sont regroupées, mais cela peut être modifié pour votre table), car la table n'a pas besoin d'être réorganisée. chaque insert. Cependant, en ce qui concerne les insertions concurrentes, les colonnes longues (identité) seront plus lentes, puis la génération de colonnes d'identité GUID nécessitera une série de verrous exclusifs pour garantir qu'une seule ligne obtiendra le numéro séquentiel suivant. Dans un environnement où de nombreux utilisateurs insèrent plusieurs lignes tout le temps, cela peut être un coup de performance. La génération de GUID dans cette situation est plus rapide. En ce qui concerne le stockage, un GUID occupe deux fois l'espace d'un long (8 octets contre 16). Cependant, cela dépend de la taille globale de votre ligne si 8 octets vont faire une différence notable dans le nombre d'enregistrements contenus dans une feuille, et donc le nombre de feuilles extraites du disque lors d'une requête moyenne.

+2

plus si vous utilisez GUID comme clé de clustering, cette valeur (deux fois plus grande qu'un BIGINT) est ajoutée à chaque entrée de chaque index non clusterisé, ce qui multiplie le gaspillage d'espace, pas juste sur le disque, mais aussi dans la RAM de SQL Server –

3

Un long (grand int dans le serveur SQL) est de 8 octets et un Guid est de 16 octets, donc vous réduire de moitié le nombre des octets serveur SQL doit comparer lorsque vous faites un coup d'oeil vers le haut.

Pour générer un long, utilisez IDENTITY (1,1) lorsque vous créez le champ dans la base de données.

donc soit à l'aide create table ou alter table:

Field_NAME BIGINT NOT NULL PRIMARY KEY IDENTITY(1,1) 

Voir les commentaires pour l'affichage LINQ to SQL

+1

Lorsque vous soumettez votre nouvel enregistrement à la base de données en utilisant L2S, laissez le PK non peuplé. Il sera rempli par L2S dans le cadre de l'envoi, ce qui vous permettra de le récupérer à partir de votre objet d'enregistrement après la soumission, si vous en avez besoin. – Lazarus

+0

Existe-t-il un moyen de le faire en utilisant la vue de conception SQL Server? Mon code de script SQL n'est pas trop bon ........ – Goober

+0

Il y a, mais je ne sais pas comment le faire. Désolé :( – kemiller2002

1

Vous pouvez débattre du GUID ou de l'identité toute la journée. Je préfère la base de données pour générer la valeur unique avec une identité. Si vous fusionnez des données provenant de plusieurs bases de données, ajoutez une autre colonne (pour identifier la base de données source, éventuellement un tinyint ou un smallint) et formez une clé primaire composite.

Si vous allez avec une identité, assurez-vous de choisir le bon type de données, en fonction du nombre de clés attendus que vous allez générer:

bigint - 8 Bytes - max positive value: 9,223,372,036,854,775,807 
int - 4 Bytes - max positive value:    2,147,483,647 

Note « nombre de clés attendus » est différent du nombre de lignes Si vous ajoutez et gardez principalement des lignes, vous pouvez trouver qu'une INT est suffisante avec plus de 2 milliards de clés uniques. Je parie que votre table ne sera pas si grande. Cependant, si vous avez une table de volume élevé où vous continuez d'ajouter et de supprimer des lignes, le nombre de lignes peut être faible, mais vous passerez rapidement par les touches.Vous devriez faire quelques calculs pour voir comment il faudrait loger pour passer les 2 milliards de clés INT. Si vous ne les utilisez pas, allez dans INT, sinon, doublez la taille de la clé et utilisez BIGINT.

3

La "reine d'indexation" - Kim Tripp - dit essentiellement tout dans ses messages de blog d'indexation:

Fondamentalement, ses meilleures pratiques sont : une clé de cluster optimale doit être:

  • uniques
  • petit
  • stable (jamais changer)
  • toujours plus

GUID violez les "petits" et "toujours plus" et ne sont donc pas optimale. PLUS: toutes vos clés de cluster seront ajoutées à chaque entrée de chaque index non cluster (comme la recherche pour trouver réellement l'enregistrement dans la base de données), donc vous voulez les rendre aussi petites possible (INT = 4 octets par rapport à GUID = 16 octets). Si vous avez des centaines de millions de lignes et plusieurs index non clusterisés, choisir un INT ou un BIGINT sur un GUID peut faire une différence majeure - même juste en termes d'espace.

Marc

+2

Si vous ne vous souciez pas de l'échelle, ne choisissez pas de GUID, ce qui ne fait probablement pas de différence de vitesse ou d'échelle dans les bases de données plus petites. Avec plus d'un index, les GUID sont un cauchemar de performance ... Lisez les articles de Kim Tripp ci-dessus, c'est une décision énorme, qui nous a coûté 3 mois de dette technique – BoomTownTech

1

Utilisez GUIDs lorsque vous devez considérer l'importation/l'exportation vers plusieurs bases de données. Les règles sont souvent plus faciles à utiliser que les colonnes spécifiant l'attribut IDENTITY lorsque vous travaillez avec un ensemble de données de plusieurs relations enfants. En effet, vous pouvez générer aléatoirement des guids dans le code dans un état déconnecté de la base de données, puis soumettre tous les changements en même temps. Lorsque les guids sont générés correctement, ils sont insoutenables à dupliquer par hasard. Avec les colonnes d'identité, vous devez souvent insérer une insertion initiale d'une ligne parente et demander sa nouvelle identité avant d'ajouter des données enfant. Vous devez ensuite mettre à jour tous les enregistrements enfants avec la nouvelle identité parent avant de les valider dans la base de données. La même chose vaut pour les petits-enfants et ainsi de suite dans la hiérarchie. Cela crée beaucoup de travail qui semble inutile et banal. Vous pouvez faire quelque chose de similaire à Guids en entrant des entiers aléatoires sans la spécification IDENTITY, mais le risque de collision augmente considérablement lorsque vous insérez plus d'enregistrements au fil du temps. (Guid.NewGuid() est similaire à un Int128 aléatoire - qui n'existe pas encore). J'utilise Byte (TinyInt), Int16 (SmallInt), Int32/UInt16 (Int), Int64/UInt32 (BigInt) pour les petites listes de recherche qui ne changent pas ou les données qui ne sont pas répliquées entre plusieurs bases de données. (Autorisations, configuration de l'application, noms de couleurs, etc.)

J'imagine que l'indexation est aussi longue à interroger, que vous utilisiez un guid ou un long. Il y a généralement d'autres champs dans les tables qui sont indexés de plus de 128 bits (noms d'utilisateur dans une table utilisateur par exemple). La différence entre Guids et Integer est la taille de l'index en mémoire, ainsi que le remplissage et la reconstruction des index. La majorité des transactions de base de données est souvent en lecture. L'écriture est minime. Concentrez-vous d'abord sur l'optimisation de la lecture de la base de données, car ils sont généralement constitués de tables jointes qui n'ont pas été optimisées correctement, d'une pagination incorrecte ou d'index manquants.

Comme pour tout, la meilleure chose à faire est de prouver votre point. créer une base de données de test avec deux tables. Un avec une clé primaire d'entiers/longs, et l'autre avec un guid. Remplissez chacun avec des rangées N-Million. Surveiller les performances de chacun lors des opérations CRUD (créer, lire, mettre à jour, supprimer). Vous pouvez découvrir qu'il a un impact sur la performance, mais insignifiant.

Les serveurs s'exécutent souvent sur des boîtes sans environnements de débogage et autres applications prenant le processeur, la mémoire et les E/S du disque dur (en particulier avec RAID). Un environnement de développement ne vous donne qu'une idée de la performance.