J'ai une requête SQL Server 2008 quelque peu complexe (environ 200 lignes de SQL assez dense) qui ne fonctionnait pas comme j'en avais besoin. Au fil du temps, les performances sont passées d'environ 0,5 seconde à environ 2 secondes.
En examinant le plan d'exécution, il était assez évident qu'en réorganisant les jointures, les performances pouvaient être améliorées. Je l'ai fait, et ça l'a fait ... jusqu'à environ 0,3 seconde. Maintenant, la requête a l'indication "OPTION FORCE ORDER" et la vie est bonne.
Je viens aujourd'hui pour nettoyer la base de données. J'archive environ 20% des lignes, sans aucune action dans la base de données concernée, sauf la suppression des lignes ... le plan d'exécution est TOTALEMENT arrosé . Il évalue complètement le nombre de lignes que certains sous-arbres retourneront, et (par exemple) remplace a:
<Hash>
avec
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
Maintenant, le temps de requête passe d'environ 0,3 s à environ 18 s. (!) Tout simplement parce que j'ai supprimé des lignes. Si je supprime l'indice de requête, je reviens à environ 2 secondes de temps de requête. Mieux, mais pire.
J'ai reproduit le problème après avoir restauré la base de données sur plusieurs emplacements et serveurs. La simple suppression d'environ 20% des lignes de chaque table entraîne toujours ce problème.
- Est-ce normal qu'un ordre de jointure forcée rende les estimations de requête complètement inexactes (et donc les temps de requête imprévisibles)?
- Dois-je simplement m'attendre à devoir accepter des performances de requête sous-optimales ou à les regarder comme un faucon et à modifier fréquemment les conseils de requête manuellement? Ou peut-être aussi faire allusion à chaque jointure? .3s à 2s est un gros coup à prendre.
- Est-il évident pourquoi l'optimiseur a explosé après la suppression de lignes? Par exemple, "oui, il a fallu une analyse d'échantillon, et parce que j'ai archivé la plupart des lignes plus tôt dans l'historique des données, l'échantillon a donné des résultats clairsemés, donc il a sous-estimé la nécessité d'une opération de hachage triée"?
Si vous souhaitez voir les plans d'exécution, veuillez suggérer un emplacement où je peux les publier. Sinon, j'ai échantillonné le morceau le plus étonnant. Voici l'erreur fondamentale d'estimation, les nombres en parenthèses sont des lignes (estimées: réelles).
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
Notez que la boucle intérieure devrait balayer 908 lignes, mais balaye à la place 52 258 441. Si elle avait été exacte, cette branche aurait fonctionné environ 2 ms, au lieu de 12 secondes. Avant de supprimer les lignes, cette estimation de jointure interne n'était désactivée que par un facteur total de 2 et a été effectuée en tant que correspondance de hachage sur deux index clusterisés.