为什么MAX()比ORDER BY慢100倍... LIMIT 1?

时间:2012-10-17 08:39:25

标签: mysql performance query-optimization

我有一个表foo,其中包含({1}},barbaz列,quuxbaz 。该表有大约500k行。

为什么以下查询的速度差异如此之大?查询A需要0.3秒,而查询B需要28秒。

查询A

quux

解释

select baz from foo
    where bar = :bar
    and quux = (select quux from foo where bar = :bar order by quux desc limit 1)

查询B

id  select_type table   type    possible_keys   key     key_len ref     rows    Extra
1   PRIMARY     foo     ref     quuxIdx         quuxIdx 9       const   2       "Using where"
2   SUBQUERY    foo     index   NULL            quuxIdx 9       NULL    1       "Using where"

解释

select baz from foo
    where bar = :bar
    and quux = (select MAX(quux) from foo where bar = :bar)

我使用MySQL 5.1.34。

1 个答案:

答案 0 :(得分:8)

您应该在(bar, quux)上添加索引。

如果没有这个索引,MySQL就无法看到如何有效地执行查询,因此它必须从各种低效的查询计划中进行选择。

在第一个示例中,它扫描quux索引,找到的每一行,在原始表中查找bar的相应值。这需要两倍的时间检查每一行,但幸运的是,具有正确值bar的行接近其扫描的开始,因此它可以停止。这可能是因为你要搜索的bar的价值经常发生,所以幸运的机会非常高。因此,它可能只需要在找到匹配项之前检查少量行,因此即使检查每一行需要两倍的时间,只检查几行的事实会带来大量的整体节省。由于bar上没有索引,MySQL事先并不知道值:bar经常发生,因此无法知道此查询会很快。

在第二个示例中,它使用不同的计划,始终扫描整个表。直接从表中读取每一行,而不使用索引。这意味着每行读取速度很快,但由于您有很多行,因此整体速度很慢。如果:bar上没有匹配的行,则这将是更快的查询计划。但是,如果大约1%的行具有期望的bar值,则与上述计划相比,使用此查询计划将(非常)慢约100倍。由于bar上没有索引,因此MySQL不会事先知道这一点。

您也可以添加缺失的索引,然后两个查询的内容都会更多