web-dev-qa-db-fra.com

sp_cursoropen et parallélisme

Je rencontre un problème de performance avec une requête que je ne peux pas sembler avoir la tête.

J'ai tiré la requête d'une définition de curseur.

Cette requête prend des secondes pour 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.

enter image description here

Le remarquant Le paramètre Wide du serveur a été réglé sur MaxDop 1 J'ai essayé de jouer avec les paramètres MaxDop.

Ajout OPTION (MAXDOP 0) à la requête ou modifier les paramètres du serveur entraîne une bien meilleure performance et ce plan de requête.

enter image description here

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

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

entraînant ce plan d'exécution (et malheureusement les mêmes temps d'exécution de plusieurs secondes secondes).

enter image description here

J'ai essayé plusieurs choses telles que la chute des plans mis en cache, ajout d'options dans la requête dans la définition du curseur, ... mais aucun d'entre eux ne semble me procurer un plan parallèle.

J'ai également cherché Google pour un peu moins cher à la recherche de limitations de parallélisme des curseurs mais ne peut sembler trouver de limitations.

Est-ce que je manque quelque chose d'évident ici?

La construction SQL réelle est SQL Server 2008 (SP1) - 10.0.2573.0 (X64) que je réalise n'est pas supportée, mais je ne peux pas mettre à niveau cette instance comme je le vois. Je devrais transférer la base de données sur un autre serveur et cela signifierait tirer une sauvegarde assez grande non compressée sur une lente WAN.

Le drapeau de trace 4199 ne fait pas de différence et l'option (recompilation).

Les propriétés du curseur sont:

API | Fast_Forward | Read Only | Global (0)

FAST_FORWARD curseurs Ne pas prendre en charge le parallélisme (bien que le serveur générant le plan aurait besoin d'être 2012 ou plus pour obtenir NonParallelPlanReason dans le cadre du XML de Showplan).

Lorsque vous spécifiez FAST_FORWARD, l'optimiseur choisit entre STATIC et DYNAMIC pour vous.

Le plan d'exécution fourni montre l'optimiseur qui choisit un plan de type statique. Parce que la requête contient une agrégation, je doute qu'un plan de curseur dynamique soit encore possible ici. Néanmoins, demandant un FAST_FORWARD Le type de curseur empêche un plan parallèle.

Vous devez modifier explicitement le type de curseur sur STATIC ou KEYSET, par exemple. Ces deux types de curseurs peuvent utiliser le parallélisme.

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

20
Paul White 9