我反复使用这个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;
使用我的测试数据,此查询需要 3.6秒才能执行。
我认为creating a custom stored function用于int->字符串转换可以更容易地读取查询并允许重用,所以我做了这个:
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)
);
使用此功能,我的查询如下所示:
SELECT IntToIp(ip) FROM ips;
但是根据我的测试数据,这需要 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();
答案 0 :(得分:21)
请勿重新发明轮子,请使用INET_NTOA():
mysql> SELECT INET_NTOA(167773449);
-> '10.0.5.9'
答案 1 :(得分: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)
在我的系统上添加测试数据之后启动原始SELECT需要4.78秒(四核上的2gB mysql 5.1实例(fedora 64位)。
编辑: 期待这么慢吗?
是的,存储过程很慢,比解释/编译代码慢一堆。当你需要绑定一些你想要远离你的应用程序的数据库逻辑时,它们变得很有用,因为它超出了特定的域(即日志/管理任务)。如果存储的函数不包含任何查询,那么以您选择的语言编写实用程序函数总是更好的做法,因为它不会阻止重用(没有查询),并且运行速度会快得多。
这就是为什么在这种特殊情况下,你应该使用INET_NTOA函数,这可以满足你的需求,如sanmai的回答所示。