GeoIP 数据库 SQL 查询 returns 多个结果

GeoIP database SQL query returns multiple results

我已经安装了 Maxmind GeoIP database,现在我正在测试结果。我住在阿姆斯特丹,所以我用自己的 IP 地址进行了 IP 查询检查,但得到了 2 个结果。是我哪里做错了还是数据不清楚?

数据库示例:

SQL查询:

SELECT * FROM wp_geoip WHERE '{my-ip-address}' BETWEEN begin_ip_num AND end_ip_num;

结果:

它可能使用 begin_ip_numend_ip_num 作为 varchar 字段。

所以以 92.11[...] 开头的 IP 也将在第一条记录的范围之间。对于第一条记录,它检查 92.092.3

之间的任何字符串

所以在这种情况下进行文本搜索会得到错误的结果。您可以尝试将所有 IP 转换为良好的可搜索字符串。这意味着像 92.31.255.255 这样的 ip 应该转换为 092.031.255.255

如果你对所有 IP 都这样做,你就可以对它们进行适当的搜索。

CREATE FUNCTION dbo.formatIP ( @ip varchar(20) )
RETURNS varchar(20)
AS
BEGIN
    SELECT  RIGHT('000' + PARSENAME(@ip,4), 3) + '.' + 
            RIGHT('000' + PARSENAME(@ip,3), 3) + '.' + 
            RIGHT('000' + PARSENAME(@ip,2), 3) + '.' + 
            RIGHT('000' + PARSENAME(@ip,1), 3)
END

将其封装在一个函数中并像这样使用它:

SELECT * FROM wp_geoip 
WHERE dbo.formatIP('{my-ip-address}') 
     BETWEEN dbo.formatIP(begin_ip_num) AND dbo.formatIP(end_ip_num);

您不能只将 IP 地址存储为 varchar。好吧……你 可以 ,但从根本上讲这是错误的。

正确的解决方案是将 IP 地址存储为它们实际表示的内容:无符号 32 位整数 (INT UNSIGNED)。

导入数据时,使用 INET_ATON() built-in function 转换数据,它将点分四组 IPv4 地址转换为无符号整数。

使用反函数查询数据:

WHERE INET_NTOA('you.r.ip.add') BETWEEN begin_ip_num AND end_ip_num;

如果在两个方向上索引开始和结束列,您将获得更好的性能,例如:

PRIMARY KEY(begin_ip_num,end_ip_num),
KEY(end_ip_num,begin_ip_num)

但是...B 树不是这种搜索的最佳选择。

如果您使用 spatial index, as Jeremy Cole explains in a blog post on the topic,您还可以更快地查询它。请注意,他还详细介绍了 INET_ATON()INET_NTOA().

的用法

空间索引概念让一些人大吃一惊,因为他们认为 "spatial" 仅表示“geospatial”,但 IP 地址 space 毕竟,MySQL 的空间扩展提供的 "space" 和 R-Tree 索引比 B 树更适合搜索边界"space" 某事物(如 IP 地址)占用。