[MySQL] UDF vs. Query

secret_3des

Lieutenant
Registriert
Sep. 2005
Beiträge
822
Hi!

Ich dachte eigentlich, dass UDFs (User defined functions) in MySQL performant sind, da sie (meines Wissens) in reines C übersetzt werden. Dem ist aber scheinbar nicht so.. Hat jemand eine Erklärung dafür? Bzw. weiß jemand wieso die folgende UDF so langsam ist?

Also hier eine UDF:
Code:
delimiter //
CREATE FUNCTION around (val DOUBLE, around_val DOUBLE, d DOUBLE) RETURNS INT
BEGIN
RETURN CEIL(ABS((val-around_val)) / d);
END;
//
Wenn ich die Funktion dann in einer Query über eine Test-Tabelle mit 100.000 Einträgen laufen lasse:
Code:
SELECT *, around (km, 30000, 1000) FROM cars100000;
Dann dauert das 0,8957 Sekunden (laut MySQL Query Browser)

Das ganze in eine SQL-Query verpackt:
Code:
SELECT *, ceil(abs(30000.0 - km) / 1000.0) FROM cars100000;
dauert 0,5777 Sekunden. Also ist etwa 64% schneller.. Wenn man dann natürlich mehrere solcher UDFs in einer Query einsetzt, ist der Unterschied noch höher (bzw. summiert sich noch höher auf).

Woran liegt es also? Im Prinzip läuft doch das gleiche ab..

Viele Grüße,
Tom
 
Also in reines C wird die UDF garantiert nicht übersetzt, da dann zusätzlich eine weitere Übersetzung vorgenommen werden müsste (sprich: wäre unsinnig).
Das deine UDF langsamer ist hängt mit der Optimierung des Queries zusammen. Durch deine UDF geht als erstes die Information verloren, das du durch eine Konstante dividierst, das lässt sich auf heuten Architekturen sehr gut optimieren (Vektor-Operationen). Gleiches gilt für die anderen Teiloperationen.
Benutzt du dagegen deine UDF hat der Optimizer ein dickes Problem: Die Zusatzinformationen können nicht verwendet werden, da die UDF in kompilierter Form vorliegt! Das ist übrigens auch der Grund warum man generell bei jeder Datenbank UDFs mit Bedacht einsetzen muss.
Aber das das verhalten logisch ist kannst du dir auch an folgendem Beispiel klar machen (bissel Mathe ^^):

Du hast die folgende Funktion:

x := int-spalte aus der DB

a = b*c + e*x


nun setzt du die folgenden Werte ein:
b=0, c=444, e=0

Was macht nun der Optimizer?

Fall UDF: er rechnet 0*444 + 0*X
Das sind 3 Operationen! Ist auch logisch, schließlich kann nicht ein kompilierte Version für jede Kombination vorliegen.

Fall ohne UDF: b*c fällt raus (wegoptimiert), e*x wird auf 0 gekürzt
Es bleibt eine Konstanten-Operation übrig (Null-setzen)

Allein an diesem winzigen Beispiel erkennt du, warum die UDF langsamer ist, noch nicht berücksichtigt sind hier Vektor- und Cache-Optimierungen, die zusätzlich vorgenommen werden können.
 
Zurück
Oben