当条件之间存在OR时,MySQL能否使用索引?

时间:2016-06-09 15:05:40

标签: mysql sql

我有两个查询加上自己的EXPLAIN结果:

一:

SELECT * 
FROM notifications 
WHERE id = 5204 OR seen = 3

enter image description here

基准(10,000行):0.861

两个

SELECT h.* FROM ((SELECT n.* from notifications n WHERE id = 5204) 
                    UNION ALL
                 (SELECT n.* from notifications n WHERE seen = 3)) h 

enter image description here

基准(10,000行):2.064

上面两个查询的结果是相同的。我在notifications表上有这两个索引:

notifications(id) -- this is PK
notification(seen)

如您所知,OR通常会阻止有效使用索引,这就是我编写第二个查询(UNION)的原因。但经过一些测试后,我发现使用OR仍然使用UNION的速度要快得多union。所以我很困惑,在我的情况下,我真的无法选择最佳选择。

基于一些合理且合理的解释,使用OR会更好,但基准测试的结果表明使用function sendWithoutTimerFunc() { try { FB.ui({ app_id: '1226220854077249', method: 'send', link: 'https://developers.facebook.com/apps/1226220854077249/roles/test-users/', to: '111526025937966', message: 'Hello test user', data: '...' }); } catch(error) { alert(error); //Will change to console.log() later } } 会更好。如果我使用哪种方法,请你帮助我?

3 个答案:

答案 0 :(得分:7)

OR案例的查询计划似乎表明MySQL确实正在使用索引,所以显然是,它可以做到,至少在这种情况下。这似乎是完全合理的,因为seen上有一个索引,而id是PK。

  

基于一些合理且合理的解释,使用union更好,但基准测试的结果表明使用OR更好。

如果"逻辑合理的解释"与现实相矛盾的是,可以安全地假设逻辑存在缺陷或解释错误或不适用。众所周知,表现难以预测;在速度很重要的情况下,性能测试至关重要。

  

如果我使用哪种方法,请你帮助我吗?

您应该在输入上更快地使用测试的那个,以充分模拟程序将在实际使用中看到的那些。

但是,请注意,您的两个查询在语义上并不相同:如果id = 5204的行也有seen = 3,那么OR查询将返回一次,但是{{ 1}}查询将返回两次。在任何基础上选择正确的代码和不正确的代码是没有意义的。

答案 1 :(得分:5)

index_merge,顾名思义,使用Sort Merge JoinSort Merge UnionANDOR条件合并两个索引的主键,然后通过PK查找表中的其余值。

为了实现这一点,两个索引上的条件应该是每个索引按顺序生成主键(条件是)。

您可以在docs中找到条件的严格定义,但简而言之,您应该使用相等条件过滤索引的所有部分,加上可能<,{{1 PK上的,或=

如果您在>上有索引,则该值应为(col1, col2, col3)(方括号中的部分不是必需的)。

以下条件不起作用:

col1 = :val1 AND col2 = :val2 AND col3 = :val3 [ AND id > :id ]

作为免费副作用,您的输出按col1 = :val1 -- you omit col2 and col3 col1 = :val1 AND col2 = :val2 AND col3 > :val3 -- you can only use equality on key parts 排序。

您可以使用以下方法获得类似的结果:

id

,除了在早期版本的MySQL中,必须实现派生表,这肯定会使查询性能变差,并且SELECT * FROM ( SELECT 5204 id UNION ALL SELECT id FROM mytable WHERE seen = 3 AND id <> 5204 ) q JOIN mytable m ON m.id = q.id 不再对您的结果进行排序。

简而言之,如果您的查询允许id,请选择它。

答案 2 :(得分:3)

答案包含在你的问题中。 OR的EXPLAIN输出显示Using union(PRIMARY, seen) - 这意味着正在使用index_merge优化,并且通过联合两个索引的结果实际执行查询。

所以MySQL在某些情况下可以使用索引,而在这一种情况下也是如此。但index_merge并不总是可用或未被使用,因为索引的统计数据表明它不值得。在这些情况下OR可能比UNION慢很多(或者不是,如果你不确定,你需要经常检查两个版本。)

在你的考试中,你很幸运,并且#34;和MySQL自动为您做了正确的优化。情况并非如此。