我有两个查询加上自己的EXPLAIN
结果:
一:
SELECT *
FROM notifications
WHERE id = 5204 OR seen = 3
基准(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
基准(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
}
}
会更好。如果我使用哪种方法,请你帮助我?
答案 0 :(得分:7)
OR
案例的查询计划似乎表明MySQL
确实正在使用索引,所以显然是,它可以做到,至少在这种情况下。这似乎是完全合理的,因为seen
上有一个索引,而id
是PK。
基于一些合理且合理的解释,使用union更好,但基准测试的结果表明使用OR更好。
如果"逻辑合理的解释"与现实相矛盾的是,可以安全地假设逻辑存在缺陷或解释错误或不适用。众所周知,表现难以预测;在速度很重要的情况下,性能测试至关重要。
如果我使用哪种方法,请你帮助我吗?
您应该在输入上更快地使用测试的那个,以充分模拟程序将在实际使用中看到的那些。
但是,请注意,您的两个查询在语义上并不相同:如果id = 5204
的行也有seen = 3
,那么OR
查询将返回一次,但是{{ 1}}查询将返回两次。在任何基础上选择正确的代码和不正确的代码是没有意义的。
答案 1 :(得分:5)
index_merge
,顾名思义,使用Sort Merge Join
或Sort Merge Union
对AND
和OR
条件合并两个索引的主键,然后通过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自动为您做了正确的优化。情况并非如此。