J'ai un étrange problème de compilation de requêtes qui est difficile à reproduire. Cela ne se produit que sous une charge élevée et ne peut pas être facilement répété.
- Il y a un tableau T avec les colonnes A, B, C, D.
- Il existe un index cluster non unique sur T (A, B, C, D).
- Il y a une requête SELECT * FROM T WHERE A = @ P1 AND B = @ P2 AND (C = @ P3 OR C = @ P4) AND D = @ P5. La condition de recherche est sur toutes les colonnes de l'index clusterisé, la 3ème colonne a un OU.
Le problème est que le plan de requête pour cette requête a un prédicat de recherche uniquement sur A et B! Le prédicat sur C et D est un prédicat ordinaire, ce qui signifie que l'arborescence de recherche sur les colonnes C et D n'est pas utilisée.
Les types de données pour tous les paramètres correspondent aux types de données de colonne.
Quelqu'un pourrait-il fournir des indices sur la raison pour laquelle cela pourrait se produire? La version SQL est 2008 R2 (SP1) - 10.50.2789.0 (X64)
OPTION (RECOMPILE)
?Réponses:
Pour une requête paramétrée Il ne peut pas simplement faire deux recherches sur
et
Parce
@P3 = @P4
que si cela ramènerait incorrectement des lignes en double. Il faudrait donc un opérateur qui supprime les doublons de ceux-ci en premier.D'après un test rapide à cette fin, il semble dépendre de la taille de la table, que vous l'obteniez ou non. Dans le test ci
245
- dessous /246
rangées se trouve le point de coupure entre les plans (c'était aussi le point de coupure entre l'index s'adaptant le tout sur une seule page et devenant 2 pages feuilles et une page racine).1 pages / 245 lignes
Ce plan a une recherche sur
A=1 AND B=2
avec un prédicat résiduel sur(C=@C1 OR C=@C2) AND D=5
Pages 2 feuilles / 246 lignes
Dans le second plan, les opérateurs supplémentaires sont responsables de la suppression des doublons
@C1,@C2
avant d'effectuer les recherches.La recherche dans le deuxième plan est en fait une recherche de plage entre
A=1 AND B=2 AND C > Expr1010
etA=1 AND B=2 AND C < Expr1011
avec un prédicat résiduel activéD=5
. Ce n'est toujours pas une recherche d'égalité sur les 4 colonnes. Pour plus d'informations sur les opérateurs de plans supplémentaires, cliquez ici .L'ajout
OPTION (RECOMPILE)
lui permet d'inspecter les valeurs des paramètres pour les doublons au moment de la compilation et produit un plan avec deux recherches d'égalité.Vous pouvez également y parvenir avec
Mais en réalité, dans ce cas de test, il serait probablement contre-productif, car avoir deux recherches dans l'index d'une seule page plutôt qu'une seule augmente le nombre d'entrées / sorties logiques.
la source
select .. union select ...
cela vous donnerait également deux recherches plus l'étape supplémentaire de suppression des doublons du résultat.SELECT * FROM T WHERE A=1 AND B=2 AND C=@C1 AND D=5 UNION SELECT * FROM T WHERE A=1 AND B=2 AND C=@C2 AND D=5
pourrait supprimer de manière incorrecte les doublons qui devraient être retournés. Dans mes données d'exemple où j'ai rempli paresseusement tous avec la même valeur, cela retournerait 1 ligne non256
Tout à fait d'accord avec l'analyse de Martin. Cette requête ne peut pas produire de recherche sur les 4 colonnes en raison du prédicat OR, sauf (peut-être) avec OPTION (RECOMPILE). Je suppose que c'est une requête d'aiguille dans une botte de foin, vous ne voulez probablement pas les frais généraux supplémentaires.
Que dis-tu de ça:
Je n'ai pas testé cela, mais l'autre partie devrait donner 2 recherches sur les 4 valeurs et une union bon marché par concaténation. Dans le cas où les deux recherches se retrouveraient sur la même page, je ne pense pas qu'une lecture logique supplémentaire ajouterait beaucoup de temps. Cependant, selon vos données, les deux recherches peuvent très bien se trouver sur des pages différentes.
la source