0

奇怪的事情发生了。谁能解释一下。我有一张桌子。

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) 没有效果。谢谢。

4

2 回答 2

1

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

于 2013-10-18T07:49:11.167 回答
1

既然您可以让单列 (END_IP_LONG) 索引快速工作,为什么不只对一列进行索引和搜索呢?

我可能会使用 BEGIN_IP_LONG 并搜索指定 IP 为 >= country.BEGIN_IP_LONG 的第一条记录,按 IP 降序排列,限制为 1。这应该检索“地板”条目,然后您需要做的就是检查指定的IP 不超出该国家/地区的 END_IP_LONG。

这将仅使用单列索引正确完成查找。(所有这些都假设范围不重叠,鉴于您所述的结构,我认为这是正确的。)


正如其他人所建议的那样,调查 MySQL 的计划(也许还有重建统计数据)是值得的——但从技术上讲,非重叠范围查找在技术上应该可以使用仅在单个边界上的索引。

于 2013-10-18T08:01:07.287 回答