J'essaie d'optimiser les performances d'une requête que nous avons dans SQL Server 2014 Enterprise.
J'ai ouvert le plan de requête réel dans SQL Sentry Plan Explorer et je peux voir sur un nœud qu'il a un Seek Predicate et aussi un Prédicat
Quelle est la différence entre Prédicat de recherche et Prédicat ?
Remarque: je peux voir qu'il y a beaucoup de problèmes avec ce nœud (par exemple, les lignes estimées vs réelles, les E/S résiduelles), mais la question ne se rapporte à rien de tout cela.
Jetons un million de lignes dans une table temporaire avec quelques colonnes:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (PK)
);
INSERT INTO #174860 WITH (TABLOCK)
SELECT RN
, RN % 1000
, RN % 10000
FROM
(
SELECT TOP 1000000 ROW_NUMBER () OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values v1,
master..spt_values v2
) t;
CREATE INDEX IX_174860_IX ON #174860 (COL1) INCLUDE (COL2);
Ici, j'ai un index cluster (par défaut) sur la colonne PK
. Il y a un index non cluster sur COL1
qui a une colonne clé de COL1
et comprend COL2
.
Considérez la requête suivante:
SELECT *
FROM #174860
WHERE PK >= 15000 AND PK < 15005
AND COL2 = 5000;
Ici, je n'utilise pas BETWEEN
car Aaron Bertrand est en train de contourner cette question.
Comment l'optimiseur SQL Server devrait-il interroger cette requête? Eh bien, je sais que le filtre sur PK
réduira le résultat à cinq lignes. Le serveur SQL peut utiliser l'index clusterisé pour accéder à ces cinq lignes au lieu de parcourir les millions de lignes de la table. Cependant, l'index cluster n'a que la colonne PK comme colonne clé. Une fois la ligne lue en mémoire, nous devons appliquer le filtre sur COL2
. Ici, PK
est un prédicat de recherche et COL2
est un prédicat.
Le serveur SQL trouve cinq lignes à l'aide du prédicat de recherche et réduit encore ces cinq lignes à une ligne avec le prédicat normal.
Si je définis l'index clusterisé différemment:
CREATE TABLE #174860 (
PK INT NOT NULL,
COL1 INT NOT NULL,
COL2 INT NOT NULL,
PRIMARY KEY (COL2, PK)
);
Et exécutez la même requête, j'obtiens des résultats différents:
Dans ce cas, SQL Server peut rechercher à l'aide des deux colonnes dans la clause WHERE
. Exactement une ligne est lue dans le tableau à l'aide des colonnes clés.
Pour un autre exemple, considérez cette requête:
SELECT *
FROM #174860
WHERE COL1 = 500
AND COL2 = 3545;
L'index IX_174860_IX est un index de couverture car il contient toutes les colonnes nécessaires à la requête. Cependant, seulement COL1
est une colonne clé. SQL Server peut rechercher avec cette colonne pour trouver les 1000 lignes avec un COL1
valeur. Il peut filtrer davantage ces lignes sur le COL2
colonne pour réduire le jeu de résultats final à 0 lignes.