IPv4如何存储比较好

IPv4如何存储比较好

之前在网上看到一篇文章,说IPv4可以使用UNSIGNED INT 数据类型进行存储,比通过字符串存储有两个好处:

  • 占用空间更小,UNSIGNED INT可通过4个字节存储,而IP地址存储需要7~15个字节
  • 支持范围查询

当然同时也存在坏处:

  • 可读性差。底层是通过整型存储,从数据库直接读取的是整数
  • 需要手动转换。如果想得到IP地址,就得在sql中通过指定函数转换

下边通过实例详细看一下:

创建测试表

CREATE TABLE `tb_ip` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '唯一ID',
  `ipval` int(11) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'IP',
	`ip` varchar(15) NOT NULL DEFAULT '' COMMENT 'IP',
  PRIMARY KEY (`id`),
  KEY `idx_ipval` (`ipval`),
  KEY `idx_ip` (`ip`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='ip测试表';

插入测试数据

首先讲一下,mysql内置函数支持ip地址与整形转换:

  • inet_aton :把IP地址转为整形
  • inet_ntoa:把整形转为IP地址
INSERT into tb_ip(ipval,ip) 
VALUES 
	(inet_aton('192.168.0.1'),'192.168.0.1'),
	(inet_aton('192.168.0.2'),'192.168.0.2'),
	(inet_aton('192.168.0.3'),'192.168.0.3'),
	(inet_aton('192.168.0.4'),'192.168.0.4'),
	(inet_aton('192.168.0.5'),'192.168.0.5'),
	(inet_aton('192.168.0.6'),'192.168.0.6'),
	(inet_aton('192.168.0.7'),'192.168.0.7'),
	(inet_aton('192.168.0.8'),'192.168.0.8'),
	(inet_aton('192.168.0.9'),'192.168.0.9'),
	(inet_aton('192.168.0.10'),'192.168.0.10'),
	(inet_aton('192.168.0.11'),'192.168.0.11'),
	(inet_aton('192.168.0.12'),'192.168.0.12')
;

通过指定IP查询记录

整形和字符串类型都支持指定查询

// 通过整形查询
select * from tb_ip where ipval = inet_aton('192.168.0.5');
// 通过IP字段查询
select * from tb_ip where ip = '192.168.0.5';

范围查询

范围查询只能通过整形字段实现,字符串字段不支持该操作

select * from tb_ip where ipval BETWEEN inet_aton('192.168.0.5') and inet_aton('192.168.0.10');

查询结果转换

select id,inet_ntoa(ipval),ip from tb_ip where ipval BETWEEN inet_aton('192.168.0.5') and inet_aton('192.168.0.10');

结果:
IPv4如何存储比较好_第1张图片
由此看到,整形存储比字符串存储对场景支持要广

IP地址与整形转换实现

// ip地址转整形
func inetAton(ip string) int {
	ipSlice := strings.Split(ip, `.`)
	ipVal, movNum := 0, 8*(len(ipSlice)-1)
	for _, item := range ipSlice {
		itemVal, err := strconv.Atoi(item)
		if err != nil {
			return 0
		}
		ipVal += itemVal << movNum
		movNum -= 8
	}
	return ipVal
}

// 整形转IP地址
func inetNtoa(ipVal int) string {
	ipSlice := []string{}
	for {
		if ipVal == 0 {
			break
		}
		item := ipVal & 0xFF
		ipSlice = append([]string{strconv.Itoa(item)}, ipSlice...)
		ipVal >>= 8
	}
	return strings.Join(ipSlice, `.`)
}

你可能感兴趣的:(mysql,mysql,dba,数据库)