[SOLVED] Why is my custom MySQL function so much slower than inlining same in query?

Issue

I repeatedly use this SELECT query to read unsigned integers representing IPv4 addresses and present them as human readable 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;

With my test data, this query takes 3.6 seconds to execute.

I thought that creating a custom stored function for the int->string conversion would allow for easier to read queries and allow reuse, so I made this:

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)
  );

With this function my query looks like this:

SELECT IntToIp(ip) FROM ips;

but with my test data, this takes 13.6 seconds to execute.

I would expect this to be slower on first run, as there is an extra level of indirection involved, but nearly 4 times slower seems excessive. Is this much slowness expected?

I’m using out of the box MySQL server 5.1 on Ubuntu 10.10 with no configuration changes.


To reproduce my test, create a table and populate with 1,221,201 rows:

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();

Solution

Using this one you could get better performance:

CREATE FUNCTION IntToIp2(value INT UNSIGNED)
  RETURNS char(15)
  DETERMINISTIC
  RETURN CONCAT_WS(
    '.', 
    (value >> 24),
    (value >> 16) & 255,
    (value >>  8) & 255,
     value        & 255
  );

> SELECT IntToIp(ip) FROM ips;
1221202 rows in set (18.52 sec)

> SELECT IntToIp2(ip) FROM ips;
1221202 rows in set (10.21 sec)

Launching your original SELECT just after adding your test data took 4.78 secs on my system (2gB mysql 5.1 instance on quad core (fedora 64 bit).

EDIT: Is this much slowness expected?

Yes, stored procedures are slow, a bunch of magnitudes slower than interpreted/compiled code. They turn out useful when you need to tie up some database logic which you want to keep out of your application because it’s out of the specific domain (ie, logging/administrative tasks). If a stored function contains no queries, it’s always better practice to write an utility function in your chosen language, as that wont prevent reuse (there are no queries), and will run much faster.

And that’s the reason for which, in this particular case, you should use the INET_NTOA function instead, which is available and fulfils your needs, as suggested in sanmai answer.

Answered By – guido

Answer Checked By – Clifford M. (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *