优化整数范围搜索的MySQL查询

时间:2013-10-18 18:24:15

标签: mysql indexing query-optimization

我在一张表中有超过170万条记录,其中包含主要密钥和相应详细信息的IP地址范围(开始和结束)。

表结构是

mysql> desc csv;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| begin   | bigint(20)  | NO   | PRI | 0       |       |
| end     | bigint(20)  | NO   | PRI | 0       |       |
| code    | char(2)     | YES  |     | NULL    |       |
| country | varchar(50) | YES  |     | NULL    |       |
| city    | varchar(50) | YES  |     | NULL    |       |
| area    | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+

由于主键中的索引,当要像这样进行完全匹配时搜索速度很快

mysql> SELECT * FROM csv WHERE begin=3338456576;
+------------+------------+------+---------------+----------+---------------+
| begin      | end        | code | country       | city     | area          |
+------------+------------+------+---------------+----------+---------------+
| 3338456576 | 3338456831 | US   | UNITED STATES | NEW YORK | NEW YORK CITY |
+------------+------------+------+---------------+----------+---------------+
1 row in set (0.03 sec)

但是当我尝试在一个范围内搜索时,需要更长的时间。

mysql> SELECT * FROM csv WHERE begin<3338456592 AND end>3338456592;
+------------+------------+------+---------------+----------+---------------+
| begin      | end        | code | country       | city     | area          |
+------------+------------+------+---------------+----------+---------------+
| 3338456576 | 3338456831 | US   | UNITED STATES | NEW YORK | NEW YORK CITY |
+------------+------------+------+---------------+----------+---------------+
1 row in set (1.59 sec)

有什么方法可以优化我的查询来搜索某个范围内的IP地址吗?

修改

创建表语句

CREATE TABLE `csv` (
  `begin` bigint(20) NOT NULL DEFAULT '0',
  `end` bigint(20) NOT NULL DEFAULT '0',
  `code` char(2) DEFAULT NULL,
  `country` varchar(50) DEFAULT NULL,
  `city` varchar(50) DEFAULT NULL,
  `area` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`begin`,`end`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

3 个答案:

答案 0 :(得分:3)

如果IP范围不重叠,那么查询永远不会返回超过1行,您可以使用:

SELECT q.*
FROM 
  ( SELECT csv.* 
    FROM csv
    WHERE csv.begin < 3338456592 
    ORDER BY csv.begin DESC
    LIMIT 1
  ) AS q
WHERE 3338456592 < q.end ;

不需要添加索引。将使用主索引。

答案 1 :(得分:1)

如果范围重叠,您应该:

  • 将ip范围定义为LineString列
  • 在该列上定义空间索引
  • 使用几何&#34;包含&#34;查询

Efficient data model for range queries

中查看详情

答案 2 :(得分:0)

SELECT begin, end, code, country, city, area FROM csv WHERE begin <> 3338456592 HAVING begin NOT BETWEEN MIN(begin) AND MAX(end)得分是什么?

<强> UPD : 这是我的表结构版本。

CREATE TABLE `csv` (
  `begin` INT(10) NOT NULL DEFAULT '0',
  `end` INT(10) NOT NULL DEFAULT '0',
  `code` char(2) DEFAULT NULL,
  `country` varchar(50) DEFAULT NULL,
  `city` varchar(45) DEFAULT NULL,
  `area` varchar(40) DEFAULT NULL,
  KEY `combined` (`begin`,`end`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

我认为使用国家和代码作为ENUM它更快。