终于周四了,今天咱们聊下数据库存储IP地址时的数据类型选择问题。
在高性能mysql一书中,作者建议:当存储IPv4的地址时,使用32位的无符号整数(UNSIGNED INT)来存储,而不是使用字符串。
优点
- 节省空间,不管是数据存储空间还是索引存储空间
- 便于使用范围查询(between and),效率也更高
与字符串类型比较
在使用字符串存储ip地址时,字符串长度在7-15之间,所以可以使用varchar(15)来存储。同时,mysql在存储变长字符串时,还需要一个额外的字节来存储字符串的长度。而使用无符号整数存储时,只需要4个字节。
缺点
- 不便于阅读
- 需要手动转换
对于转换来讲,mysql 提供了把字符串格式转成整数的函数
INET_ATON,以及把整数转换为字符串格式的函数INET_NTOA
select inet_aton('192.168.0.1');
3232235521
select inet_ntoa('3232235521');
192.168.0.1
IPv6使用VARBINARY可以获得相同的好处同时MySQL也提供了相应的转换函数,即INET6_ATON和INET6_NTOA
转换IPv4与字符串可以放在应用层。
java实现
public class IpLongUtils {
/**
* 把字符串IP转换成long
*
* @param ipStr 字符串IP
* @return IP对应的long值
*/
public static long ip2Long(String ipStr) {
String[] ip = ipStr.split("\\.");
return (Long.valueOf(ip[0]) << 24) + (Long.valueOf(ip[1]) << 16)
+ (Long.valueOf(ip[2]) << 8) + Long.valueOf(ip[3]);
}
/**
* 把IP的long值转换成字符串
*
* @param ipLong IP的long值
* @return long值对应的字符串
*/
public static String long2Ip(long ipLong) {
StringBuilder ip = new StringBuilder();
ip.append(ipLong >>> 24).append(".");
ip.append((ipLong >>> 16) & 0xFF).append(".");
ip.append((ipLong >>> 8) & 0xFF).append(".");
ip.append(ipLong & 0xFF);
return ip.toString();
}
public static void main(String[] args) {
System.out.println(ip2Long("192.168.0.1"));
System.out.println(long2Ip(3232235521L));
System.out.println(ip2Long("10.0.0.1"));
}
}
输出为:
3232235521
192.168.0.1
167772161