mysql:非常简单的SELECT id ORDER BY LIMIT不会按预期使用INDEX(?!)

时间:2013-02-28 20:09:32

标签: mysql sql-order-by indexing

我有一个包含约300万条记录的简单表格。我做了必要的索引,我也强制索引PRIMARY但仍然无法工作。 它搜索几乎所有300万行而不是使用索引来执行这一行(record_id是INT自动增量):

EXPLAIN SELECT record_id
FROM myrecords
FORCE INDEX (
PRIMARY )
ORDER BY record_id ASC
LIMIT 2955900 , 300

id  select_type     table     type  possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE          myrecords index NULL            PRIMARY 4           NULL    2956200 Using index

索引是

Keyname Type    Unique  Packed  Column      Cardinality Collation   Null
PRIMARY BTREE   Yes     No      record_id   2956742     A           No  

我想知道为什么这个FORCED索引没有以正确的方式使用。

在没有强制索引'primary'的情况下尝试了ASC和DESC,结果是一样的。表已经过修复 - 优化分析。没有运气。

查询需要一分钟才能执行!

我期望的是:查询应该只处理300行,因为该列已编入索引。你可以在第一个代码格式的块中看到它们几乎不是所有300万个(向右滚动一点)

1 个答案:

答案 0 :(得分:4)

索引查找是,而不是位置。索引可以搜索值2955900,但您不是要求它。您要求查询从表中第2955900行的偏移量开始。

优化器不能假设所有主键值都是连续的。因此,第2955900行的值很可能远高于此值。

即使主键值是连续的,您也可能具有WHERE条件,该条件仅匹配例如45%的行。在这种情况下,第2955900行的id值将 way 超过id值2955900.

换句话说,id值2955900的索引查找将不会传递第2955900行。

因此MySQL不能将索引用于限制的偏移量。它必须扫描行以计算它们,直到达到偏移+限制行。

MySQL确实有optimizations related to LIMIT,但它更多的是在达到要返回的行数后停止表扫描。优化器仍然可以在EXPLAIN计划中报告它希望可能必须扫描整个表。

FORCE INDEX的经常误解是它强制使用索引。 :-) 实际上,如果查询不能使用索引(或者如果可用索引对此查询没有任何好处),则FORCE INDEX无效。


重新评论:

分页是数据驱动的Web应用程序的常见祸害。尽管此功能有多么常见,但优化并不容易。以下是一些提示:

  • 你为什么要用偏移量2955900查询?你真的希望用户筛选那么多页吗?大多数用户在几页后放弃(具体取决于应用程序类型和数据的数量)。

  • 减少查询次数。您的分页功能可以获取前5-10页,即使它只向用户显示第一页。缓存其他页面,假设用户将前进几页。只有当它们超过缓存的页面集时,您的应用才能进行另一个查询。您甚至可以在客户端的浏览器上缓存Javascript中的所有10个页面,因此单击“下一步”即时(至少对于前几页)。

  • 不要在任何用户界面上放置“上一个”按钮,因为人们会出于好奇而点击它。请注意,Google有一个“下一步”按钮,但没有“最后一个”按钮。因此,UI本身不鼓励人们以高偏移量运行效率低下的查询。

  • 如果用户一次前进一页,请使用下一页查询的WHERE子句中上一页中返回的最高id值。即以下 使用索引,即使没有FORCE INDEX提示:

    SELECT * FROM thistable WHERE id > 544 LIMIT 20