L'index d'une colonne d'identité doit-il être non clusterisé?


19

Pour une table avec une colonne d'identité, un index PK / unique en cluster ou non en cluster doit-il être créé pour la colonne d'identité?

La raison en est que d'autres index seront créés pour les requêtes. Une requête qui utilise un index non cluster (sur un segment de mémoire) et renvoie des colonnes qui ne sont pas couvertes par l'index utilise moins d'E / S logiques (LIO) car il n'y a pas d'étapes de recherche d'arborescence b d'index en cluster supplémentaires?

create table T (
  Id int identity(1,1) primary key, -- clustered or non-clustered? (surrogate key, may be used to join another table)
  A .... -- A, B, C have mixed data type of int, date, varchar, float, money, ....
  B ....
  C ....
  ....)

create index ix_A on T (A)
create index ix_..... -- Many indexes can be created for queries

-- Common query is query on A, B, C, ....
select A, B 
from T 
where A between @a and @a+5 -- This query will have less LIO if the PK is non-clustered (seek)

select A, B, C
from T 
where B between @a and @a+5 

....

PK en cluster sur la colonne d'identité est bon car:

  1. Il augmente de façon monotone afin qu'aucune page ne se divise lors de l'insertion. On dit qu'un insert en vrac peut être aussi rapide que sur une table en tas (non cluster)

  2. C'est étroit

Cependant, les requêtes dans la question seront-elles plus rapides sans la définir en cluster?

** Mise à jour: ** Que faire si le IdFK est d'autres tables et qu'il sera joint dans certaines requêtes?


3
Ce n'est ni meilleur ni pire, cela dépend.
Aaron Bertrand

1
@ypercube Le lien kejser.org/clustered-indexes-vs-heaps indique que le non-CI aura moins de LIO.
u23432534

2
J'ai lu l'article dans le passé et il indique certainement qu'il existe des cas pour un index cluster et des cas pour un tas. Ce n'est pas tout noir ou tout blanc.
ypercubeᵀᴹ

4
Je ne suis pas sûr que votre réponse à @ypercube satisfasse à l'un des critères cités par M. Kejser - au moins avec les détails que vous avez partagés. Dans sa forme actuelle, je ne suis pas vraiment sûr que cela va générer une réponse utile car elle devrait couvrir presque tous les scénarios - ce qui est déjà fait dans le billet de blog que vous avez cité. Si vous pouvez fournir plus de détails sur votre scénario spécifique, alors certaines des connaissances contenues dans le message peuvent être appliquées.
swasheck

2
Cela dépendra de choses comme: a) la charge de travail (OLTP? OLAP? Etc?), B) la taille des tables, c) la forme normale, pour n'en nommer que quelques-unes. Vous n'avez pas fourni de détails sur l'un de ces facteurs, donc toute recommandation serait basée sur des suppositions de votre environnement. En outre, avez-vous essayé de profiler les requêtes que vous proposez (avec des tampons effacés) et d'obtenir les profils d'E / S spécifiques par configuration et de voir par vous-même?
swasheck

Réponses:


16

Par défaut, le PK est mis en cluster et dans la plupart des cas, c'est très bien. Cependant, quelle question devrait être posée:

  • mon PK doit-il être mis en cluster?
  • quelle (s) colonne (s) sera la meilleure clé pour mon index clusterisé?

PK et l'index cluster sont deux choses différentes:

  • PK est une contrainte. PK est utilisé pour identifier de manière unique les lignes, mais il n'y a aucune notion de stockage. Cependant, par défaut (dans SSMS), il est appliqué par un index cluster unique si un index cluster n'est pas encore présent.
  • Les index clusterisés sont un type spécial d'index qui stocke les données de ligne au niveau feuille, ce qui signifie qu'il est toujours couvrant. Toutes les colonnes, qu'elles fassent partie ou non de la clé, sont stockées au niveau feuille. Il n'est pas nécessaire qu'il soit unique, auquel cas un unificateur (4 octets) est ajouté à la clé en cluster.

Maintenant, nous nous retrouvons avec 2 questions:

  • Comment puis-je identifier de façon unique les lignes de ma table (PK)
  • Comment puis-je le stocker au niveau feuille d'un index (Clustered Index)

Cela dépend de la façon dont:

  • vous concevez votre modèle de données
  • vous interrogez vos données et vous écrivez vos requêtes
  • vous insérez ou mettez à jour vos données
  • ...

Tout d'abord, avez-vous besoin d'un index clusterisé? Si vous insérez en bloc, il est plus efficace de stocker des données non ordonnées dans un HEAP (par rapport aux données ordonnées dans un cluster). Il utilise le RID (Row Identifier, 8 octets) pour identifier de manière unique les lignes et les stocker sur des pages.

L'index cluster ne doit pas être une valeur aléatoire. Les données au niveau feuille seront stockées et ordonnées par la clé d'index. Par conséquent, il doit croître en permanence afin d'éviter la fragmentation ou le fractionnement de page. Si cela ne peut pas être réalisé par le PK, vous devez envisager une autre clé en tant que candidat en cluster. Un index clusterisé sur des colonnes d'identy, un GUID séquentiel ou même quelque chose comme la date de l'insertion est très bien d'un point de vue séquentiel puisque toutes les lignes seront ajoutées à la dernière page feuille. D'un autre côté, bien qu'un identifiant unique puisse être utile aux besoins de votre entreprise en tant que PK, il ne doit pas être mis en cluster (il est commandé / généré de manière aléatoire).

Si, après quelques analyses de données et de requêtes, vous découvrez que vous utilisez principalement le même index pour obtenir vos données avant d'effectuer une recherche de clé dans le PK en cluster, vous pouvez le considérer comme un index en cluster bien qu'il ne puisse pas identifier de manière unique vos données.

La clé d'index cluster est composée de toutes les colonnes que vous souhaitez indexer. Une colonne uniquefier (4 octets) est ajoutée s'il n'y a pas de contrainte unique (valeur incrémentielle pour les doublons, null sinon). Cette clé d'index sera ensuite stockée une fois pour chaque ligne au niveau feuille de tous vos index non cluster. Certains d'entre eux seront également stockés plusieurs fois à des niveaux intermédiaires (branche) entre la racine et le niveau feuille de l'arbre d'index (arbre B). Si la clé est trop grande, tout l'index non clusterisé s'agrandira, nécessitera plus de stockage et plus d'E / S, CPU, mémoire, ... Si vous avez un PK sur nom + date de naissance + pays, il est très probable que cette clé n'est pas un bon candidat. Il est trop grand pour un index clusterisé. Uniqueidentifier utilisant NEWSEQUENTIALID () n'est généralement pas considéré comme une clé étroite (16 octets) bien qu'il soit séquentiel.

Ensuite, une fois que vous avez compris comment identifier de manière unique les lignes de votre tableau, vous pouvez ajouter un PK. Si vous pensez que vous ne l’utiliserez pas dans votre requête, ne le créez pas en cluster. Vous pouvez toujours créer un autre index non cluster si vous avez parfois besoin de l'interroger. Notez que le PK créera automatiquement un index unique.

Les index non clusterisés contiendront toujours la clé clusterisée. Cependant, si les colonnes indexées (+ colonnes clés) couvrent, il n'y aura pas de recherche de clé dans l'index clusterisé. N'oubliez pas que vous pouvez également ajouter Inclure et Où à un index non cluster. (fais-en bon usage)

L'index cluster doit être unique et aussi étroit que possible. L'index cluster ne doit pas changer avec le temps et doit être inséré de manière incrémentielle.

Il est maintenant temps d'écrire du SQL qui créera la table, les index et les contraintes en cluster et non-cluster.

Tout cela est théorique car nous ne connaissons pas votre modèle de données et les types de données utilisés (A et B).


11

Pour une table avec une clé primaire (PK) sur une colonne d'identité, elle sera groupée par défaut. Pourrait-il être mieux que non cluster?

Si vous demandez si la valeur par défaut d'une clé primaire sur une colonne d'identité (en particulier) ne doit pas être mise en cluster, je dirais non. La plupart des tables ont l'avantage d'avoir un index clusterisé, donc faire du clustering la valeur par défaut pour une contrainte de clé primaire est probablement globalement utile, en particulier pour les nouveaux utilisateurs de SQL Server.

Comme avec à peu près n'importe quelle option, il existe toujours des circonstances différentes dans lesquelles l'une doit être préférée à l'autre, mais un administrateur de base de données expérimenté doit être conscient de la valeur par défaut et pouvoir la remplacer le cas échéant. Voir également les questions et réponses connexes. Quand faut-il déclarer une clé primaire non clusterisée? .

Les requêtes dans la question seront-elles plus rapides sans la mettre en cluster?

Oui, mais avec des mises en garde.

Les recherches RID sont en effet plus efficaces que les recherches de clés. Même si toutes les pages requises sont en mémoire (très probablement pour les niveaux supérieurs d'un index), il y a un coût CPU associé à la navigation dans l'arborescence b de l'index clusterisé. Par conséquent, SQL Server peut généralement effectuer beaucoup plus de recherches RID que de recherches de clés par unité de temps CPU.

Avertissements

Ce qui précède ne serait pas souvent un facteur déterminant pour décider de structurer une table comme un tas ou non. Il devrait être impossible d'éviter les recherches (en utilisant des index de couverture), et le nombre de recherches devrait être suffisamment important pour avoir un effet mesurable (et important) sur les performances, compte tenu de l'environnement matériel et de la charge de travail.

Il n'est pas vraiment pratique de couvrir tous les aspects du débat tas vs index clusterisé dans cette réponse, mais je dirai qu'il y a relativement peu de bonnes raisons de préférer structurer une table comme un tas en général. Pour moi, le choix du type de conception proposé dans la question nécessiterait une analyse très approfondie avant la mise en œuvre et devrait respecter une barre très élevée. Des arguments généraux sur «l'évolutivité» ne seraient pas suffisants.

En ce qui concerne la mise à jour de la question sur les jointures, l'évaluation de l'impact de la perte de l'index cluster sur les plans d'exécution ferait partie de l'analyse mentionnée ci-dessus. Si des jointures de boucles imbriquées sont utilisées, il est très pratique d'avoir l'index clusterisé sur la clé de jointure car toutes les colonnes de la ligne sont immédiatement disponibles sans recherche.

Ma propre expérience a été que le fait d'avoir des index clusterisés uniques sur les colonnes d'identité est très souvent bénéfique, tout est pris en compte. J'ai trouvé des tas problématiques en termes de gestion de l'espace, et je dois également mentionner que certaines fonctionnalités de SQL Server nécessitent un index cluster unique pour fonctionner.


8

En fait, vous n'avez pas besoin de créer d'index cluster ni de clé primaire, car les index uniques et les index non uniques peuvent gérer le travail. SQL Server prend en charge un index clusterisé depuis au moins la version 1.1, mais la clé primaire n'est qu'un «concept» que les programmeurs appliquent en définissant un index unique.

Mais il semble que les clés primaires et les index cluster sont des concepts précieux dans la majorité des bases de données.

Examinons la documentation de SQL Server pour voir les descriptions partielles de certaines options d'indexation comme indiqué ci-dessous.

Index en cluster: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Les index clusterisés trient et stockent les lignes de données dans la table ou la vue en fonction de leurs valeurs clés. Ce sont les colonnes incluses dans la définition d'index.
  • Il ne peut y avoir qu'un seul index clusterisé par table

Clé primaire: https://msdn.microsoft.com/en-us/library/ms190457.aspx

  • Une table ne peut contenir qu'une seule contrainte PRIMARY KEY.

  • Toutes les colonnes définies dans une contrainte PRIMARY KEY doivent être définies comme NOT NULL.

  • La clé primaire peut être créée en tant qu'index cluster (par défaut s'il n'y a pas d'index cluster) ou index non cluster.

Index unique: https://msdn.microsoft.com/en-us/library/ms187019.aspx

  • Lorsque vous créez une contrainte UNIQUE, un index non cluster unique est créé pour appliquer une contrainte UNIQUE par défaut.

  • Vous pouvez spécifier un index cluster unique si un index cluster n'existe pas déjà pour la table.

Cela signifie que votre question sur les index en cluster et les clés primaires concerne vraiment certains des problèmes suivants. Veuillez noter que toutes les tables ne bénéficient pas du même plan d'indexation.

Quand bénéficierais-je de la séparation de la clé primaire de l'index clusterisé?

Peut-être lorsque l'index clusterisé est large (par exemple, 5 colonnes d'informations textuelles, mais la clé primaire est petite (INT ou BIGINT), comme vous semblez le décrire.

  • Un large index clusterisé vous permettrait de sélectionner rapidement des lignes dans l'index pour un sous-ensemble de requêtes qui fournissent des réponses en série à partir de l' index cluster (également connu sous le nom de tableau ). Par exemple, un index clusterisé à 5 colonnes prendrait en charge le balayage des colonnes C1, C2, C3, C4, C5 ou C1, C2, C3, C4 et ainsi de suite jusqu'à C1.
  • Remarque: Si les lignes étaient grandes, cela pourrait vous donner des avantages de vitesse sur la sélection de l' ensemble série de lignes, en particulier si d'autres colonnes du tableau sont régulièrement incluses dans l'ensemble de résultats.
  • Dans ce cas, vous pouvez utiliser la clé primaire pour l'intégrité référentielle afin de fournir la valeur requise en tant que clé étrangère pour contraindre les lignes dans d'autres tables. Le PK est petit et est donc le FK est un petit coup sur la taille des tables référencées.
  • Cependant, notez que tout index créé sur une table qui a un index cluster inclura toutes les colonnes de cluster dans les autres index que vous créez sur cette table. Un index cluster étendu étendrait la taille de tous les index non cluster de cette table.

Devriez-vous faire de la clé primaire seule l'index clusterisé?

  • Si vous avez une petite clé primaire (INT ou BIGINT) et qu'il s'agit de l'index clusterisé, la surcharge des colonnes du cluster est relativement petite. Bien que la clé primaire en cluster dans ce cas existera également dans chaque index de cette table, c'est un prix inférieur à payer que le cluster large discuté ci-dessus.

  • Cet index clusterisé de clé primaire ne propose généralement pas directement un chemin facile pour sélectionner plusieurs lignes en série.

  • Maintenant que vous avez créé une clé primaire en cluster, qu'en est-il des autres colonnes que vous envisagiez d'inclure dans l'index en cluster ?

  • Créez un index unique (ou non unique) selon les besoins pour indexer ce large critère de recherche des colonnes C1, C2, C3, C4, C5. Les valeurs de cet index «Imitation Clustered» peuvent servir de chemin de recherche plus rapide pour ces 5 colonnes. S'il existe également une ou deux colonnes non indexées qui sont régulièrement sélectionnées, elles peuvent être incluses dans l'index avec INCLUDE (Doctor_Name, Diagnosis_Synopsis).

Bien que je trouve les index clusterisés simples et les clés primaires utiles, il existe de bonnes raisons de réfléchir à leur utilisation dans une table ou dans une base de données.

Avez-vous besoin d'un index clusterisé?

  • Si vous créez des index (index uniques et index non uniques) et définissez la clé primaire sans surcharger d'être un index clusterisé, vous pouvez constater que les index plus étroits vous fournissent ce dont vous avez besoin pour vos requêtes.

  • Il existe certains comportements utiles dans les index clusterisés et les clés primaires, mais n'oubliez pas que ce sont vraiment les index qui importent le plus. Concevez la stratégie d'indexation pour prendre en compte les réalités de votre application. Peut-être le OneBigTablebesoin d'avoir une stratégie d'indexation différente de celle que vous utilisez pour la plupart des tables.

  • Sans un index clusterisé, vos données seront stockées sous forme de tas avec l'identificateur de ligne (RID) qui n'est pas du tout un bon mécanisme de recherche. Mais, comme mentionné précédemment, vous pouvez créer des index uniques et non uniques pour gérer vos requêtes.

Ce qui vous amène maintenant à considérer les tas:

Tas et index: https://msdn.microsoft.com/en-us/library/hh213609.aspx

  • Lorsqu'une table est stockée en tant que segment de mémoire, les lignes individuelles sont identifiées par référence à un identificateur de ligne (RID) composé du numéro de fichier, du numéro de la page de données et de l'emplacement sur la page. L'identifiant de ligne est une structure petite et efficace. (Mais ce n'est pas un index .)
  • Parfois, les architectes de données utilisent des tas lorsque les données sont toujours accessibles via des index non clusterisés et que le RID est plus petit qu'une clé d'index cluster .

Mais si vous avez également des «points chauds» dans un ensemble de données volumineuses, vous pouvez également rechercher un autre type d'index:

Index filtré: https://msdn.microsoft.com/en-us/library/cc280372.aspx

  • Un index filtré bien conçu améliore les performances des requêtes et la qualité du plan d'exécution car il est plus petit qu'un index non cluster de table complète et possède des statistiques filtrées. Les statistiques filtrées sont plus précises que les statistiques de table complète car elles ne couvrent que les lignes de l'index filtré .

  • Les index filtrés ont un certain nombre de restrictions qui sont décrites dans le lien vers les index filtrés.

Cependant, si vous êtes intéressé à penser à cette possibilité de sauter les clés primaires et les index clusterisés, vous pouvez lire le post de Markus Winand lié ci-dessous. Il démontre ses raisons, avec quelques exemples de code, pour suggérer que ce serait parfois une bonne idée de renoncer à utiliser ces fonctionnalités.

http://use-the-index-luke.com/blog/2014-01/unreasonable-defaults-primary-key-clustering-key

Mais tout revient finalement à comprendre votre application et à concevoir le code, les tables, les index, etc. pour s'adapter au travail que vous faites.


Pour ce que ça vaut, dans mon travail quotidien, si je trouve une table qui est un tas, je considère que c'est probablement une erreur et je vérifie auprès des développeurs pour voir si elle a été faite intentionnellement.
RLF

-2

Quelques points à considérer.

Alors qu'un index (en cluster ou non) sur une valeur augmentant de façon monotone vous évite les sauts de page lors des insertions de masse, il crée un nouveau point chaud à la fin de l'index. Bien que cela ne soit pas un problème avec une insertion en bloc à un seul thread, cela augmentera certainement les conflits pour une application multithread insérant de nouveaux tuples à un taux élevé, car les threads seront constamment en concurrence pour accéder à la dernière page de l'index.

Le regroupement de la table sur la base d'une PK de substitution (identité) est rarement bénéfique. Une telle clé primaire est principalement utilisée pour accéder à des tuples individuels, un par un, ou pour analyser l'intégralité de l'index à la recherche de jointures. Dans les deux cas, peu importe que l'index soit en cluster ou non (à l'exception des jointures de fusion, peut-être, mais à quelle fréquence sont-elles?)

Je pense que vous bénéficierez le plus d'un index cluster qui couvre les requêtes demandant une analyse des plages de clés et des prédicats supplémentaires référençant d'autres colonnes.


Quel doit être le taux pour que cela devienne réellement un problème?
ypercubeᵀᴹ

@ypercube puis-je dire "ça dépend"? Parce que c'est le cas. En l'absence de déclencheurs sur la table, je m'attends à commencer à rencontrer des conflits avec une douzaine de threads totalisant 1 000 insertions par seconde.
mustaccio


Je ne suis pas en désaccord mais je demandais jusqu'où on peut aller avec un seul point chaud. Je me souviens avoir vu un article sur l'insertion de 30 000 lignes par seconde dans un tableau avec IDENTITÉ comme CI (si la mémoire me sert bien) mais je ne trouve pas le billet de blog.
ypercubeᵀᴹ

Cette discussion est inutile en l'absence d'une charge de travail concrète s'exécutant sur un schéma concret sur du matériel spécifique. J'espère que nous pouvons tous convenir qu'un index sur une séquence augmentant de façon monotone créera un «point chaud»; si cela créera un goulot d'étranglement inacceptable et si l'on doit s'en préoccuper ou non, cela dépend des circonstances.
mustaccio
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.