两列之间的mysql选择工作得太慢了

mit*_*sky 2 mysql indexing select between

我有这个问题:

SELECT `country`
FROM `geoip_base`
WHERE 1840344811 BETWEEN `start` AND `stop`
Run Code Online (Sandbox Code Playgroud)

它是使用索引(使用,但解析表的大部分)并且工作太慢.我试过使用ORDER BY和LIMIT,但它没有帮助.

"start <= 1840344811 AND 1840344811 <= stop"的工作方式类似.

CREATE TABLE IF NOT EXISTS `geoip_base` (
  `start` decimal(10,0) NOT NULL,
  `stop` decimal(10,0) NOT NULL,
  `inetnum` char(33) collate utf8_bin NOT NULL,
  `country` char(2) collate utf8_bin NOT NULL,
  `city_id` int(11) NOT NULL,
  PRIMARY KEY  (`start`,`stop`),
  UNIQUE KEY `start` (`start`),
  UNIQUE KEY `stop` (`stop`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
Run Code Online (Sandbox Code Playgroud)

表有57,424行.

解释查询"......按开始限制1开始和停止开始":使用键stop并获得24099行.没有顺序和限制,mysql不使用键并获取所有行.

Qua*_*noi 5

如果您的表是MyISAM,您可以使用SPATIAL索引改进此查询:

ALTER TABLE
        geoip_base
ADD     ip_range LineString;

UPDATE  geoip_base
SET     ip_range =
        LineString
                (
                Point(-1, `start`),
                Point(1, `stop`)
                );

ALTER TABLE
        geoip_base
MODIFY  ip_range NOT NULL;

CREATE SPATIAL INDEX
        sx_geoip_range ON geoip_base (ip_range);

SELECT  country
FROM    geoip_base
WHERE   MBRContains(ip_range, Point(0, 1840344811)
Run Code Online (Sandbox Code Playgroud)

您可能会对本文感兴趣:

或者,如果您的范围不相交(并且根据数据库的性质除外),您可以创建UNIQUE索引geoip_base.start并使用此查询:

SELECT  *
FROM    geoip_base
WHERE   1840344811 BETWEEN `start` AND `stop`
ORDER BY
        `start` DESC
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

注意ORDER BYLIMIT条件,它们很重要.

此查询与此类似:

SELECT  *
FROM    geoip_base
WHERE   `start` <= 1840344811
        AND `stop` >= 1840344811
ORDER BY
        `start` DESC
LIMIT 1;
Run Code Online (Sandbox Code Playgroud)

使用ORDER BY / LIMIT使查询选择降序索引扫描,start该扫描将在第一个匹配时停止(即在start最接近IP您输入的范围内).停止时的附加过滤器将仅检查范围是否包含此内容IP.

由于您的范围不相交,因此该范围或根本没有范围将包含IP您之后的范围.