Leistungsproblem, verursacht durch den Zusammenhang mit dem Ergebnis einer Skalarfunktion?
-
16-10-2019 - |
Frage
Im folgenden Beispiel ist die Leistung der ersten Version mit nur einer SQL -Abfrage sehr schlecht. Das Problem ist der letzte Join.
Wenn ich das Ergebnis der linken Seite in einen temporären Tisch speichere und sich diesem anschließt, läuft es etwa 50 -mal schneller.
Es ist beabsichtigt, dies in Oracle umzuwandeln. Daher versuche ich, die Verwendung von temporären Tabellen zu vermeiden.
Irgendwelche Erklärungen, warum sich die erste Abfrage so schlecht verhält oder Hinweis, um sie zu verbessern?
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;
BEARBEITEN:
Hier die Funktion:
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
Lösung
Genau wie erwartet.
Ein Skalar -UDF ist eine schwarze Box für den Optimierer: Es können keine Indizes verwendet werden, die Kosten können nicht richtig ausgearbeitet werden.
Und wenn der Skalar -UDF über einen Tabellenzugriff verfügt, haben Sie einen Cursor (schlecht in SQL Server), um eine Suche durchzuführen pro Zeile: Es ist kein fester Set -basiertes Vorgang
Um es zu beheben, verwenden Sie auf diese Weise keinen UDF. Es kann als Join geschrieben werden. Es gibt keinen Hinweis oder keine Magie
Bearbeiten: Entfernen Sie die UDF. Für jede Zeile in Bewertungen Ihre Abfrage fähigitungen. Es ist exponentiell
Und ich bewegte die Filter in die Verknüpfungen
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;