当前位置: 首页 > 科技观察

面试官:如果要存储一个ip地址,哪种数据类型比较好?_0

时间:2023-03-22 00:15:05 科技观察

作者在阅读高性能MySQL第三版(4.1.7节)时建议存储IPv4地址时,应该使用一个32位无符号整数(UNSIGNEDINT)来存储IP地址,而不是使用字符串。但没有给出具体原因。为了查明原因,查了一些资料记录一下。与字符串存储相比,使用无符号整数存储有以下优点:节省空间,无论是数据存储空间还是索引存储空间,使用范围查询(BETWEEN...AND)都方便,效率更高。一般在保存IPv4地址时,一个IPv4要求最少7个字符,最多15个字符,所以使用VARCHAR(15)即可。MySQL在保存变长字符串时,需要额外的一个字节来保存字符串的长度。而如果使用无符号整数来存储,只需要4个字节。另外也可以用4个字段分别存储IPv4的每一部分,但通常这样在存储空间和查询效率上应该不会很高(可能有一些场景适合这种方式存储)。关于使用字符串和无符号整数存储IP的具体性能分析和基准测试,可以阅读这篇文章。https://bafford.com/2009/03/09/mysql-performance-benefits-of-storing-integer-ip-addresses/使用无符号整数存储也有缺点,不易阅读,需要手动转换。对于转换,MySQL提供了相应的函数,将字符串格式的IP转换为整数INET_ATON,将整数格式的IP转换为字符串格式的INET_NTOA。如下:mysql>selectinet_aton('192.168.0.1');+------------------------+|inet_aton('192.168.0.1')|+------------------------+|3232235521|+----------------------+1行在集合中(0.00秒)mysql>选择inet_ntoa(3232235521);+---------------------+|inet_ntoa(3232235521)|+--------------------+|192.168.0.1|+----------------------+1rowinset(0.00sec)对于IPv6,使用VARBINARY也可以获得相同的好处,并且MySQL也提供了相应的转换函数,即INET6_ATON和INET6_NTOA。对于stringIPv4和numeric类型的转换,可以放在应用层下使用java代码将两者转换:packagecom.mikan;/***@authorMikan*/publicclassIpLongUtils{/***StringIP转long**@paramipStrstringIP*@returnlongIP对应的值*/publicstaticlongip2Long(StringipStr){String[]ip=ipStr.split("\\.");返回(Long.valueOf(ip[0])<<24)+(Long.valueOf(ip[1])<<16)+(Long.valueOf(ip[2])<<8)+Long.valueOf(ip[3]);}/***将IP的long值转成字符串**@paramipLongIP的long值*@returnlong值对应的字符串*/publicstaticStringlong2Ip(longipLong){StringBuilderip=newStringBuilder();ip.append(ipLong>>>24).append(".");ip.append((ipLong>>>16)&0xFF).append(".");ip.append((ipLong>>>8)&0xFF).append(".");ip.append(ipLong&0xFF);返回ip.toString();}publicstaticvoidmain(String[]args){System.out.println(ip2Long("192.168.0.1"));System.out.println(long2Ip(3232235521L));System.out.println(ip2Long("10.0.0.1"));}}输出结果为:3232235521192.168.0.1167772161