web-dev-qa-db-fra.com

Clustered vs non-clustered

Mes connaissances de base de SQL (Server 2008) sont limitées et nos administrateurs de base de données nous ont lancé un défi. Laissez-moi vous 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-le-moi, s'il vous plaît), le scénario:

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

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é). Mes raisons sont que c'est un champ unique (clé primaire), et devrait être indexé, principalement à des fins de sélection, comme nous le faisons souvent Select from table where primary key = ...

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

J'ai été interpellé à ce sujet maintenant. On m'a dit que nous devrions placer l'index clusterisé sur la clé primaire et l'index normal sur le personId. Cela me semble très étrange. Tout d'abord, pourquoi voudriez-vous mettre un index clusterisé sur une colonne unique? qu'est-ce que ça regroupe? 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, la mise en cluster de l'index signifie que nous ne pouvons pas mettre en cluster une colonne différente (une par table, n'est-ce pas?).

La raison pour laquelle je me suis fait dire que je me suis trompé est qu’ils pensent que le fait de placer un index en cluster sur le PersonId ralentirait les insertions. Avec un gain de vitesse de 5% en sélection, nous obtiendrions une dégradation de 95% de la vitesse des insertions et des 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 CLUSTERÉ, 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 est utilisé plus qu'INSERT ... mais ils disent que nous rencontrons des problèmes de verrouillage sur INSERTS ...

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

95
Craig

La distinction entre un index clusterisé et non clusterisé est que l'index clusterisé détermine l'ordre physique des lignes dans la base de données. En d’autres termes, appliquer l’index clusterisé à PersonId signifie que les lignes seront physiquement triées par PersonId dans la table, permettant ainsi à une recherche d’index sur celle-ci d’aller directement à la ligne (plutôt qu’une index non-cluster, qui vous dirigerait vers l'emplacement de la ligne, en ajoutant une étape supplémentaire).

Cela dit, il est inhabituel que la clé primaire ne soit pas un index clusterisé, mais pas inconnue. Le problème de votre scénario est en réalité l'opposé de ce que vous supposez: vous voulez des valeurs niques dans un index clusterisé, pas des doublons. Comme l'index en cluster détermine l'ordre physique de la ligne, s'il 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 ayant le même PersonId) afin que la valeur combinée (clé + valeur d'arrière-plan) soit unique.

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

115
Adam Robinson

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

Les insertions sur des index en cluster (ordonnés physiquement) qui ne sont pas dans un ordre séquentiel occasionnent un travail supplémentaire pour les insertions/mises à jour. De plus, si vous avez plusieurs insertions à la fois et qu'elles se produisent toutes au même endroit, vous vous retrouvez avec des conflits. 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 est de construire votre index clusterisé sur la valeur étroite la plus unique de votre table (généralement la 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

Maintenant, insérez 20 nouvelles lignes pour PersonId de 3. Premièrement, comme il ne s’agit pas d’une clé unique, le serveur ajoute des octets supplémentaires à votre valeur (en coulisse) 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 ont lieu à la fin. L'explication non technique résulterait probablement en ceci: il y a moins de travail de "mélange de feuilles" à faire si les valeurs progressent naturellement à la fin du tableau par rapport au lieu de modification des éléments existants à cet emplacement lors de l'insertion de vos éléments.

Maintenant, si vous rencontrez des problèmes avec les insertions, il est probable que vous insériez un ensemble de valeurs PersonId identiques (ou similaires) à la fois, ce qui provoque ce travail supplémentaire à différents endroits de la table et la fragmentation vous tue. L’inconvénient du passage à la PK en cluster dans votre cas, c’est si vous rencontrez aujourd’hui des problèmes d’insertion sur des PersonIds dont la valeur varie en fonction de la répartition du tableau, si vous basculez votre index clusterisé vers la PK et que toutes les insertions ont maintenant lieu en une seule fois. votre problème peut s’aggraver en raison de la concentration accrue des conflits. (D'un autre côté, si vos insertions actuelles ne sont pas éparpillées, mais sont généralement regroupées dans des zones similaires, votre problème s'atténuera probablement en basculant votre index en cluster de PersonId vers votre PK, car vous réduirez la fragmentation.)

Vos problèmes de performance doivent être analysés en fonction de votre situation unique et prendre ces types de réponses à titre de directives générales uniquement. Votre meilleur choix est de faire appel à un administrateur de base de données capable de valider exactement où se situent vos problèmes. Il semble que vous ayez des problèmes de conflits de ressources qui dépassent le simple index Tweak. Cela pourrait être le symptôme d'un problème beaucoup plus vaste. (Problèmes de conception probables… sinon des ressources limitées.)

En tout cas, bonne chance!

13
Darian Miller

Certains auteurs suggèrent de ne pas "gaspiller" le CI sur une colonne identity s'il existe une alternative qui pourrait bénéficier aux requêtes par plage.

À partir de MSDN Directives de conception d'index clusterisés , la clé doit être choisie en fonction des critères suivants

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

Votre colonne CourtOrderID rencontre 2. Votre PersonId rencontre 1 Et 3. Comme la plupart des lignes se retrouvent avec le uniqueifier ajouté de toute façon, vous pouvez tout aussi bien le déclarer comme unique et utiliser PersonId,CourtOrderID, Car il aura la même largeur mais sera plus utile car la clé d'index cluster est ajouté à tous les NCI en tant que localisateur de ligne, ce qui leur permettra de couvrir davantage de requêtes.

Le principal problème lié à l'utilisation de PersonId,CourtOrderID En tant qu'EC est que la fragmentation logique s'ensuivra probablement (et que cela affecte en particulier les requêtes de plage que vous essayez d'aider). entretien plus souvent.

5
Martin Smith

C'est expliqué dans le lien suivant: https://msdn.Microsoft.com/en-us/ms190457.aspx

en cluster

  • Index clusterisés triez et stockez 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 de l'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é correspond au moment où la table contient un index en cluster. Lorsqu'une table a un index clusterisé, elle est appelée une 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é c contient les valeurs de clé d'index non clusterisé et chaque entrée de valeur de clé a un pointeur sur la ligne de données contenant la valeur de clé.

  • Le pointeur d'une ligne d'index d'un index non clusterisé vers une ligne de données s'appelle un localisateur de ligne. 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 segment de mémoire, un localisateur de ligne est un pointeur sur la ligne. Pour une table en cluster, le localisateur de ligne est la clé d'index en 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 de clés, et exécuter des requêtes indexées entièrement couvertes.

3
user2191454