原理
相对字符串存储,使用无符号整数来存储有如下的好处:
- 节省空间(数据存储空间、索引存储空间)
- 便于使用范围查询(BETWEEN…AND)且效率更高
通常,在保存IPv4地址时,一个IPv4最小需要7个字符,最大需要15个字符,所以,使用VARCHAR(15)
即可。MySQL在保存变长的字符串时,还需要额外的一个字节来保存此字符串的长度。而如果使用无符号整数来存储,只需要4个字节即可。
另外还可以使用4个字段分别存储IPv4中的各部分,但是通常这不管是存储空间和查询效率应该都不是很高(可能有的场景适合使用这种方式存储)。
使用无符号整数来存储也有缺点:
- 不便于阅读
- 插入查询需要转换类型
对于转换来说,MySQL提供了相应的函数来把字符串格式的IP转换成整数INET_ATON
,以及把整数格式的IP转换成字符串的INET_NTOA
。如下所示:
mysql> select inet_aton('192.168.0.1');
+--------------------------+
| inet_aton('192.168.0.1') |
+--------------------------+
| 3232235521 |
+--------------------------+
1 row in set (0.00 sec)
mysql> select inet_ntoa(3232235521);
+-----------------------+
| inet_ntoa(3232235521) |
+-----------------------+
| 192.168.0.1 |
+-----------------------+
1 row in set (0.00 sec)
测试
创建测试表:
drop table if exists test_ip;
create table test_ip
(
ip int unsigned
);
插入数据时要将IP字符串转换为整数:
insert into test_ip (ip)
values (inet_aton('192.168.1.1')),
(inet_aton('192.168.1.2')),
(inet_aton('192.168.1.3')),
(inet_aton('192.168.1.4'));
插入后是这样的:
mysql> select * from test_ip;
+------------+
| ip |
+------------+
| 3232235777 |
| 3232235778 |
| 3232235779 |
| 3232235780 |
+------------+
查询数据使用inet_ntoa
函数将整数转换为IP字符串:
mysql> select inet_ntoa(ip) from test_ip;
+---------------+
| inet_ntoa(ip) |
+---------------+
| 192.168.1.1 |
| 192.168.1.2 |
| 192.168.1.3 |
| 192.168.1.4 |
+---------------+
可以使用大于、小于、between实现高效的范围查询:
select inet_ntoa(ip) from test_ip
where ip > inet_aton('192.168.1.2');
select inet_ntoa(ip) from test_ip
where ip between inet_aton('192.168.1.2') and inet_aton('192.168.1.4');