Différence entre Seek Predicate et Predicate

12

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 prédicat de recherche et également un prédicat

Quelle est la différence entre Seek Predicate et Predicate ?

entrez la description de l'image ici

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.

Greg
la source
3
Le prédicat de recherche assiste la jointure, en filtrant uniquement les lignes qui se trouvent également dans l'autre table (que vous avez caviardée). Le prédicat (un prédicat résiduel) élimine alors les lignes avec le statut spécifique de 2.
Aaron Bertrand
5
Rob Farley a déclaré ce qui suit dans un commentaire ici :The Seek Predicate can be used to find the start of the RangeScan and then when to stop, while the Predicate is the "check" that is applied to every row in the Range.
Aaron Bertrand

Réponses:

18

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 clusterisé (par défaut) sur la PKcolonne. Il y a un index non cluster sur COL1lequel a une colonne clé de COL1et 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 BETWEENparce que Aaron Bertrand traîne autour de cette question.

Comment l'optimiseur SQL Server devrait-il interroger cette requête? Eh bien, je sais que le filtre PKréduit le jeu de résultats à 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. Toutefois, 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 COL2. Ici, PKest un prédicat de recherche et COL2est un prédicat.

entrez la description de l'image ici

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:

entrez la description de l'image ici

Dans ce cas, SQL Server peut rechercher à l'aide des deux colonnes dans la WHEREclause. Une seule 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, seule COL1est une colonne clé. SQL Server peut rechercher avec cette colonne pour trouver les 1000 lignes avec une COL1valeur correspondante . Il peut filtrer davantage ces lignes sur la COL2colonne pour réduire le jeu de résultats final à 0 lignes.

entrez la description de l'image ici

Joe Obbish
la source