9

我有一个表foo,其中包含(以及其他 20 个)列barbaz并且quux索引在baz和上quux。该表有约 500k 行。

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

查询 A

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

解释

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"

查询 B

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

解释

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     ALL     NULL            NULL    NULL    NULL    448060  "Using where"

我使用 MySQL 5.1.34。

4

1 回答 1

9

您应该在(bar, quux).

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

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

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

您也可以只添加缺少的索引,然后两个查询都会更快

于 2012-10-17T08:44:22.570 回答