Day*_*Day 21 mysql performance user-defined-functions
我重复使用此SELECT查询来读取表示IPv4地址的无符号整数,并将它们显示为人类可读的虚线四字符串.
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;
Run Code Online (Sandbox Code Playgroud)
使用我的测试数据,此查询需要3.6秒才能执行.
我认为为int-> string转换创建自定义存储函数将允许更容易读取查询并允许重用,所以我这样做:
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)
);
Run Code Online (Sandbox Code Playgroud)
使用此功能,我的查询如下所示:
SELECT IntToIp(ip) FROM ips;
Run Code Online (Sandbox Code Playgroud)
但是使用我的测试数据,这需要13.6秒才能执行.
我希望在首次运行时这会更慢,因为涉及额外的间接级别,但是近4倍的速度似乎过度.预计会这么缓慢吗?
我在Ubuntu 10.10上使用开箱即用的MySQL服务器5.1,没有配置更改.
要重现我的测试,请创建一个表并填充1,221,201行:
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();
Run Code Online (Sandbox Code Playgroud)
san*_*mai 22
不要重新发明轮子,使用INET_NTOA():
mysql> SELECT INET_NTOA(167773449);
-> '10.0.5.9'
Run Code Online (Sandbox Code Playgroud)
gui*_*ido 11
使用这个可以获得更好的性能:
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)
Run Code Online (Sandbox Code Playgroud)
在添加测试数据后启动原始SELECT在我的系统上花了4.78秒(四核上的2gB mysql 5.1实例(fedora 64位).
编辑:预计这么慢吗?
是的,存储过程很慢,比解释/编译代码慢一堆.当你需要绑定一些你想要远离你的应用程序的数据库逻辑时,它们变得很有用,因为它超出了特定的域(即日志/管理任务).如果存储的函数不包含任何查询,那么以您选择的语言编写实用程序函数总是更好的做法,因为它不会阻止重用(没有查询),并且运行速度会快得多.
这就是为什么在这种特殊情况下,你应该使用INET_NTOA函数,它可以满足你的需求,如sanmai的回答所示.