Mes développeurs ont configuré leur application pour utiliser les GUID en tant que PK pour à peu près toutes leurs tables et par défaut, SQL Server a configuré l'index cluster sur ces PK.
Le système est relativement jeune et nos plus grandes tables ne dépassent pas un million de lignes, mais nous examinons notre indexation et voulons pouvoir évoluer rapidement car cela pourrait être nécessaire dans un proche avenir.
Donc, ma première inclination a été de déplacer l'index clusterisé vers le champ créé qui est une représentation bigint d'un DateTime. Cependant, la seule façon dont je peux rendre le CX unique serait d'inclure la colonne GUID dans ce CX, mais l'ordre en le créant d'abord.
Cela rendrait-il la clé de clustering trop large et augmenterait-il les performances d'écriture? Les lectures sont également importantes, mais les écritures sont probablement une préoccupation plus importante à ce stade.
newsequentialid
sont pas créés avec sont aléatoires. Les clés en cluster sont meilleures lorsqu'elles sont étroites et croissantes. Un GUID est le contraire: gras et aléatoire. Imaginez une étagère presque pleine de livres. En vient l'OED et en raison du caractère aléatoire des guides, il s'insère au milieu de l'étagère. Pour garder les choses ordonnées, la bonne moitié des livres doit être placée dans un nouvel emplacement, ce qui est une tâche exigeante en temps. C'est ce que le GUID fait à votre base de données et réduit les performances.Réponses:
Les principaux problèmes avec les GUID, en particulier ceux non séquentiels, sont:
Alors qu'est-ce que cela signifie pour votre situation? Cela dépend de votre conception. Si votre système concerne simplement les écritures et que vous ne vous souciez pas de la récupération des données, l'approche décrite par Thomas K est exacte. Cependant, vous devez garder à l'esprit qu'en poursuivant cette stratégie, vous créez de nombreux problèmes potentiels pour la lecture de ces données et leur stockage. Comme le souligne Jon Seigel , vous occuperez également plus d'espace et aurez essentiellement un ballonnement de mémoire.
La principale question concernant les GUID est de savoir à quel point ils sont nécessaires. Les développeurs les aiment parce qu'ils garantissent l'unicité globale, mais c'est une occasion rare que ce type d'unicité soit nécessaire. Mais considérez que si votre nombre maximal de valeurs est inférieur à 2 147 483 647 (la valeur maximale d'un entier signé de 4 octets), vous n'utilisez probablement pas le type de données approprié pour votre clé. Même en utilisant BIGINT (8 octets), votre valeur maximale est de 9 223 372 036 854 775 807. Cela est généralement suffisant pour toute base de données non globale (et de nombreuses bases de données globales) si vous avez besoin d'une valeur d'incrémentation automatique pour une clé unique.
Enfin, en ce qui concerne l'utilisation d'un segment de mémoire par rapport à un index clusterisé, si vous écrivez uniquement des données, un segment de mémoire serait plus efficace car vous réduisez la surcharge pour les insertions. Cependant, les tas dans SQL Server sont extrêmement inefficaces pour la récupération de données. D'après mon expérience, un index cluster est toujours souhaitable si vous avez la possibilité d'en déclarer un. J'ai vu l'ajout d'un index clusterisé à une table (4 milliards + d'enregistrements) améliorer les performances de sélection globales d'un facteur 6.
Information additionnelle:
la source
Il n'y a rien de mal avec GUID en tant que clés et clusters dans un système OLTP (sauf si vous avez BEAUCOUP d'index sur la table qui souffrent de l'augmentation de la taille du cluster). En fait, ils sont beaucoup plus évolutifs que les colonnes IDENTITY.
Il y a une croyance répandue que les GUID sont un gros problème dans SQL Server - en grande partie, c'est tout simplement faux. En fait, le GUID peut être considérablement plus évolutif sur les boîtes avec plus d'environ 8 cœurs:
Je suis désolé, mais vos développeurs ont raison. Souciez-vous d'autres choses avant de vous soucier du GUID.
Oh, et enfin: pourquoi voulez-vous un index de cluster en premier lieu? Si votre problème est un système OLTP avec beaucoup de petits index, vous êtes probablement mieux avec un tas.
Voyons maintenant ce que la fragmentation (que le GUID introduira) fait à vos lectures. Il y a trois problèmes majeurs avec la fragmentation:
Étant donné que votre préoccupation dans la question concerne l'évolutivité, que nous pouvons définir comme «l'ajout de matériel accélère le système», ce sont les moindres problèmes. Pour aborder chacun à son tour
Annonce 1) Si vous voulez évoluer, vous pouvez vous permettre d'acheter des E / S. Même un SSD Samsung / Intel 512 Go bon marché (à quelques USD / Go) vous permettra de dépasser les 100 000 IOPS. Vous ne consommerez pas cela de sitôt sur un système à 2 prises. Et si vous rencontrez cela, achetez-en un de plus et vous êtes prêt
Annonce 2) Si vous supprimez votre tableau, vous aurez quand même des pages à moitié pleines. Et même si vous ne le faites pas, la mémoire est bon marché et pour tous, sauf les plus grands systèmes OLTP - les données chaudes devraient y tenir. La recherche de plus de données dans des pages est une sous-optimisation lorsque vous recherchez une échelle.
Annonce 3) Une table construite à partir de données fréquemment fragmentées et très fragmentées effectue des E / S aléatoires exactement à la même vitesse qu'une table remplie séquentiellement
En ce qui concerne la jointure, il existe deux principaux types de jointures que vous êtes susceptible de voir dans une charge de travail de type OLTP: Hash and loop. Regardons chacun à son tour:
Jointure par hachage: une jointure par hachage suppose que la petite table est analysée et que la plus grande est généralement recherchée. Les petites tables sont très probablement en mémoire, donc les E / S ne sont pas votre problème ici. Nous avons déjà évoqué le fait que les recherches ont le même coût dans un indice fragmenté que dans un indice non fragmenté
Jointure de boucle: la table externe sera recherchée. Même coût
Vous pouvez également avoir beaucoup de mauvaises analyses de table en cours - mais le GUID n'est à nouveau pas votre problème, une bonne indexation l'est.
Maintenant, vous pouvez avoir des analyses de plage légitimes en cours (en particulier lors de la jonction sur des clés étrangères) et dans ce cas, les données fragmentées sont moins "compressées" par rapport aux données non fragmentées. Mais considérons les jointures que vous verrez probablement dans des données 3NF bien indexées:
Une jointure d'une table qui a une référence de clé étrangère à la clé primaire de la table qu'elle référence
L'inverse
Annonce 1) Dans ce cas, vous allez pour une seule recherche à la clé primaire - joindre n à 1. Fragmentation ou non, même coût (une recherche)
Annonce 2) Dans ce cas, vous vous joignez à la même clé, mais vous pouvez récupérer plusieurs lignes (recherche de plage). La jointure dans ce cas est de 1 à n. Cependant, la table étrangère que vous recherchez, vous recherchez la même clé, qui est tout aussi susceptible d'être sur la même page dans un index fragmenté que sur une index non fragmentée.
Considérez ces clés étrangères pendant un moment. Même si vous aviez "parfaitement" séquentiellement posé nos clés primaires - tout ce qui pointe vers cette clé sera toujours non séquentiel.
Bien sûr, vous exécutez peut-être une machine virtuelle dans un SAN dans une banque peu onéreuse et gourmande en processus. Ensuite, tous ces conseils seront perdus. Mais si tel est votre monde, l'évolutivité n'est probablement pas ce que vous recherchez - vous recherchez des performances et une vitesse / coût élevés - qui sont deux choses différentes.
la source
Thomas: certains de vos points sont parfaitement logiques et je suis d'accord avec eux tous. Si vous utilisez des SSD, l'équilibre de ce que vous optimisez change. Random vs séquentiel n'est pas la même discussion que le disque en rotation.
Je suis particulièrement d'accord que prendre une vue DB pure est horriblement mauvais. Rendre votre application lente et non évolutive pour améliorer uniquement les performances de la base de données peut être assez erroné.
Le gros problème avec IDENTITY (ou séquence, ou tout ce qui est généré dans la base de données) est qu'il est horriblement lent car il nécessite un aller-retour vers la base de données pour créer une clé, ce qui crée automatiquement un goulot d'étranglement dans votre base de données, il impose que les applications doivent effectuer un appel DB pour commencer à utiliser une clé. La création d'un GUID résout ce problème en utilisant l'application pour créer la clé, il est garanti d'être globalement unique (par définition), et les couches d'application peuvent ainsi l'utiliser pour transmettre l'enregistrement AVANT d'engager un aller-retour DB.
Mais j'ai tendance à utiliser une alternative aux GUID Ma préférence personnelle pour un type de données ici est un BIGINT unique au monde généré par l'application. Comment procéder? Dans l'exemple le plus trivial, vous ajoutez une petite fonction TRÈS légère à votre application pour hacher un GUID. En supposant que votre fonction de hachage est rapide et relativement rapide (voir CityHash de Google pour un exemple: http://google-opensource.blogspot.in/2011/04/introducing-cityhash.html - assurez-vous que toutes les étapes de compilation sont correctes, ou la variante FNV1a de http://tools.ietf.org/html/draft-eastlake-fnv-03 pour le code simple), vous bénéficiez à la fois des identifiants uniques générés par l'application et d'une valeur de clé 64 bits avec laquelle les processeurs fonctionnent mieux avec .
Il existe d'autres façons de générer des BIGINT, et dans ces deux algues, il existe un risque de collision de hachage - lisez et prenez des décisions conscientes.
la source