GeoIP 数据库 SQL 查询返回多个结果

Posted

技术标签:

【中文标题】GeoIP 数据库 SQL 查询返回多个结果【英文标题】:GeoIP database SQL query returns multiple results 【发布时间】:2015-09-16 08:57:55 【问题描述】:

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

数据库示例:

SQL 查询:

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

结果:

【问题讨论】:

【参考方案1】:

您不能只将 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-Trees 并不是这种搜索的最佳选择。

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

空间索引的概念让一些人大吃一惊,因为他们认为“空间”仅意味着“geo空间”,但 IP 地址 space 毕竟仍然是“空间” " 和 R-Tree mysql 的空间扩展提供的索引在搜索事物(如 IP 地址)占用的“空间”边界方面比 B-Tree 更优化。

【讨论】:

感谢您的回答!我对 MySQL 的 lvl 知识很低。因此,在我在 phpmyadmin 中创建表并使用导入工具上传 CSV 文件之前。但是当您需要使用内置功能时,您应该制作一个导入脚本,对吗?我应该从哪里开始? 您实际上可以从已有的表开始。使用所需的结构和列在相同位置创建一个新表,然后使用INSERT ... SELECT 通过转换从一个表复制到另一个表:INSERT INTO table2 SELECT INET_ATON(begin_ip_num), INET_ATON(end_ip_num), longitude, ... FROM table1;。 dev.mysql.com/doc/refman/5.6/en/insert-select.html【参考方案2】:

它可能使用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);

【讨论】:

感谢您的回答。我会试试!是否也可以将类型从 varchar 更改为 unsigned int? 我收到了这个语法错误:#1064 - 您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 '@ip varchar(20) ) RETURNS varchar(20) AS BEGIN SELECT RIGHT('000' + PAR' 附近使用正确的语法 我没有看到它是关于 MySQL 服务器的。您的帖子中有一个 SQL-server 标签。我不确定如何为 MySQL 重写它 对不起,我的错。

以上是关于GeoIP 数据库 SQL 查询返回多个结果的主要内容,如果未能解决你的问题,请参考以下文章

sql 问题子查询返回的值不止一个。

SQL:查询数据库中所有表的字段,并在查询结果中返回表、字段、字段描述

易语言中如何从SQL查询中返回结果?

SQL总结

sql 子查询返回的值不止一个怎么解决?

SQL查询语句查询多个数据