【发布时间】:2016-10-10 07:53:56
【问题描述】:
我有两个查询加上它自己的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 更好。请问我应该使用哪种方法?
【问题讨论】:
-
为什么要使用选择(选择联合选择)而不是使用更简单的选择联合选择?您还需要一个 UNION 而不是 UNION ALL 以避免重复
-
虽然我不知道答案——我也发现 OR 语句会影响 MySQL 的性能。通常我会更改一些内容,例如 select a.* from account a join account b on a.member_number = b.member_number 或 a.last_name = b.last_name。 --> 选择 a.* from account a left join account b on a.member_number left join account c on a.last_name = c.last_name where b.account_id is not null or c.account_id is not null;绕过 OR 条件的糟糕表现。我很想知道真正的答案.....
-
如果您可以在第二个示例中删除
SELECT h.* FROM () h并看看它是否有所作为会很好 -
@RolandStarke 说了什么。来自文档:在 MySQL 5.7.6 之前,派生表总是被物化,而等效的视图引用有时被物化,有时被合并。这种对等价查询的不一致处理可能会导致性能问题:不必要的派生表实现需要时间并阻止优化器将条件下推到派生表。
-
@Stack:
UNION或UNION ALL?UNION必须确保结果是唯一的,这就是为什么它可能会抛出另一个临时表。尝试将id <> 5204添加到您的seen查询中,看看UNION ALL的执行情况。