我有这样的疑问:
SELECT `country`
FROM `geoip_base`
WHERE 1840344811 BETWEEN `start` AND `stop`
索引的使用很糟糕(使用,但是解析表的大部分),而且运行太慢。我试过使用ORDERBY和LIMIT,但是没有帮助。
“启动〈= 1840344811和1840344811〈=停止”的工作原理与此类似。
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;
表具有57,424行。
查询“......按起始限值1在起始和停止顺序之间”的解释:使用键stop
并得到24099行。没有顺序和限制,mysql不使用键并得到所有行。
5条答案
按热度按时间huus2vyu1#
如果您的表是
MyISAM
,则可以使用SPATIAL
索引改进此查询:您可能会对本文感兴趣:
或者,如果您的范围不相交(从数据库的性质来看,除非它们不相交),您可以在
geoip_base.start
上创建一个UNIQUE
索引,并使用以下查询:注意
ORDER BY
和LIMIT
条件,它们很重要。此查询类似于:
使用
ORDER BY / LIMIT
使查询选择在start
上进行降序索引扫描,这将在第一个匹配项上停止(即在start
与您输入的IP
最接近的范围上)。停止时的附加过滤器将只检查范围是否包含此IP
。由于您的范围不相交,因此该范围或根本没有范围将包含您要查找的
IP
。798qvoo82#
而Quassnoi的答案https://stackoverflow.com/a/5744860/1095353是完美的。MySQL函数(5.7)**MBRContains(g1,g2)在使用select时并不适合IP的全部范围。MBRContains将包含[g1,g2[不包括g2。
使用MBRTouches(g1,g2)**可以同时匹配[g1,g2]。在数据库中写入IP块作为开始列和停止列将使此函数更可行。
在具有约6 m行的数据库表(AWS db.m4.xlarge)上
约2-5秒
~〈0.030秒
资料来源:MBRTouches(g1、g2)-https://dev.mysql.com/doc/refman/5.7/en/spatial-relation-functions-mbr.html#function_mbrtouches
7gyucuyw3#
你的table设计错了。
你使用了decimal但不允许任何零,你立即花费5字节来存储这样一个数字,简单的INT就足够了(4字节)。
然后,创建复合主键(5 + 5字节),后跟2个唯一约束(每个约束5字节),有效地使索引文件与数据文件大小几乎相同,这样,无论索引什么都是极其低效的。
使用LIMIT并不强制MySQL使用索引,至少不会像构造查询那样,MySQL将获得满足条件的数据集,然后丢弃不符合offset - limit的行。
此外,使用MySQL的受保护关键字(如START和STOP)是一个坏主意,您应该 * 永远 * 使用受保护的关键字命名您的列。
有用的是你可以直接创建主键,而不用单独索引列,另外,配置MySQL使用更多的内存可以加快执行速度。
出于测试目的,我创建了一个与您的表类似的表,定义了一个
start
和stop
的复合键,并使用了以下查询:我的表是InnoDB类型的,我插入了100 k行,查询以这种方式检查87行,并在几毫秒内执行,我的缓冲池大小是测试机器内存的90%。
pgx2nnw84#
从地理数据中选择标识符,其中起始IP〈=(选择初始化ATON('113.0.1.63'))且结束IP〉=(选择初始化ATON('113.0.1.63'))按起始IP排序描述限制1;
kgsdhlau5#
Michael J.V.的上述示例不起作用:从表中选择
country
,其中start
和stop
之间为1500,并且开始〉= 1500开始和停止之间与开始〈= 1500和结束〉= 1500相同
因此,在同一个子句中,start〈= 1500 AND start〉= 1500,所以,只有start=1500,优化器才知道要使用start索引,这样才能成功。