sp_cursoropen e parallelismo


15

Sto riscontrando un problema di prestazioni con una query che non riesco a capire.

Ho estratto la query da una definizione del cursore.

Questa query richiede pochi secondi per essere eseguita

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

Il piano di esecuzione effettivo è simile al seguente.

inserisci qui la descrizione dell'immagine

Notando che l'impostazione a livello di server è stata impostata su MaxDOP 1, ho provato a giocare con le impostazioni di maxdop.

Aggiungendo OPTION (MAXDOP 0)alla query o modificando le impostazioni del server si ottengono prestazioni molto migliori e questo piano di query.

inserisci qui la descrizione dell'immagine

Tuttavia, l'applicazione in questione (Dynamics AX) non esegue query come questa, utilizza i cursori.

Il vero codice acquisito è questo.

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

risultante in questo piano di esecuzione (e purtroppo gli stessi tempi di esecuzione di più secondi).

inserisci qui la descrizione dell'immagine

Ho provato diverse cose come eliminare i piani memorizzati nella cache, aggiungere opzioni nella query all'interno della definizione del cursore, ... Ma nessuno di loro sembra farmi un piano parallelo.

Ho anche cercato su Google un po 'alla ricerca di limiti di parallelismo dei cursori, ma non riesco a trovare alcun limite.

Mi sto perdendo qualcosa di ovvio qui?

L'effettivo build SQL è SQL Server 2008 (SP1) - 10.0.2573.0 (X64)che mi rendo conto che non è supportato, ma non posso aggiornare questa istanza a mio avviso. Avrei bisogno di trasferire il database su un altro server e ciò significherebbe eseguire il pull di un backup non compresso abbastanza grande su una WAN lenta.

Il flag di traccia 4199 non fa differenza, e nemmeno OPTION (RECOMPILE).

Le proprietà del cursore sono:

API | Fast_Forward | Read Only | Global (0)

Risposte:


20

FAST_FORWARDi cursori non supportano il parallelismo (anche se il server che genera il piano dovrebbe essere 2012 o superiore per ottenere NonParallelPlanReasoncome parte dello showplan XML).

Quando specifichi FAST_FORWARD, l'ottimizzatore sceglie tra STATICe DYNAMICper te.

Il piano di esecuzione fornito mostra l'ottimizzatore che sceglie un piano di tipo statico. Poiché la query contiene aggregazione, dubito che un piano di cursore dinamico sia persino possibile qui. Tuttavia, la richiesta di un FAST_FORWARDtipo di cursore impedisce un piano parallelo.

È necessario modificare esplicitamente il tipo di cursore in uno STATICo KEYSET, ad esempio. Entrambi questi tipi di cursore possono usare il parallelismo.

Detto questo, poiché si tratta di un cursore API, la modifica del tipo di cursore richiederebbe probabilmente una modifica dell'applicazione. Ovviamente, dovrai verificare le prestazioni per verificare che cambiare il tipo di cursore sia davvero l'opzione migliore per te.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.