Le plan d'exécution n'utilise PAS INDEX, il utilise l'analyse de table

9

Je sais quand il s'agit d'utiliser un index ou une analyse de table, SQL Server utilise des statistiques pour voir laquelle est la meilleure.

J'ai une table avec 20 millions de lignes. J'ai un index sur (SnapshotKey, Measure) et cette requête:

select Measure, SnapshotKey, MeasureBand
from t1
where Measure = 'FinanceFICOScore'
group by Measure, SnapshotKey, MeasureBand

La requête renvoie 500 000 lignes. Ainsi, la requête ne sélectionne que 2,5% des lignes de la table.

La question est pourquoi SQL Server n'utilise pas l'index non cluster que j'ai et utilise à la place une analyse de table?

Les statistiques sont mises à jour.

Bon de mentionner que les performances de la requête sont bonnes cependant.

Scan de table

Scan de table

Index forcé

Indice de force

Structure de table / index

CREATE TABLE [t1](
    [SnapshotKey] [int] NOT NULL,
    [SnapshotDt] [date] NOT NULL,
    [Measure] [nvarchar](30) NOT NULL,
    [MeasureBand] [nvarchar](30) NOT NULL,
    -- and many more fields
) ON [PRIMARY]

Pas de PK sur table, car c'est un entrepôt de données.

CREATE NONCLUSTERED INDEX [nci_SnapshotKeyMeasure] ON [t1]
(
    [SnapshotKey] ASC,
    [Measure] ASC
)

la source

Réponses:

16

La recherche d'index n'est peut-être pas le meilleur choix si vous renvoyez de nombreuses lignes et / ou si les lignes sont très larges. Les recherches peuvent être coûteuses si votre index ne couvre pas. Voir # 2 ici .

Dans votre scénario, l'optimiseur de requêtes estime que l'exécution de 50 000 recherches individuelles coûtera plus cher qu'une seule analyse. Le choix de l'optimiseur entre l'analyse et la recherche (avec des recherches RID pour les colonnes nécessaires à la requête, mais non présentes dans l'index non cluster) est basé sur le coût estimé de chaque alternative.

L'optimiseur choisit toujours l'alternative la moins chère qu'il considère. Si vous regardez la propriété Coût de sous-arbre estimé dans le nœud racine des deux plans d'exécution, vous verrez que le plan d'analyse a un coût estimé inférieur au plan de recherche. Par conséquent, l'optimiseur a choisi l'analyse. C'est essentiellement la réponse à votre question.

Désormais, le modèle de coût utilisé par l'optimiseur est basé sur des hypothèses et des "nombres magiques" qui ne correspondent probablement pas aux performances de votre système. En particulier, une hypothèse émise dans le modèle est que la requête commence à s'exécuter avec aucune des données ou pages d'index requises déjà en mémoire. Un autre est que les E / S séquentielles (attendues pour une analyse) sont moins chères que le modèle d'E / S aléatoire supposé pour les recherches RID. Il existe de nombreuses autres hypothèses et mises en garde de ce type, beaucoup trop pour être détaillées ici.

Néanmoins, il a été démontré que le modèle de coût dans son ensemble produit des plans généralement "assez bons" pour la plupart des requêtes, sur la plupart des schémas de base de données, sur la plupart des configurations matérielles, la plupart du temps, partout. C'est tout un exploit, si vous y réfléchissez.

Les limitations du modèle et d'autres facteurs signifieront parfois que l'optimiseur choisit un plan qui n'est pas, en fait, «assez bon» du tout. Vous signalez que "les performances sont bonnes", ce qui ne semble pas être le cas ici.

Aaron Bertrand
la source
9

Vous avez en fait 595 947 lignes correspondantes, ce qui représente environ 3% de vos données. Le coût de la recherche s'additionne donc rapidement. Supposons que vous ayez 100 lignes par page dans votre tableau, soit 200 000 pages à lire dans une analyse de tableau. C'est beaucoup moins cher que de faire 595 947 recherches.

Avec la GROUP BYclause dans la question, je pense que vous serez mieux avec une clé composite sur (Measure, SnapshotKey, MeasureBand).

Regardez la suggestion "index manquant". Il vous indique d'inclure des colonnes pour éviter les recherches. Plus généralement, si vous référencez d'autres colonnes dans votre requête, elles devront se trouver dans les clés ou la INCLUDEclause du nouvel index. Sinon, il devra toujours effectuer les recherches 595 947 pour obtenir ces valeurs.

Par exemple, pour la requête:

select Measure, SnapshotKey, MeasureBand, SUM(NumLoans), SUM(PrinBal)
from t1
where Measure = 'FinanceFICOScore'
group by Measure, SnapshotKey, MeasureBand

... il vous faudrait:

CREATE INDEX ixWhatever 
ON t1 (Measure, SnapshotKey, MeasureBand) 
INCLUDE (NumLoans,PrinBal);
Rob Farley
la source
6
  1. Le champ dans votre condition WHERE n'est pas le champ de tête de l'index.

  2. Vous avez measuredéfini comme préfixe NVARCHAR de sorte que le littéral avec N: where Measure = N'FinanceFICOScore'.

Envisagez de créer un index clusterisé sur SnapshotKey. S'il est unique, il peut s'agir d'un PK (et d'un cluster). S'il n'est pas unique, il ne peut pas s'agir d'un PK, mais peut tout de même être un index cluster non unique. Votre index non cluster serait alors uniquement sur la measurecolonne.

Et, étant donné que le premier champ de l' GROUP BYest également measure, cela gagnerait également à measureêtre le premier.

En fait, pour cette opération, vous devrez peut-être plutôt définir l'index NonClustered sur Measure, SnapshotKey, MeasureBand, dans cet ordre exact car il correspond à la GROUP BYclause. En ce qui concerne MeasureBandla taille, cela n'ajoute vraiment que puisque l'index NonClustered est déjà basé sur Measure, et MeasureKeyest déjà inclus dans l'index car il s'agit désormais de la clé Clustered Index (non, Measurene sera pas dupliqué dans l'index NonClustered).

@Rob avait mentionné dans un commentaire maintenant supprimé sur sa réponse que la résolution de ce problème nécessite uniquement que l'index non cluster soit défini avec ces trois champs dans cet ordre, et que la création d'un index cluster (non unique) sur SnapshotKeyn'est pas nécessaire . Bien qu'il ait probablement raison (j'espérais que moins de champs fonctionneraient), je soutiendrais toujours que le fait d'avoir l'index clusterisé est bénéfique non seulement pour cette opération, mais probablement pour la plupart des autres.

Solomon Rutzky
la source
La discussion sur cette réponse a été déplacée vers le chat .
Paul White 9