有点像
SELECT COUNT(*) AS c FROM BANS WHERE typeid=6 AND (SELECT ipaddr,cidr FROM BANS) MATCH AGAINST 'this_ip';
因此,您不必先从数据库中获取所有记录,然后逐条匹配它们。
如果 c > 0 那么匹配。
禁令表:
id int auto incr PK
typeid TINYINT (1=hostname, 4=ipv4, 6=ipv6)
ipaddr BINARY(128)
cidr INT
host VARCHAR(255)
数据库:MySQL 5
IP 和 IPv 类型(4 或 6)在查询时是已知的。
IP 例如二进制格式的::1
BANNED IP 例如:::1/64
最佳答案
请记住,IP 不是文本地址,而是数字 ID。我有类似的情况(我们正在做geo-ip查找),如果您将所有IP地址存储为整数(例如,我的IP地址是192.115.22.33所以它存储为3228767777),那么您可以查找IP使用右移运算符很容易。
所有这些类型的查找的缺点是您无法从索引中受益,并且每次查找时都必须进行全表扫描。上述方案可以通过存储CIDR网络的网络IP地址(范围的开始)和广播地址(范围的结束)来改进,例如存储192.168.1.0/24可以存储两个列:
network broadcast
3232235776, 3232236031
然后你就可以简单地匹配它
SELECT count(*) FROM bans WHERE 3232235876 >= network AND 3232235876 <= broadcast
这将使您可以将 CIDR 网络存储在数据库中,并利用快速数字索引将它们与 IP 地址快速有效地匹配。
以下讨论的注意事项:
MySQL 5.0 包含一个名为“index merge intersect”的范围查询优化,它允许加速此类查询(并避免全表扫描),只要:
- 有一个多列索引按顺序与查询中的列完全匹配。所以 - 对于上面的查询示例,索引需要是
(network, broadcast)
。 - 可以从索引中检索所有数据。这适用于
COUNT(*)
,但不适用于SELECT * ... LIMIT 1
。
MySQL 5.6 包含一个称为 MRR 的优化,它也可以加快全行检索,但这超出了此答案的范围。
关于mysql - 有没有办法直接从 SELECT 查询中将 IP 与 IP+CIDR 匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/595748/