différence de performance incompréhensible entre 2 méthodes
bonjour
j'ai un requete assez complexe, qui prend pas mal de temps, et pourtant si je le fais en 2 fois via une table temporaire, c'est instantané
dans les 2 cas j'ai le meme with au dessus :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
WITH
ListePlanning(Numero, IdPlanning, IdArticle)
AS (SELECT ROW_NUMBER() OVER (ORDER BY Planning.IdPlanning, Planning.OrderToUse DESC), Planning.idPlanning, Planning.IdArticle FROM Planning)
,
ListeArticlesUtilisesPourPlanning (IdPlanning, IdArticle) -- pour chaque planning, l'article du planning et les articles en provenance
AS (SELECT Planning.IdPlanning, Planning.IdArticle FROM Planning
UNION SELECT Planning.IdPlanning, PlanningProv.IdArticle FROM Planning INNER JOIN PlanningProv ON Planning.IdPlanning = PlanningProv.IdPlanning)
,
ListeIncompatibilites (IdArticle, IdArticleInterdit, NbBatch, IdIncompatibilite) -- ne contient que des isarticles (soit direct soit pris dans les regroupements définis)
-- article à fabriquer, article précédent interdit, nombre entre chaque requis
AS (SELECT case when vueFab.IdArticle IS NULL then IncompatibiliteDefinition.IdArticle else vueFab.IdArticle end as c1,
case when vueInterdit.IdArticle IS NULL then IncompatibiliteInterdite.IdArticle else vueInterdit.IdArticle end as c2,
IncompatibiliteInterdite.NbBatch, IncompatibiliteDefinition.IdIncompatibilite
FROM IncompatibiliteDefinition
LEFT JOIN ArticleGetArticleEtRegroupements vueFab ON vueFab.IdRegroupement = IncompatibiliteDefinition.IdArticle
INNER JOIN IncompatibiliteInterdite ON IncompatibiliteDefinition.IdIncompatibilite = IncompatibiliteInterdite.IdIncompatibilite
LEFT JOIN ArticleGetArticleEtRegroupements vueInterdit ON vueInterdit.IdRegroupement = IncompatibiliteInterdite.IdArticle
) |
1ère méthode : je tente de faire un select direct de ce que je veux
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
-- WITH mis au dessus
SELECT PlanningCourant.IdPlanning , ListeIncompatibilites.IdIncompatibilite, ListeIncompatibilites.IdArticle, ListeIncompatibilites.IdArticleInterdit
, ArticleFab.Code, ArticlePasse.Code
FROM Planning PlanningCourant
INNER JOIN ListePlanning ON PlanningCourant.IdPlanning = ListePlanning.IdPlanning
INNER JOIN ListePlanning TrouvePrecedent ON TrouvePrecedent.Numero = ListePlanning.Numero - 1
INNER JOIN Planning PlanningPrecedent ON PlanningPrecedent.IdPlanning = TrouvePrecedent.IdPlanning -- récupération pour chaque idplanning, l'idplanning précédent
INNER JOIN ListeArticlesUtilisesPourPlanning lc ON lc.IdPlanning = PlanningCourant.IdPlanning
INNER JOIN ListeArticlesUtilisesPourPlanning lp ON lp.IdPlanning = PlanningPrecedent.IdPlanning
INNER JOIN ListeIncompatibilites ON lc.IdArticle = ListeIncompatibilites.IdArticle
AND lp.IdArticle = ListeIncompatibilites.IdArticleInterdit
INNER JOIN Article ArticleFab ON ArticleFab.IdArticle = ListeIncompatibilites.IdArticle
INNER JOIN Article ArticlePasse ON ArticlePasse.IdArticle = ListeIncompatibilites.IdArticleInterdit |
2 ème méthode : je retire 2 jointures sur la table Article et je passe par une table @
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
DECLARE @IncompatibiliteTable table
(IdPlanning bigint, IdIncompatibilite bigint, IdArticle bigint, IdArticleInterdit bigint)
-- WITH mis au dessus
INSERT INTO @IncompatibiliteTable
SELECT PlanningCourant.IdPlanning , ListeIncompatibilites.IdIncompatibilite, ListeIncompatibilites.IdArticle, ListeIncompatibilites.IdArticleInterdit
FROM Planning PlanningCourant
INNER JOIN ListePlanning ON PlanningCourant.IdPlanning = ListePlanning.IdPlanning
INNER JOIN ListePlanning TrouvePrecedent ON TrouvePrecedent.Numero = ListePlanning.Numero - 1
INNER JOIN Planning PlanningPrecedent ON PlanningPrecedent.IdPlanning = TrouvePrecedent.IdPlanning -- récupération pour chaque idplanning, l'idplanning précédent
INNER JOIN ListeArticlesUtilisesPourPlanning lc ON lc.IdPlanning = PlanningCourant.IdPlanning
INNER JOIN ListeArticlesUtilisesPourPlanning lp ON lp.IdPlanning = PlanningPrecedent.IdPlanning
INNER JOIN ListeIncompatibilites ON lc.IdArticle = ListeIncompatibilites.IdArticle
AND lp.IdArticle = ListeIncompatibilites.IdArticleInterdit
select tmp.*, ArticleFab.Code, ArticlePasse.Code
FROM @IncompatibiliteTable tmp
INNER JOIN Article ArticleFab ON ArticleFab.IdArticle = tmp.IdArticle
INNER JOIN Article ArticlePasse ON ArticlePasse.IdArticle = tmp.IdArticleInterdit |
on répète souvent que les tables temporaires ralentissent les traitements, que des lectures sont plus performantes donc j'ai essayé de décomposer mon traitement en plusieurs sous requetes
dans le 1er cas, je retrouve 2 IdArticle, et je fais une jointure sur la table article pour retrouver le code de l'article
ca prend des 10aines de secondes
dans le 2eme cas, je stocke le résultat et donc les 2 IdArticle dans une table temporaire, puis je fais un select de cette table temporaire avec la table article pour avoir le Code
c'est instantané
ma table article comporte 300 ligne
si quelqu'un peut m'expliquer pourquoi sql server s'emmele les pinceaux avec ma requete ...