En cluster ou non en cluster

98

Ma connaissance de niveau inférieur de SQL (Server 2008) est limitée et est maintenant remise en question par nos DBA. Permettez-moi d'expliquer (j'ai mentionné des déclarations évidentes dans l'espoir d'avoir raison, mais si vous voyez quelque chose qui ne va pas, dites-moi s'il vous plaît) le scénario:

Nous avons une table qui contient des «ordonnances judiciaires» pour les gens. Lorsque j'ai créé la table, (Nom: CourtOrder), je l'ai créée comme:

CREATE TABLE dbo.CourtOrder
(
  CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key)
  PersonId INT NOT NULL,
  + around 20 other fields of different types.
)

J'ai ensuite appliqué un index non clusterisé à la clé primaire (pour plus d'efficacité). Ma raison est qu'il s'agit d'un champ unique (clé primaire), et devrait être indexé, principalement à des fins de sélection, comme nousSelect from table where primary key = ...

J'ai ensuite appliqué un index CLUSTERED sur PersonId. La raison était de regrouper physiquement les commandes d'une personne en particulier, car la grande majorité du travail consiste à obtenir des commandes pour une personne. Alors,select from mytable where personId = ...

J'ai été tiré dessus maintenant. On m'a dit que nous devrions mettre l'index clusterisé sur la clé primaire et l'index normal sur le personId. Cela me semble très étrange. Tout d'abord, pourquoi placeriez-vous un index clusterisé sur une colonne unique? qu'est-ce que le clustering? C'est sûrement un gaspillage de l'index clusterisé? J'aurais cru qu'un index normal serait utilisé sur une colonne unique. De plus, le regroupement de l'index signifierait que nous ne pouvons pas regrouper une colonne différente (une par table, non?).

Le raisonnement pour lequel on me dit que j'ai fait une erreur est qu'ils pensent que mettre un index groupé sur PersonId ralentirait les insertions. Pour le gain de vitesse de 5% d'une sélection, nous obtiendrions une dégradation de 95% de la vitesse sur les insertions et les mises à jour. Est-ce correct et valide?

Ils disent que parce que nous regroupons le personId, SQL Server doit réorganiser les données chaque fois que nous insérons ou modifions le PersonId.

Alors j'ai demandé, pourquoi SQL aurait-il le concept d'un INDEX CLUSTERED, si c'est si lent? Est-ce aussi lent qu'ils le disent? Comment dois-je configurer mes index pour obtenir des performances optimales? J'aurais pensé que SELECT était plus utilisé que INSERT ... mais ils disent que nous avons des problèmes de verrouillage sur INSERTS ...

J'espère que quelqu'un pourra m'aider.

Craig
la source

Réponses:

117

La distinction entre un index clusterisé et non clusterisé est que l'index cluster détermine l'ordre physique des lignes dans la base de données . En d'autres termes, appliquer l'index clusterisé à PersonIdsignifie que les lignes seront physiquement triées PersonIddans la table, ce qui permet à une recherche d'index à ce sujet d'aller directement à la ligne (plutôt qu'à un index non groupé, qui vous dirigerait vers la ligne. emplacement, en ajoutant une étape supplémentaire).

Cela dit, il est inhabituel que la clé primaire ne soit pas l'index clusterisé, mais ce n'est pas inconnu. Le problème avec votre scénario est en fait le contraire de ce que vous supposez: vous voulez des valeurs uniques dans un index clusterisé, pas des doublons. Étant donné que l'index cluster détermine l'ordre physique de la ligne, si l'index est sur une colonne non unique, le serveur doit ajouter une valeur d'arrière-plan aux lignes qui ont une valeur de clé en double (dans votre cas, toutes les lignes avec la même valeur PersonId) afin que la valeur combinée (clé + valeur d'arrière-plan) soit unique.

La seule chose que je suggérerais est de ne pas utiliser une CourtOrderIdcolonne de clé de substitution (votre ) comme clé primaire, mais plutôt d'utiliser une clé primaire composée de la PersonIdet d'une autre colonne ou d'un ensemble de colonnes à identification unique. Si ce n'est pas possible (ou pas pratique), activez l'index clusterisé CourtOrderId.

Adam Robinson
la source
Merci Adam. Alors, quand un index clusterisé serait-il utile alors? Je pensais que l'avantage de l'index clusterisé était de regrouper les données, pour les moments où, par exemple, la plupart des requêtes sont sur un PersonID ... donc les données seraient regroupées.
Craig
3
Il n'est pas trié physiquement par PersonId. Il est trié logiquement par PersonId, tout écart entre l'ordre logique et physique est le degré de fragmentation logique.
Martin Smith
1
@cdotlister L'avantage d'un index est de trier les données, pas de les regrouper (ce qui impliquait des données dupliquées dans l'index). Si la distinction peut sembler sémantique, dans le cas d'index groupés, elle ne l'est pas. Si possible, l'index clusterisé doit se trouver sur quelque chose qui identifie de manière unique la ligne et (idéalement) est également la colonne ou l'ensemble de colonnes le plus fréquemment interrogé. C'est pourquoi il se trouve généralement sur la clé primaire.
Adam Robinson
1
@CyberSluethOmega: Je ne sais pas; votre question ne contient pas suffisamment d'informations pour que je puisse prendre une décision. Voudrais-je un index clusterisé sur un ensemble de colonnes où des lignes seraient fréquemment ajoutées ou supprimées autrement qu'à la fin de la table ? Non. Mais je ne sais pas vraiment pourquoi vous demandez cela ou pourquoi le vote négatif.
Adam Robinson
1
@CyberSluethOmega: Internet peut faire des commentaires défensifs ou froids lorsqu'ils ne sont pas prévus de cette façon. Vous avez prétendu que j'avais dit que je n'avais connaissance d'aucune circonstance où faire de l'index groupé autre chose que la clé primaire, alors qu'en fait je n'ai rien dit de tel. En fait, ce que je disais était «c'est inhabituel ..., mais pas du jamais vu », ce qui veut dire que je ne connais des cas où cela se fait.
Adam Robinson
14

Je ne suis en aucun cas un expert SQL ... alors prenez cela comme une vue de développeur plutôt qu'une vue DBA.

Les insertions sur des index en cluster (ordonnés physiquement) qui ne sont pas dans l'ordre séquentiel entraînent un travail supplémentaire pour les insertions / mises à jour. De plus, si de nombreuses insertions se produisent en même temps et qu'elles se produisent toutes au même endroit, vous vous retrouvez avec une contention. Vos performances spécifiques varient en fonction de vos données et de la manière dont vous y accédez. La règle générale consiste à créer votre index clusterisé sur la valeur étroite la plus unique de votre table (généralement le PK)

Je suppose que votre PersonId ne changera pas, donc les mises à jour n'entrent pas en jeu ici. Mais considérons un instantané de quelques lignes avec PersonId de 1 2 3 3 4 5 6 7 8 8

Insérez maintenant 20 nouvelles lignes pour PersonId de 3. Premièrement, comme il ne s'agit pas d'une clé unique, le serveur ajoute quelques octets supplémentaires à votre valeur (dans les coulisses) pour la rendre unique (ce qui ajoute également de l'espace supplémentaire), puis l'emplacement où ceux-ci résideront doivent être modifiés. Comparez cela à l'insertion d'un PK auto-incrémenté où les insertions se produisent à la fin. L'explication non technique se résumerait probablement à ceci: il y a moins de travail de `` mélange de feuilles '' à faire s'il progresse naturellement des valeurs plus élevées à la fin du tableau que de retravailler l'emplacement des éléments existants à cet emplacement lors de l'insertion de vos éléments.

Maintenant, si vous rencontrez des problèmes avec les insertions, vous insérez probablement un tas de valeurs PersonId identiques (ou similaires) à la fois, ce qui provoque ce travail supplémentaire à divers endroits de la table et la fragmentation vous tue. L'inconvénient du passage au PK en cluster dans votre cas, c'est que si vous rencontrez des problèmes d'insertion aujourd'hui sur des PersonIds dont la valeur varie dans la table, si vous basculez votre index cluster sur le PK et que toutes les insertions se produisent maintenant en un emplacement, votre problème peut en fait s'aggraver en raison d'une concentration accrue de conflits. (D'un autre côté, si vos inserts aujourd'hui ne sont pas répartis partout, mais sont généralement regroupés dans des zones similaires, votre problème sera probablement atténué en faisant passer votre index cluster de PersonId à votre PK car vous minimiserez le fragmentation.)

Vos problèmes de performance doivent être analysés en fonction de votre situation particulière et ne prendre ces types de réponses que comme des directives générales. Votre meilleur pari est de compter sur un DBA qui peut valider exactement où se situent vos problèmes. Il semble que vous ayez des problèmes de conflit de ressources qui peuvent aller au-delà d'un simple ajustement d'index. Cela pourrait être le symptôme d'un problème beaucoup plus vaste. (Problèmes de conception probables ... sinon limitations de ressources.)

Dans tous les cas, bonne chance!

Darian Miller
la source
5

Certains auteurs suggèrent de ne pas «gaspiller» le CIsur une identitycolonne s'il existe une alternative qui profiterait aux requêtes de plage.

D'après les directives de conception d'index en cluster MSDN, la clé doit être choisie en fonction des critères suivants

  1. Peut être utilisé pour les requêtes fréquemment utilisées.
  2. Fournit un haut degré d'unicité.
  3. Peut être utilisé dans les requêtes de plage.

Votre CourtOrderIDcolonne se réunit 2. Vos PersonIdrencontres 1et 3. Comme la plupart des lignes finiront avec l' uniqueifierajout de toute façon, vous pouvez tout aussi bien le déclarer comme unique et l'utiliser PersonId,CourtOrderIDcar il aura la même largeur, mais sera plus utile car la clé d'index cluster est ajoutée à tous les NCI en tant que localisateur de lignes, ce qui permettra eux pour couvrir plus de requêtes.

Le principal problème avec l'utilisation en PersonId,CourtOrderIDtant que CI est que la fragmentation logique s'ensuivra probablement (et cela affecte particulièrement les requêtes de plage que vous essayez d'aider), vous devrez donc surveiller le facteur de remplissage et les niveaux de fragmentation et effectuer la maintenance de l'index plus souvent.

Martin Smith
la source
3

Il est expliqué dans le lien suivant: https://msdn.microsoft.com/en-us/ms190457.aspx

Clustered

  • Les index clusterisés trient et stockent les lignes de données dans la table ou la vue en fonction de leurs valeurs de clé. Ce sont les colonnes incluses dans la définition d'index. Il ne peut y avoir qu'un seul index clusterisé par table, car les lignes de données elles-mêmes ne peuvent être triées que dans un seul ordre.

  • Le seul moment où les lignes de données d'une table sont stockées dans un ordre trié est lorsque la table contient un index cluster. Lorsqu'une table a un index clusterisé, la table est appelée table clusterisée. Si une table n'a pas d'index clusterisé, ses lignes de données sont stockées dans une structure non ordonnée appelée tas.

Non clusterisé

  • Les index non clusterisés ont une structure distincte des lignes de données. Un index non clusterisé contient les valeurs de clé d'index non clusterisé et chaque entrée de valeur de clé a un pointeur vers la ligne de données qui contient la valeur de clé .

  • Le pointeur d'une ligne d'index dans un index non clusterisé vers une ligne de données est appelé un localisateur de lignes. La structure du localisateur de lignes varie selon que les pages de données sont stockées dans un tas ou dans une table en cluster. Pour un tas, un localisateur de ligne est un pointeur vers la ligne. Pour une table en cluster, le localisateur de lignes est la clé d'index cluster.

  • Vous pouvez ajouter des colonnes non clés au niveau feuille de l'index non clusterisé pour contourner les limites de clé d'index existantes, 900 octets et 16 colonnes clés, et exécuter des requêtes entièrement couvertes et indexées.

user2191454
la source
-3

Une certaine base de données avec des sélections désagréables se joint à une procédure stockée - seule la différence est l'index

INDEXES - en cluster ou non en cluster

  891 rows
  10 sec
  NONCLUSTERED 

  OR

  891 rows
  14 sec
  CLUSTERED
toLucky
la source