L'index SEEK n'est pas utilisé sauf si OPTION (RECOMPILE)?


11

(Question déplacée de SO)

J'ai une table (données fictives) avec un index cluster contenant 2 colonnes:

entrez la description de l'image ici

Maintenant, je lance ces deux requêtes:

declare 
@productid int =1 , 
@priceid  int = 1




SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid OR @productid IS NULL)
       AND (priceid = @priceid OR @priceid IS NULL)  


SELECT productid,
       t.priceID
FROM   Transactions AS t
WHERE  (productID = @productid)
       AND (priceid = @priceid)

Le plan d'exécution réel pour les deux requêtes est le suivant:

entrez la description de l'image ici

Comme vous pouvez le voir, le premier utilise SCAN tandis que le second utilise SEEK.

Cependant - en ajoutant OPTION (RECOMPILE)à la première requête, le plan d'exécution a également utilisé SEEK:

entrez la description de l'image ici

Des amis du chat DBA m'ont dit que:

Dans votre requête, @ productid = 1, ce qui signifie que (productID = @ productID OU @productID IS NULL) peut être simplifié en (productID = @ productID). Le premier nécessite une analyse pour fonctionner avec n'importe quelle valeur de @productID, le second pourrait utiliser une recherche. Ainsi, lorsque vous utilisez RECOMPILE, SQL Server examinera la valeur que vous avez réellement dans @productID et fera le meilleur plan pour cela. Avec une valeur non nulle dans @productID, une recherche est la meilleure. Si la valeur de @productID est inconnue, le plan doit correspondre à toute valeur possible dans @productID, ce qui nécessiterait une analyse. Soyez averti: OPTION (RECOMPILE) forcera une recompilation du plan chaque fois que vous l'exécuterez, ce qui ajoutera quelques millisecondes à chaque exécution. Bien que ce ne soit un problème que si la requête s'exécute très fréquemment.

Aussi :

Si @productID est null, à quelle valeur rechercheriez-vous? Réponse: il n'y a rien à chercher. Toutes les valeurs sont éligibles.

Je comprends que OPTION (RECOMPILE)SQL Server force à voir quelles sont les valeurs réelles des paramètres et à voir s'il peut RECHERCHER avec.

Mais maintenant, je perds l'avantage de la compilation anticipée.

Question

IMHO - SCAN ne se produira que si un paramètre est nul.
C'est bien - laissez SQL SERVER créer un plan d'exécution pour SCAN.
MAIS si SQL Server voit que j'exécute cette requête plusieurs fois avec des valeurs:, 1,1alors pourquoi ne crée-t-il PAS UN AUTRE plan d'exécution et utilise SEEK pour cela?

AFAIK - SQL crée un plan d'exécution pour les requêtes les plus consultées .

  • Pourquoi SQL SERVER n'enregistre-t-il pas un plan d'exécution pour:

    @productid int =1 , @priceid int = 1

(Je l'exécute plusieurs fois avec ces valeurs)

  • Est-il possible de forcer SQL à conserver ce plan d'exécution (qui utilise SEEK) - pour une invocation future?

Créer un script de table + données


Réponses:


10

Résumant certains des principaux points de notre discussion sur le salon de discussion :


De manière générale, SQL Server met en cache un plan unique pour chaque instruction . Ce plan doit être valide pour toutes les futures valeurs de paramètres possibles .

Il n'est pas possible de mettre en cache un plan de recherche pour votre requête, car ce plan ne serait pas valide si, par exemple, @productid est null.

Dans certaines versions futures, SQL Server pourrait prendre en charge un plan unique qui choisit dynamiquement entre une analyse et une recherche, en fonction des valeurs des paramètres d'exécution, mais ce n'est pas quelque chose que nous avons aujourd'hui.

Classe de problème générale

Votre requête est un exemple de modèle appelé différemment "requête globale" ou "recherche dynamique". Il existe différentes solutions, chacune avec ses avantages et ses inconvénients. Dans les versions modernes de SQL Server (2008+), les principales options sont:

  • IF blocs
  • OPTION (RECOMPILE)
  • SQL dynamique utilisant sp_executesql

Le travail le plus complet sur le sujet est probablement celui d'Erland Sommarskog, qui est inclus dans les références à la fin de cette réponse. Il n'y a pas moyen de s'éloigner des complexités impliquées, il est donc nécessaire d'investir un certain temps dans l'essai de chaque option pour comprendre les compromis dans chaque cas.

IF blocs

Pour illustrer une IFsolution de bloc pour le cas spécifique de la question:

IF @productid IS NOT NULL AND @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid
        AND T.priceID = @priceid;
END;
ELSE IF @productid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.productID = @productid;
END;
ELSE IF @priceid IS NOT NULL
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T
    WHERE
        T.priceID = @priceid;
END;
ELSE
BEGIN
    SELECT 
        T.productID,
        T.priceID
    FROM dbo.Transactions AS T;
END;

Celui-ci contient une instruction distincte pour les quatre cas possibles nul ou non nul pour chacun des deux paramètres (ou variables locales), il y a donc quatre plans.

Il y a un problème potentiel avec le reniflage de paramètres, qui pourrait nécessiter un OPTIMIZE FORindice sur chaque requête. Veuillez consulter la section des références pour explorer ces types de subtilités.

Recompiler

Comme indiqué ci-dessus et dans la question, vous pouvez également ajouter un OPTION (RECOMPILE)indice pour obtenir un nouveau plan (rechercher ou analyser) à chaque appel. Étant donné la fréquence relativement lente des appels dans votre cas (une fois toutes les dix secondes en moyenne, avec un temps de compilation inférieur à la milliseconde), il semble probable que cette option vous conviendra:

SELECT
    T.productID,
    T.priceID
FROM dbo.Transactions AS T
WHERE
    (T.productID = @productid OR @productid IS NULL)
    AND (T.priceID = @priceid OR @priceid IS NULL)
OPTION (RECOMPILE);

Il est également possible de combiner les fonctionnalités des options ci-dessus de manière créative, pour tirer le meilleur parti des avantages de chaque méthode, tout en minimisant les inconvénients. Il n'y a vraiment aucun raccourci pour comprendre ces choses en détail, puis faire un choix éclairé soutenu par des tests réalistes.

Lectures complémentaires

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.