如果 B 列的值在索引页中不可用,则 MySQL 将需要访问基础表中的页。也没有谓词过滤正在考虑的行,这意味着 MySQL 看到需要返回所有行。这可以解释为什么没有使用索引。
另请注意,LIMIT
操作在语句末尾处理,几乎是执行计划的最后一步,但有一些例外。
8.2.1.3。优化 LIMIT 查询http://dev.mysql.com/doc/refman/5.5/en/limit-optimization.html
我怀疑您的查询可以使用覆盖索引,例如“ ON hugetable (A,B)
”,以避免排序操作。
如果没有覆盖索引,您可以尝试像这样重写查询,看看这是否会利用 A 列上的索引,并避免对数百万行进行排序操作(按顺序返回前 510,000 行):
SELECT i.B
FROM ( SELECT j.A
FROM hugeTable j
ORDER
BY j.A
LIMIT 10000 OFFSET 500000
) k
JOIN hugetable i
ON i.A = k.A
ORDER
BY k.A
我建议您EXPLAIN
只对内联视图查询(别名为 k)执行一次,看看它是否显示“ Using index
.”。
外部查询可能仍然有一个 " Using filesort
" 操作,但至少只有 10,000 行。
(注意:您可能想在外部查询中尝试用“ ORDER BY i.A
”代替“ k.A
”,看看是否有区别。)
附录
A
没有专门解决您的问题,但就该查询的性能而言,如果这是“分页”一组行,另一个要考虑的选项是使用“ ”的值来进入“下一页”在上一个查询中检索到的最后一行作为下一行的“起点”。
原始查询看起来像是在获取“第 51 页”(每页 10,000 行,第 51 页将是第 510,001 到 520,000 行)。
如果您还要返回“A”的值,并将其保留在最后一行。要获得“下一页”,查询实际上可以是:
SELECT i.B, k.A
FROM ( SELECT j.A
FROM hugeTable j
WHERE j.A > $value_of_A_from_row_520000
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ORDER BY j.A ASC
LIMIT 10000
) k
JOIN hugetable i
ON i.A = k.A
ORDER
BY k.A
如果您还保留了“第一”行中 A 的值,则可以使用它来备份页面。这实际上只适用于前进一页或后退一页。跳转到不同的页面,将不得不使用查询的原始形式,计算行数。