我有一个表foo
,其中包含({1}},bar
和baz
列,quux
和baz
。该表有大约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。
答案 0 :(得分:8)
您应该在(bar, quux)
上添加索引。
如果没有这个索引,MySQL就无法看到如何有效地执行查询,因此它必须从各种低效的查询计划中进行选择。
在第一个示例中,它扫描quux
索引,找到的每一行,在原始表中查找bar
的相应值。这需要两倍的时间检查每一行,但幸运的是,具有正确值bar
的行接近其扫描的开始,因此它可以停止。这可能是因为你要搜索的bar
的价值经常发生,所以幸运的机会非常高。因此,它可能只需要在找到匹配项之前检查少量行,因此即使检查每一行需要两倍的时间,只检查几行的事实会带来大量的整体节省。由于bar
上没有索引,MySQL事先并不知道值:bar
经常发生,因此无法知道此查询会很快。
在第二个示例中,它使用不同的计划,始终扫描整个表。直接从表中读取每一行,而不使用索引。这意味着每行读取速度很快,但由于您有很多行,因此整体速度很慢。如果:bar
上没有匹配的行,则这将是更快的查询计划。但是,如果大约1%的行具有期望的bar
值,则与上述计划相比,使用此查询计划将(非常)慢约100倍。由于bar
上没有索引,因此MySQL不会事先知道这一点。
您也可以添加缺失的索引,然后两个查询的内容都会更多。