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不使用键并获取所有行.
如果您的表是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 BY和LIMIT条件,它们很重要.
此查询与此类似:
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您之后的范围.