这个问题在我的一个相关项目中出现过,而且这似乎是谷歌搜索结果中排名最高的答案,所以你得到了答案!
create function get_lowest_ipv4(cidr char(18)) returns bigint deterministic return INET_ATON(SUBSTRING_INDEX(cidr, '/', 1));
create function get_highest_ipv4(cidr char(18)) returns bigint deterministic return get_lowest_ipv4(cidr) + (0x100000000 >> SUBSTRING_INDEX(cidr,'/', -1)) - 1;
您可以执行以下操作... from ip_map where INET_ATON("ip.add.re.ss") between get_lowest_ipv4(ip) AND get_highest_ipv4(ip)
因为您将函数声明为确定性的,它将被缓存在MySQL中,计算只需要运行一次。然后它将变成"整数是否大于y且小于x",这将非常快速。
MySQL [astpp]> set @cidr="10.11.0.0/16";
Query OK, 0 rows affected (0.00 sec)
MySQL [astpp]> select get_lowest_ipv4(@cidr), get_highest_ipv4(@cidr), INET_NTOA(get_lowest_ipv4(@cidr)), INET_NTOA(get_highest_ipv4(@cidr));
+
| get_lowest_ipv4(@cidr) | get_highest_ipv4(@cidr) | INET_NTOA(get_lowest_ipv4(@cidr)) | INET_NTOA(get_highest_ipv4(@cidr)) |
+
| 168493056 | 168558591 | 10.11.0.0 | 10.11.255.255 |
+
1 row in set (0.00 sec)
MySQL [astpp]> set @cidr="10.11.12.1/32";
Query OK, 0 rows affected (0.00 sec)
MySQL [astpp]> select get_lowest_ipv4(@cidr), get_highest_ipv4(@cidr), INET_NTOA(get_lowest_ipv4(@cidr)), INET_NTOA(get_highest_ipv4(@cidr));
+
| get_lowest_ipv4(@cidr) | get_highest_ipv4(@cidr) | INET_NTOA(get_lowest_ipv4(@cidr)) | INET_NTOA(get_highest_ipv4(@cidr)) |
+
| 168496129 | 168496129 | 10.11.12.1 | 10.11.12.1 |
+
1 row in set (0.01 sec)
MySQL [astpp]>
唯一需要注意的是插入有效的CIDR。例如,10.11.12.13/24是无效的。这是10.11.12.0/24网络内部的IP地址。
如果您无法在插入之前验证CIDR(出于某种疯狂的原因),则可以更改get_lowest_ipv4以对源进行位比较,但这样做要不太优雅。
INET_ATON(SUBSTRING_INDEX(`ip`, '/', 1)) & 0xffffffff ^((0x1 <<(32 - SUBSTRING_INDEX(`ip`, '/', -1))) -1 )
这是一个(未经测试的)尝试匹配无效的CIDRs。