sp_cursoropen et parallélisme


15

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.

entrez la description de l'image ici

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.

entrez la description de l'image ici

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).

entrez la description de l'image ici

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)

Réponses:


20

FAST_FORWARDles curseurs ne prennent pas en charge le parallélisme (bien que le serveur générant le plan NonParallelPlanReasondoive être 2012 ou supérieur pour être intégré au showplan XML).

Lorsque vous spécifiez FAST_FORWARD, l'optimiseur choisit entre STATICet DYNAMICpour vous.

Le plan d'exécution fourni montre à l'optimiseur le choix d'un plan de type statique. Parce que la requête contient une agrégation, je doute qu'un plan de curseur dynamique soit même possible ici. Néanmoins, la demande d'un FAST_FORWARDtype de curseur empêche un plan parallèle.

Vous devez changer le type de curseur explicitement en STATICou KEYSET, par exemple. Ces deux types de curseur peuvent utiliser le parallélisme.

Cela dit, car il s'agit d'un curseur API, la modification du type de curseur nécessiterait probablement un changement d'application. Naturellement, vous devrez comparer les performances pour vérifier que la modification du type de curseur est vraiment la meilleure option pour vous.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.