【问题标题】:Subquery and Indexing for IP InformationIP信息的子查询和索引
【发布时间】:2011-12-06 22:57:03
【问题描述】:

我在尝试在包含用户信息的表和包含地理位置数据的表(来自 GeoIP 的数据库)之间进行交叉引用时遇到问题。

我在用户表中有标准格式的 IP 地址(不是整数),在 GeoIP 表中有 GeoIP 数据,IP 范围为整数。

此查询有效,但速度很慢且未优化。

SELECT email, country 
FROM users 
INNER JOIN geoip ON users.ip BETWEEN geoip.startip AND geoip.endip

我觉得我在这里遗漏了一些非常简单的东西。

更新:此查询有效,但速度很慢 - 有什么方法可以对其进行索引以使其运行得更快?现在不管什么时候运行,每行执行大约需要300-500ms,太慢了。

SELECT email, country 
FROM users INNER JOIN geoip ON INET_ATON(users.ip) 
BETWEEN geoip.startip AND geoip.endip

谢谢!

更新 2:这是查询的 EXPLAIN 输出:

+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows     | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | geoip     | ALL  | NULL          | NULL | NULL    | NULL |  3651972 |             | 
|  1 | SIMPLE      | users     | ALL  | NULL          | NULL | NULL    | NULL | 87996123 | Using where | 
+----+-------------+-----------+------+---------------+------+---------+------+----------+-------------+

我现在无法添加仅整数的 IP 行,因为数据库正在使用中,它有超过 9000 万行;这将是我在停机期间考虑做的事情,但现在,我想让它以这种方式运行。

【问题讨论】:

    标签: mysql geoip


    【解决方案1】:

    我还不能发表评论,所以这里有一个“答案”......

    你确定它有效吗?如果我正确理解您的描述,您将 users.ip 作为 char 或 varchar 中的 CIDR 表示法,并将 geoip.startip/endip 作为整数。因此,此查询无法正确比较这两者。

    这样做的正确方法是

    SELECT email, country 
    FROM users INNER JOIN geoip ON INET_ATON(users.ip) 
    BETWEEN geoip.startip AND geoip.endip
    

    SELECT email, country 
    FROM users INNER JOIN geoip ON users.ip 
    BETWEEN INET_NTOA(geoip.startip) AND INET_NTOA(geoip.endip) 
    

    哪个更好,取决于哪个表更大(更多行)。

    不过,最好的方法是将 users.ip 存储为整数(或具有整数解释的另一列)。

    【讨论】:

    • 第一个查询有效,但速度很慢 - 有没有办法索引它以使其运行得更快?现在,无论如何,每行至少需要 300-500 毫秒。
    • 你有关于 geoip.startip 和 geoip.endip 的索引吗?
    • 是的,还有一个关于 startip、endip 和 country 的索引。
    • 除非您在 WHERE、SORT、JOIN 或此类子句中使用它,否则您不需要关于国家/地区的索引...您能提供DESCRIBE your_query 所说的内容吗?另外,您可以尝试将整数 ip 添加到您的用户表并尝试使用该列而不是 CIDR ip 加入吗? (ALTER TABLE users ADD (intip int usigned), ADD INDEX intip(intip); UPDATE users SET intip = INET_ATON(ip);)
    • 我已将 EXPLAIN 输出添加到问题中。目前,我无法添加有问题的 IP 行,但希望在停机期间添加(数据库正在使用中,有 9000 万行)。
    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 2013-10-03
    • 2013-08-23
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 2014-03-01
    • 2013-01-02
    相关资源
    最近更新 更多