在《高性能MySQL》第3版中,作者建议使用32位无符号整数(UNSIGNED INT)来存储IPv4地址而不是字符串,这一建议基于多个原因,下面将详细分析这些原因,并提供一些额外的背景信息和实用代码。
使用无符号整数存储IPv4地址的好处
-
节省空间:
- 数据存储空间:IPv4地址作为字符串存储时,最小需要7个字符,最大15个字符,加上MySQL存储变长字符串所需的额外字节,平均需要14.28字节。而使用无符号整数存储,仅需要4字节。
- 索引存储空间:整数类型的索引通常比字符串类型的索引小,这意味着索引可以更快地被存储和查询。
-
查询效率:
- 使用无符号整数存储IPv4地址可以方便地使用范围查询(如
BETWEEN...AND
),且效率更高。字符串类型的IP地址进行范围查询时,需要额外的函数转换,效率较低。
- 使用无符号整数存储IPv4地址可以方便地使用范围查询(如
-
性能:
-
使用字符串和无符号整数来存储IP的具体性能分析及benchmark,可以看这篇文章。
https://bafford.com/2009/03/09/mysql-performance-benefits-of-storing-integer-ip-addresses/
-
根据John Bafford的测试,即使考虑数据库进行字符串到数字的转换,存储IP地址为整数比字符串快9-12%。
-
使用无符号整数存储的缺点
-
不便于阅读:整数形式的IP地址不如字符串形式直观,不便于人工阅读和理解。
-
需要手动转换:在应用层需要进行字符串和整数之间的转换。
MySQL中的转换函数
INET_ATON
:将字符串格式的IP转换为整数。INET_NTOA
:将整数格式的IP转换为字符串。
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)
Java中的转换代码
下面的Java代码展示了如何在应用层进行字符串IP和整数之间的转换:
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
结论
尽管使用无符号整数存储IPv4地址在可读性和转换上存在一定的不便,但从性能和存储效率的角度考虑,这种方法具有明显的优势。特别是在进行大量IP地址范围查询的应用场景中,使用整数存储可以显著提高查询效率和减少存储空间的使用。对于新的数据库设计,推荐使用无符号整数来存储IPv4地址。