在一个简单但非常大的Innodb表上,我在A列上有一个唯一索引,我希望按(整数)列A的顺序得到(整数)列B的列表
非常简单的查询,我正在翻阅数百万条记录。
SELECT B FROM hugeTable ORDER BY A LIMIT 10000 OFFSET 500000
在非常快的服务器上每次查询需要10秒钟?
Filesort: Yes Filesort_on_disk: Yes Merge_passes: 9
这对我没有意义,为什么不能使用索引A?
说明显示简单,没有可能的键和文件。
答案 0 :(得分:12)
如果列B的值在索引页中不可用,那么MySQL将需要访问基础表中的页面。此外,没有谓词可以过滤正在考虑的行,这意味着MySQL会看到需要返回所有行。这可以解释为什么没有使用索引。
另请注意,LIMIT
操作在语句结束时处理,几乎是执行计划的最后一步,但有一些例外。
8.2.1.3. Optimizing LIMIT Queries 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
我建议您仅对内联视图查询(别名为k)执行EXPLAIN
,并查看它是否显示" Using index
。"
外部查询可能仍然有" Using filesort
"操作,但至少只有10,000行。
(注意:您可能需要在外部查询上尝试使用" ORDER BY i.A
"代替" k.A
"并查看是否有所作为。)
<强>附录强>
没有专门解决您的问题,但就该查询的效果而言,如果这是&#34;翻译&#34;一组行,另一个要考虑的选项,以便到达&#34; next&#34;页面是使用&#34; A
&#34;的值从上一个查询中检索到的最后一行作为&#34;起点&#34;为下一行。
原始查询看起来像第51页&#34; (每页10,000行,第51页将是行510,001到520,000)。
如果您还要返回&#39; A&#39;的值,请将其保留为最后一行。获得&#34; next&#34;页面,查询实际上可能是:
SELECT i.B, k.A
FROM ( SELECT j.A
FROM hugeTable j
WHERE j.A > $value_of_A_from_row_520000
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LIMIT 10000
) k
JOIN hugetable i
ON i.A = k.A
ORDER
BY k.A
如果您还保留了&#34;第一个&#34;行,您可以使用它来备份页面。这实际上只适用于前一页或后一页。跳转到不同的页面,必须使用查询的原始形式,计算行。