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.
Premièrement, lorsque vous voyez une table de réflexion d' index clusterisé . 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 EST votre table il n'est pas séparé 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 la notation O ou l' 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.
Ainsi, le nombre d'opérations ou de notation O pour l'opération de recherche est le suivant:
- Effectuez une recherche binaire sur un index clusterisé en comparant la valeur recherchée aux valeurs du niveau intermédiaire.
- 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:
Il y a deux choses importantes à noter dans la capture d'écran ci-dessus
- 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.
- 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:
- Effectuer une recherche binaire sur un index non clusterisé en comparant la valeur recherchée aux valeurs du niveau intermédiaire
- 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).
- Pour chaque valeur retournée, effectuez une lecture sur l'index cluster (la table) pour obtenir les valeurs de ligne ici, nous lirions le CustomerSurname.
- 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.
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.