MySQL索引获取用于范围

时间:2016-02-23 19:45:09

标签: mysql indexing

我有一个用于城市ip块的MySQL表,

ip_ranges(city_id, CIDR, start_ip_decimal, end_ip_decimal)

数据类型如下

  1. city_id [unsigned bigint]
  2. CIDR [varchar 255]
  3. start_ip_decimal [unsigned bigint]:启动ip范围转换为十进制
  4. end_ip_decimal [unsigned bigint]:结束IP范围转换为十进制
  5. 所以我正在做的是,将用户ip转换为十进制,并检查此表以获取city_id。但查询需要花费太多时间 70秒来查找city_id

    SELECT city_id FROM ip_ranges WHERE 658206441 BETWEEN start_ip_decimal and end_ip_decimal 
    

    SELECT city_id FROM ip_ranges WHERE start_ip_decimal <= 658206441 AND end_ip_decimal >= 658206441
    

    注意: 658206441是从用户的IP地址转换的十进制值

    InnoDB 用作数据库引擎。 此表中总共有 10664916 条记录。

      

    Corei7 2.0GHz和2.6 GHz处理器,8 GB Ram(Windows 10)

    所以我的问题是如何加快查找速度。

    我尝试在开始和结束字段上应用索引 索引类型Normal和索引方法BTREE,但它没有任何影响。

    这是DDL的样子

    CREATE TABLE `ip_ranges` (
      `cidr` varchar(255) DEFAULT NULL,
      `start_ip_decimal` bigint(20) unsigned DEFAULT NULL,
      `end_ip_decimal` bigint(20) unsigned DEFAULT NULL,
      `city_id` bigint(20) unsigned DEFAULT NULL,
      KEY `my_index` (`start_ip_decimal`,`end_ip_decimal`) USING BTREE
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    

    解决方案:我已根据@RickJames评论解决了(我认为是这样)我的问题,但我可能已经错过了他的回复的几个部分。

    首先学到的是

      

    像IP地址这样的范围测试很难。没有简单的索引可行   好。

    所以我执行了以下步骤来实现我想要的目标。

    1 忽略end字段,经过Jame评论我意识到,每行start字段等于前一行的end+1

      

    但是,如果您只有一个起始IP而不是范围,那么   '结束'是下一行的开始,它可以做得更多   高效。

    network     start       end
    --------------------------------
    1.0.0.0/24  16777216    16777471
    1.0.1.0/24  16777472    16777727
    1.0.2.0/23  16777728    16778239
    

    然而,错过范围可能存在一些问题

    2 使用UNIQUEindex列上应用startBTREE

    3 修改后的SELECT查询如下

    SELECT * FROM ip_ranges
    WHERE $ipNumberToCheck >= `start` ORDER BY `start` DESC LIMIT 1
    

1 个答案:

答案 0 :(得分:1)

我希望它是INT UNSIGNED(未签名)。

我认为你不担心IPv6?

像IP地址这样的范围测试很难。没有简单的索引效果很好。您拥有的KEY平均会扫描500万行。

但是,如果您只有一个起始IP而不是范围,并且'end'是下一行的开头,那么它可以更有效率。这也涉及ORDER BY ip LIMIT 1。它涉及拥有未使用的IP范围的条目。我在my blog中介绍了所有这些以及有效的代码。它包括IPv4(就像您正在使用)和IPv6的存储例程。无论表大小如何,它都会在单行中找到该城市。因此它仅限于一次磁盘命中(粗略地说)。从逻辑上讲,它的速度是500万倍;但实际上70秒应该会下降到几毫秒。