2013-10-18 40 views
0

发生奇怪的事情。任何人都可以请解释。 我有一张桌子。在MySQL中使用索引

CREATE TABLE "country_ip" (
    "begin_ip" varchar(15) NOT NULL, 
    "end_ip" varchar(15) NOT NULL, 
    "begin_ip_long" int(10) unsigned NOT NULL, 
    "end_ip_long" int(10) unsigned NOT NULL, 
    "id" char(2) NOT NULL, 
    "label" varchar(50) NOT NULL, 
    KEY "begin_ip_long" ("begin_ip_long","end_ip_long"), 
    KEY "end_ip_long" ("end_ip_long") 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

约有150 000条记录。 下一查询具有巨大的时间差

0.06329400 | SELECT * FROM `country_ip` WHERE '1405662435' BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1 
0.06214600 | SELECT * FROM `country_ip` USE INDEX (begin_ip_long, end_ip_long) WHERE 1405662435 BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1 
0.00008400 | SELECT * FROM `country_ip` USE INDEX (end_ip_long) WHERE 1405662435 BETWEEN `begin_ip_long` AND `end_ip_long` LIMIT 1 

任何人都可以解释它为什么会发生?我的意思是,为什么只有USE INDEX(end_ip_long)同时使用USE INDEX(begin_ip_long)USE INDEX(begin_ip_long,end_ip_long)没有效果有所帮助。谢谢。

+0

'谁能解释吗?有趣的是,MySQL本身可以“最好地解释”:) –

+0

你需要一个R-Tree(空间)索引。 – eggyal

+0

看起来像InnoDB不支持空间索引。无论如何它不能解释任何东西 – user2893612

回答

1

也许这是因为索引(end_ip_long)小于(begin_ip_long, end_ip_long),它适合内存和一列是足够选择性的。虽然较大的索引可能需要从磁盘读取。

+0

不可以,因为(begin_ip_long)可以快速运行0.00007600 | SELECT * FROM'country_ip' USE INDEX(begin_ip_long)WHERE'begin_ip_long' <= 1405662435 LIMIT 1 – user2893612

+0

这并不意味着什么。 alexius恳求MySQL为什么选择end_ip_long,我认为他是对的。你可以不同意MySQL的优化器,但它仍然遵循它的规则。无论如何,当提问这样的问题时,你应该提供EXPLAIN的输出。 SELECT的时间没有多大意义,对LIMIT 1没有任何意义。 –

1

由于您可以使单列(END_IP_LONG)索引快速运行,为什么不只是在一列上索引&?

我可能会使用BEGIN_IP_LONG并搜索第一个记录,其中指定的IP是> = country.BEGIN_IP_LONG,通过IP降序排列,限制为1.应该检索“floor”条目,然后执行所有操作检查指定的IP是否不超过该国的END_IP_LONG。

这将正确完成查找,只使用单列索引。 (所有这些假设的范围没有重叠,我以为是真的给你规定的结构。)


正如其他人建议,调查MySQL的计划(也许重建统计数据)将是值得的 - 但在技术上,非重叠范围查找在技术上应该是可能的,只使用单个边界上的索引。