problema di prestazioni causato unendosi con il risultato di una funzione scalare?
-
16-10-2019 - |
Domanda
Nel seguente esempio le prestazioni della prima versione con una sola query SQL è molto cattivo. Il problema è l'ultimo join.
Quando ho memorizzare il risultato del lato sinistro in una tabella temporanea e aderire a questo, viene eseguito circa 50 volte più veloce.
Si intende convertire questo a Oracle, quindi cerco di evitare l'uso di tabelle temporanee.
Le eventuali spiegazioni, perché il primo si comporta così male di query o suggerimento per migliorarlo?
Declare @HO int = 2866;
Declare @Dtz int = 35;
---- version 1 takes about 60 seconds
With ratings as
(
select
ROW_NUMBER() Over ( ORDER BY SEDate) lfd,
SEDate,
BBCode
from PPV
join BB on BBRefnr = SEBBRefnr
where SEHORefnr = @HORefnr
and SEBBRefnr > 0
)
Select
SEDATE,
BBCODE,
Code,
DTRefnr
FROM (
Select
l.SEDate,
l.BBCode,
dbo.GetCode(@Dtz, l.BBCode) Code
from ratings l left join ratings r on l.lfd = r.lfd + 1
where l.BBCode <> r.BBCode
or r.BBCode is null
) as t
join DT d on code = d.DTCode and d.DTDTKRefnr = @Dtz
order by 1;
------- version 2 using a temp table takes less than 1 second
With ratings as
(
select
ROW_NUMBER() Over ( ORDER BY SEDate) lfd,
SEDate,
BBCode
from PPV
join BB on BBRefnr = SEBBRefnr
where SEHORefnr = @HORefnr
and SEBBRefnr > 0
)
Select
l.SEDate,
l.BBCode,
dbo.GetCode(@Dtz, l.BBCode) Code
into #tmp
from ratings l left join ratings r on l.lfd = r.lfd + 1
where l.BBCode <> r.BBCode
or r.BBCode is null
Select
SEDATE,
BBCODE,
Code,
DTRefnr
FROM #tmp
join DT d on code = d.DTCode and d.DTDTKRefnr = @Dtz
order by 1;
EDIT:
Qui la funzione:
Create function dbo.GetCode (
@fDtz int,
@Value varchar(10)
) returns varchar(10)
as
begin
declare @CODE varchar(10)
SET @Code =
(SELECT Code FROM Ableitungen
WHERE DTZ = @fDtz
AND Value = @Value )
return @CODE
end
Soluzione
Esattamente come previsto.
Uno scalare UDF è una scatola nera per l'ottimizzatore:. Nessun indici possono essere utilizzati, il costo non può essere risolto correttamente
E se l'UDF scalare ha accesso tavolo, allora si hanno in esecuzione un cursore (male in SQL Server) per fare una ricerca per riga : non è un'operazione basata set
Per risolvere il problema, non utilizzare una funzione definita dall'utente in questo modo. Può essere scritto come un join. Non v'è alcun indizio o la magia
Modifica: rimuovere l'UDF. Per ogni riga nelle valutazioni query Ableitungen. E 'esponenziale
E ho spostare i filtri in join
With ratings as
(
select
ROW_NUMBER() Over (ORDER BY SEDate) lfd,
SEDate,
BBCode
from PPV
join BB on BBRefnr = SEBBRefnr
where SEHORefnr = @HORefnr
and SEBBRefnr > 0
)
Select
l.SEDate,
l.BBCode,
A.Code,
D.DTRefnr
from
ratings l
left join
ratings r on l.lfd = r.lfd + 1
JOIN
Ableitungen A ON A.Value = l.BBCode
join
DT d on A.code = d.DTCode and d.DTDTKRefnr = A.DTZ
where
A.DTZ = @fDtz
AND
(l.BBCode <> r.BBCode or r.BBCode is null)
order by
SEDATE;