Warum ist meine eigene MySQL-Funktion so viel langsamer als inlining gleich in der Abfrage?
Ich benutz diese SELECT
Abfrage zu Lesen unsigned Ganzzahlen, die IPv4-Adressen zusammen und stellen diese als lesbare dotted-quad-strings.
SELECT CONCAT_WS('.',
FLOOR(ip/POW(256,3)),
MOD(FLOOR(ip/POW(256,2)), 256),
MOD(FLOOR(ip/256), 256),
MOD(ip, 256))
FROM ips;
Meiner test-Daten, diese Abfrage dauert 3,6 Sekunden zu führen.
Dachte ich, dass erstellen Sie eine benutzerdefinierte gespeicherte Funktion für die int->string Umwandlung würde es ermöglichen, einfacher zu Lesen, Abfragen und ermöglichen die Wiederverwendung, so dass ich dies:
CREATE FUNCTION IntToIp(value INT UNSIGNED)
RETURNS char(15)
DETERMINISTIC
RETURN CONCAT_WS(
'.',
FLOOR(value/POW(256,3)),
MOD(FLOOR(value/POW(256,2)), 256),
MOD(FLOOR(value/256), 256),
MOD(value, 256)
);
Mit dieser Funktion meine Abfrage sieht wie folgt aus:
SELECT IntToIp(ip) FROM ips;
aber mit meiner test-Daten, das dauert 13.6 Sekunden zu führen.
Ich würde erwarten, dass diese langsamer bei der ersten Ausführung, da es eine zusätzliche Dereferenzierungsebene beteiligt, aber fast 4-mal langsamer scheint übertrieben. Ist so viel Langsamkeit erwartet?
Bin ich mit aus der box MySQL-server-5.1 auf Ubuntu 10.10 mit keine änderungen in der Konfiguration.
Reproduzieren meinem test, erstellen Sie eine Tabelle und füllen Sie mit 1,221,201 Zeilen:
CREATE TABLE ips (ip INT UNSIGNED NOT NULL);
DELIMITER //
CREATE PROCEDURE AddIps ()
BEGIN
DECLARE i INT UNSIGNED DEFAULT POW(2,32)-1;
WHILE (i>0) DO
INSERT INTO ips (ip) VALUES (i);
SET i = IF(i<3517,0,i-3517);
END WHILE;
END//
DELIMITER ;
CALL AddIps();
Du musst angemeldet sein, um einen Kommentar abzugeben.
Mit dieser könnten Sie eine bessere Leistung erhalten:
Starten Sie Ihre original-WÄHLEN Sie einfach nach dem hinzufügen von Testdaten nahm 4.78 Sek. auf meinem system (2 GB mysql 5.1-Instanz auf quad-core (fedora 64 bit).
EDIT: Ist so viel Langsamkeit erwartet?
Ja, sind die gespeicherten Prozeduren langsam, ein paar Größenordnungen langsamer als interpretierte/compilierte code. Sie wiederum nützlich, wenn Sie brauchen, zu binden, einige Datenbank-Logik, die Sie behalten möchten, aus der Anwendung, weil es ist, aus der spezifischen Domäne (dh, Protokollierung/administrative Aufgaben). Wenn Sie eine gespeicherte Funktion enthält keine Anfragen, es ist immer besser der Praxis zum schreiben eines utility-Funktion in der von Ihnen gewählten Sprache, die nicht verhindern, dass die Wiederverwendung (keine Abfragen), und wird viel schneller laufen.
... Und das ist der Grund für die, in diesem besonderen Fall, verwenden Sie die Funktion INET_NTOA statt, die verfügbar ist, und erfüllt Ihre Bedürfnisse, wie vorgeschlagen, in sanmai Antwort.
time mysql -u root test -e "SELECT IntToIp2(ip) FROM ips" > /dev/null
vs 1,3 Sekunden fürtime mysql -u root test -e "SELECT CONCAT_WS('.', (ip>>24), (ip>>16)&255, (ip>>8)&255, ip&255) FROM ips" > /dev/null
so auch dieses mal der Funktionsaufruf-overhead mehr als 5 mal.Das Rad nicht neu erfinden, verwenden Sie INET_NTOA():
time mysql -u root test -e "SELECT INET_NTOA(ip) FROM ips" > /dev/null