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_num
和 end_ip_num
作为 varchar
字段。
所以以 92.11[...] 开头的 IP 也将在第一条记录的范围之间。对于第一条记录,它检查 92.0
和 92.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 地址)占用。
我已经安装了 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_num
和 end_ip_num
作为 varchar
字段。
所以以 92.11[...] 开头的 IP 也将在第一条记录的范围之间。对于第一条记录,它检查 92.0
和 92.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 地址)占用。