Je rencontre un problème de performances avec une requête que je n'arrive pas à comprendre.
J'ai retiré la requête d'une définition de curseur.
Cette requête prend quelques secondes pour s'exécuter
SELECT A.JOBTYPE
FROM PRODROUTEJOB A
WHERE ((A.DATAAREAID=N'IW')
AND ((A.CALCTIMEHOURS<>0)
AND (A.JOBTYPE<>3)))
AND EXISTS (SELECT 'X'
FROM PRODROUTE B
WHERE ((B.DATAAREAID=N'IW')
AND (((((B.PRODID=A.PRODID)
AND ((B.PROPERTYID=N'PR1526157') OR (B.PRODID=N'PR1526157')))
AND (B.OPRNUM=A.OPRNUM))
AND (B.OPRPRIORITY=A.OPRPRIORITY))
AND (B.OPRID=N'GRIJZEN')))
AND NOT EXISTS (SELECT 'X'
FROM ADUSHOPFLOORROUTE C
WHERE ((C.DATAAREAID=N'IW')
AND ((((((C.WRKCTRID=A.WRKCTRID)
AND (C.PRODID=B.PRODID))
AND (C.OPRID=B.OPRID))
AND (C.JOBTYPE=A.JOBTYPE))
AND (C.FROMDATE>{TS '1900-01-01 00:00:00.000'}))
AND ((C.TODATE={TS '1900-01-01 00:00:00.000'}))))))
GROUP BY A.JOBTYPE
ORDER BY A.JOBTYPE
Le plan d'exécution réel ressemble à ceci.
Remarquant que le paramètre du serveur était réglé sur MaxDOP 1 J'ai essayé de jouer avec les paramètres maxdop.
L'ajout OPTION (MAXDOP 0)
à la requête ou la modification des paramètres du serveur entraîne de bien meilleures performances et ce plan de requête.
Cependant, l'application en question (Dynamics AX) n'exécute pas de requêtes comme celle-ci, elle utilise des curseurs.
Le code réel capturé est le suivant.
declare @p1 int
set @p1=189527589
declare @p3 int
set @p3=16
declare @p4 int
set @p4=1
declare @p5 int
set @p5=2
exec sp_cursoropen @p1 output,N'SELECT A.JOBTYPE FROM PRODROUTEJOB A WHERE ((A.DATAAREAID=N''IW'') AND ((A.CALCTIMEHOURS<>0) AND (A.JOBTYPE<>3))) AND EXISTS (SELECT ''X'' FROM PRODROUTE B WHERE ((B.DATAAREAID=N''IW'') AND (((((B.PRODID=A.PRODID) AND ((B.PROPERTYID=N''PR1526157'') OR (B.PRODID=N''PR1526157''))) AND (B.OPRNUM=A.OPRNUM)) AND (B.OPRPRIORITY=A.OPRPRIORITY)) AND (B.OPRID=N''GRIJZEN''))) AND NOT EXISTS (SELECT ''X'' FROM ADUSHOPFLOORROUTE C WHERE ((C.DATAAREAID=N''IW'') AND ((((((C.WRKCTRID=A.WRKCTRID) AND (C.PRODID=B.PRODID)) AND (C.OPRID=B.OPRID)) AND (C.JOBTYPE=A.JOBTYPE)) AND (C.FROMDATE>{TS ''1900-01-01 00:00:00.000''})) AND ((C.TODATE={TS ''1900-01-01 00:00:00.000''})))))) GROUP BY A.JOBTYPE ORDER BY A.JOBTYPE ',@p3 output,@p4 output,@p5 output
select @p1, @p3, @p4, @p5
résultant en ce plan d'exécution (et malheureusement les mêmes temps d'exécution de plusieurs secondes).
J'ai essayé plusieurs choses telles que supprimer des plans mis en cache, ajouter des options dans la requête à l'intérieur de la définition du curseur, ... Mais aucun d'entre eux ne semble me procurer un plan parallèle.
J'ai également recherché sur google un peu à la recherche de limitations de parallélisme des curseurs, mais je n'arrive pas à trouver de limitations.
Suis-je en train de manquer quelque chose d'évident ici?
La version SQL réelle est celle SQL Server 2008 (SP1) - 10.0.2573.0 (X64)
que je réalise non prise en charge, mais je ne peux pas mettre à niveau cette instance comme bon me semble. J'aurais besoin de transférer la base de données vers un autre serveur et cela signifierait tirer une sauvegarde non compressée assez grande sur un WAN lent.
L'indicateur de trace 4199 ne fait aucune différence, et OPTION (RECOMPILE) non plus.
Les propriétés du curseur sont:
API | Fast_Forward | Read Only | Global (0)