J'ai eu ce problème il y a longtemps, j'ai trouvé une solution de contournement qui me convenait et je l'ai oubliée.
Mais maintenant, il y a cette question sur SO donc je suis prêt à soulever ce problème.
Il y a une vue qui joint quelques tables de manière très simple (commandes + lignes de commande).
Lorsqu'elle est interrogée sans where
clause, la vue renvoie plusieurs millions de lignes.
Cependant, personne ne l'appelle jamais comme ça. La requête habituelle est
select * from that_nasty_view where order_number = 123456;
Cela renvoie environ 10 enregistrements sur 5m.
Une chose importante: la vue contient une fonction de fenêtre rank()
, qui est partitionnée exactement par le champ à l'aide duquel la vue est toujours interrogée:
rank() over (partition by order_number order by detail_line_number)
Maintenant, si cette vue est interrogée avec des paramètres littéraux dans la chaîne de requête, exactement comme indiqué ci-dessus, elle retourne les lignes instantanément. Le plan d'exécution est très bien:
- Recherche d'index sur les deux tables en utilisant les indices sur
order_number
(retourne 10 lignes). - Calcul des fenêtres sur le minuscule résultat renvoyé.
- Sélection.
Cependant, lorsque la vue est appelée de manière paramétrée, les choses deviennent désagréables:
Index scan
sur toutes les tables en ignorant les indices. Renvoie 5 m de lignes.- Énorme jointure.
- Calcul des fenêtres sur tous les
partition
s (environ 500k fenêtres). Filter
prendre 10 rangs sur 5m.- Sélectionner
Cela se produit dans tous les cas lorsque des paramètres sont impliqués. Il peut s'agir de SSMS:
declare @order_number int = 123456;
select * from that_nasty_view where order_number = @order_number;
Il peut s'agir d'un client ODBC, tel qu'Excel:
select * from that_nasty_view where order_number = ?
Ou il peut s'agir de tout autre client qui utilise des paramètres et non la concaténation sql.
Si la fonction de fenêtre est supprimée de la vue, elle s'exécute parfaitement rapidement, qu'elle soit ou non interrogée avec des paramètres.
Ma solution de contournement consistait à supprimer la fonction incriminée et à la réappliquer ultérieurement.
Mais qu'est-ce qui donne? Est-ce vraiment un bug dans la façon dont SQL Server 2008 gère les fonctions des fenêtres?
order_number
n'est pas une clé primaire. C'est int not null
avec un index non clusterisé dans les deux tables.
OPTION (RECOMPILE)
aide?