web-dev-qa-db-fra.com

Différence de performances entre les index cluster et non cluster

Je lisais Clustered et Non Clustered Indexes.

Clustered Index - Il contient des pages de données. Cela signifie que les informations de ligne complètes seront présentes dans la colonne d'index clusterisé.

Non Clustered Index - Il contient uniquement les informations du localisateur de lignes sous la forme d'une colonne d'index clusterisé (si disponible) ou de l'identificateur de fichier + numéro de page + nombre total de lignes dans une page. Cela signifie que le moteur de requête doit effectuer une étape supplémentaire afin de localiser les données réelles.

Requête - Comment puis-je vérifier la différence de performances à l'aide d'un exemple pratique car nous savons que la table ne peut avoir qu'un seul Clustered Index et fournit sorting au Clustered Index Column et Non Clustered Index ne fournit pas sorting et peut prendre en charge 999 Non Clustered Indexes dans SQL Server 2008 et 249 dans SQL Server 2005.

22
Pankaj Garg

Très bonne question car c'est un concept si important. C'est un gros sujet cependant et ce que je vais vous montrer est une simplification afin que vous puissiez comprendre les concepts de base.

Tout d'abord, lorsque vous voyez un index cluster , pensez à la table . Dans SQL Server, si une table ne contient pas d'index cluster, il s'agit d'un segment. La création d'un index cluster sur la table transforme en fait la table en une structure de type b-tree. Votre index cluster IS votre table elle n'est pas séparée de la table

Vous êtes-vous déjà demandé pourquoi vous ne pouvez avoir qu'un seul index cluster? Eh bien, si nous avions deux index clusterisés, nous aurions besoin de deux copies de la table. Il contient les données après tout.

Je vais essayer d'expliquer cela en utilisant un exemple simple.

REMARQUE: J'ai créé le tableau dans cet exemple et l'ai rempli avec plus de 3 millions d'entrées aléatoires. Ensuite, a exécuté les requêtes réelles et collé les plans d'exécution ici.

Ce que vous devez vraiment comprendre, c'est notation O ou efficacité opérationnelle. Supposons que vous ayez le tableau suivant.

CREATE TABLE [dbo].[Customer](
[CustomerID] [int] IDENTITY(1,1) NOT NULL,
[CustomerName] [varchar](100) NOT NULL,
[CustomerSurname] [varchar](100) NOT NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
(
[CustomerID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , IGNORE_DUP_KEY = OFF,ALLOW_ROW_LOCKS  = ON
  , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Nous avons donc ici une table de base avec une clé en cluster sur CustomerID (la clé primaire est en cluster par défaut). Ainsi, la table est organisée/ordonnée en fonction de la clé primaire CustomerID. Les niveaux intermédiaires contiendront les valeurs CustomerID. Les pages de données contiendront la ligne entière, c'est donc la ligne du tableau.

Nous allons également créer un index non clusterisé sur le champ CustomerName. Le code suivant le fera.

CREATE NONCLUSTERED INDEX [ix_Customer_CustomerName] ON [dbo].[Customer] 
 (
[CustomerName] ASC
 )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF
  , SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF
  , DROP_EXISTING = OFF, ONLINE = OFF
  , ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Ainsi, dans cet index, vous trouverez sur les pages de données/nœuds de niveau feuille un pointeur vers les niveaux intermédiaires de l'index clusterisé. L'index est organisé/ordonné autour du champ CustomerName. Ainsi, le niveau intermédiaire contient les valeurs CustomerName et le niveau feuille contiendra le pointeur (ces valeurs de pointeur sont en fait les valeurs de clé primaire ou la colonne CustomerID).

Exactement si nous exécutons la requête suivante:

SELECT * FROM Customer WHERE CustomerID = 1 

SQL lira probablement l'index clusterisé via une opération de recherche. Une opération de recherche est une recherche binaire qui est beaucoup plus efficace qu'une analyse qui est une recherche séquentielle. Ainsi, dans notre exemple ci-dessus, l'index est lu et en utilisant une recherche binaire, SQL peut éliminer les données qui ne correspondent pas aux critères que nous recherchons. Voir la capture d'écran ci-jointe pour le plan de requête.

enter image description here

Ainsi, le nombre d'opérations ou de notation O pour l'opération de recherche est le suivant:

  1. Effectuez une recherche binaire sur un index clusterisé en comparant la valeur recherchée aux valeurs du niveau intermédiaire.
  2. Renvoyer les valeurs qui correspondent (rappelez-vous que puisque l'index cluster contient toutes les données, il peut renvoyer toutes les colonnes de l'index car ce sont les données de ligne)

Il s'agit donc de deux opérations. Cependant, si nous avons exécuté la requête suivante:

SELECT * FROM Customer WHERE CustomerName ='John'

SQL va maintenant utiliser l'index non clusterisé sur le CustomerName pour effectuer la recherche. Cependant, puisqu'il s'agit d'un index non clusterisé, il ne contient pas toutes les données de la ligne.

Ainsi, SQL effectuera la recherche aux niveaux intermédiaires pour trouver les enregistrements qui correspondent, puis effectuera une recherche en utilisant les valeurs renvoyées pour effectuer une autre recherche sur l'index cluster (alias la table) pour récupérer les données réelles. Cela semble déroutant, je sais, mais lisez la suite et tout deviendra clair.

Étant donné que notre index non clusterisé ne contient que le champ CustomerName (les valeurs de champ indexées stockées dans les nœuds intermédiaires) et le pointeur vers les données qui sont le CustomerID, l'index n'a pas d'enregistrement de CustomerSurname. Le CustomerSurname doit être récupéré à partir de l'index ou de la table en cluster.

Lors de l'exécution de cette requête, j'obtiens le plan d'exécution suivant:

enter image description here

Il y a deux choses importantes à noter dans la capture d'écran ci-dessus

  1. SQL dit que j'ai un index manquant (le texte en vert). SQL suggère que je crée un index sur CustomerName qui inclut CustomerID et CustomerSurname.
  2. Vous verrez également que 99% du temps de la requête est consacré à la recherche de clé sur l'index de clé primaire/l'index clusterisé.

Pourquoi SQL suggère-t-il à nouveau l'index sur CustomerName? Eh bien, puisque l'index contient uniquement le CustomerID et le CustomerName SQL doit toujours trouver le CustomerSurname à partir des index de table/cluster.

Si nous avons créé l'index et que nous avons inclus la colonne CustomerSurname dans l'index, SQL pourrait satisfaire l'intégralité de la requête en lisant simplement l'index non cluster. C'est pourquoi SQL suggère que je modifie mon index non clusterisé.

Ici, vous pouvez voir l'opération supplémentaire que SQL doit faire pour obtenir la colonne CustomerSurname à partir de la clé en cluster

Ainsi, le nombre d'opérations est le suivant:

  1. Effectuer une recherche binaire sur un index non clusterisé en comparant la valeur recherchée aux valeurs du niveau intermédiaire
  2. Pour les nœuds qui correspondent, lisez le nœud de niveau feuille qui contiendra le pointeur pour les données dans l'index clusterisé (les nœuds de niveau feuille contiendront d'ailleurs les valeurs de clé primaire).
  3. Pour chaque valeur retournée, faites une lecture sur l'index clusterisé (la table) pour obtenir les valeurs de ligne ici, nous lirions le CustomerSurname.
  4. Renvoyer les lignes correspondantes

Il s'agit de 4 opérations pour extraire les valeurs. Deux fois le nombre d'opérations nécessaires par rapport à la lecture de l'index clusterisé. Ils vous montrent que votre index cluster est votre index le plus puissant car il contient toutes les données.

Juste pour clarifier un dernier point. Pourquoi dois-je dire que le pointeur dans l'index non cluster est la valeur de clé primaire? Eh bien pour démontrer que les nœuds de niveau feuille de l'index non clusterisé contiennent la valeur de clé primaire, je change ma requête en:

SELECT CustomerID
FROM Customer
WHERE CustomerName='Jane'

Dans cette requête, SQL peut lire le CustomerID à partir de l'index non cluster. Il n'a pas besoin d'effectuer une recherche sur l'index clusterisé. Vous pouvez le voir sur le plan d'exécution qui ressemble à ceci.

enter image description here

Notez la différence entre cette requête et la requête précédente. Il n'y a pas de recherche. SQL peut trouver toutes les données dans l'index non clusterisé

J'espère que vous pourrez commencer à comprendre que l'index cluster est la table et que les index non cluster NE contiennent PAS toutes les données. L'indexation accélérera les sélections car les recherches binaires peuvent être effectuées mais seuls les index clusterisés contiennent toutes les données. Ainsi, une recherche sur un index non clusterisé entraînera presque toujours le chargement de valeurs à partir de l'index clusterisé. Ces opérations supplémentaires rendent les index non cluster moins efficaces qu'un index cluster.

Espérons que cela arrange les choses. Si quelque chose n'a pas de sens, veuillez poster un commentaire et je vais essayer de clarifier. Il est assez tard ici et mon cerveau se sent un peu plat. Il est temps pour un taureau rouge.

43
Namphibian

"Cela signifie que le moteur de requête doit effectuer une étape supplémentaire afin de localiser les données réelles."

Pas nécessairement - si l'index couvre une requête donnée, aucun déplacement ne doit être effectué vers les pages de données. En outre, avec les colonnes incluses, des colonnes supplémentaires peuvent être ajoutées à un index non clusterisé pour le rendre couvrant sans modifier la taille de la clé.

Donc, la réponse ultime est - cela dépend (sur beaucoup plus d'informations que vous ne pouvez vraiment couvrir dans une seule question) - vous devez comprendre toutes les capacités des index et le plan d'exécution pour une requête donnée peut différer de vos attentes.

Une règle générale que j'ai est qu'une table a toujours un index clusterisé (et généralement sur une identité ou un GUID séquentiel), mais des index non clusterisés sont ajoutés pour les performances. Mais il y a toujours des exceptions - les tables de tas ont une place, les index cluster plus larges ont une place. Les index apparemment redondants qui sont plus étroits pour contenir plus de lignes par page ont une place. etc.

Et je ne m'inquiéterais pas des limites des différents index autorisés - cela ne va certainement pas entrer en jeu dans de nombreux exemples du monde réel.

9
Cade Roux