75

我刚刚阅读了一篇优化文章的一部分,并以下语句中出现了段错误:

使用ORwith a使用 SQL 替换语句时UNION

select username from users where company = ‘bbc’ or company = ‘itv’;

到:

select username from users where company = ‘bbc’ union
select username from users where company = ‘itv’;

从快速EXPLAIN

使用OR

在此处输入图像描述

使用UNION

在此处输入图像描述

UNION这不是意味着加倍工作吗?

虽然我很欣赏UNION某些 RDBMS 和某些表模式的性能可能更高,但这并不像作者建议的那样绝对正确。

问题

我错了吗?

4

5 回答 5

131

您阅读的文章使用了一个不好的例子,或者您误解了他们的观点。

select username from users where company = 'bbc' or company = 'itv';

这相当于:

select username from users where company IN ('bbc', 'itv');

MySQL 可以对此查询使用索引company。没有必要做任何 UNION。

更棘手的情况是您的OR条件涉及两个不同的列。

select username from users where company = 'bbc' or city = 'London';

假设有一个索引 oncompany和一个单独的索引 on city。鉴于 MySQL 通常在给定查询中每个表只使用一个索引,它应该使用哪个索引?如果它使用 上的索引company,它仍然需要进行表扫描以查找city伦敦所在的行。如果它使用 上的索引city,则必须对companybbc 所在的行进行表扫描。

UNION解决方案是针对这种情况的。

select username from users where company = 'bbc' 
union
select username from users where city = 'London';

现在每个子查询都可以使用索引进行搜索,子查询的结果由UNION.


一位匿名用户提议对我上面的答案进行编辑,但版主拒绝了该编辑。它应该是评论,而不是编辑。提议的编辑声称 UNION 必须对结果集进行排序以消除重复行。这使查询运行速度变慢,因此索引优化是一种清洗。

我的回答是索引有助于在 UNION 发生之前将结果集减少到少数行。UNION 实际上确实消除了重复,但要做到这一点,它只需要对小的结果集进行排序。可能存在 WHERE 子句匹配表的重要部分的情况,并且在 UNION 期间进行排序与​​简单地进行表扫描一样昂贵。但更常见的是通过索引搜索减少结果集,因此排序比表扫描成本低得多。

差异取决于表中的数据以及正在搜索的术语。确定给定查询的最佳解决方案的唯一方法是在MySQL 查询分析器中尝试这两种方法并比较它们的性能。

于 2012-12-13T18:35:40.000 回答
5

这些不是同一个查询。

我对 MySQL 没有太多经验,所以我不确定查询优化器做什么或不做什么,但这是我的一般背景(主要是 ms sql server)的想法。

通常,查询分析器可以采用上述两个查询并从中制定完全相同的计划(如果它们相同),因此没关系。我怀疑这些查询之间没有性能差异(它们是等效的)

select distinct username from users where company = ‘bbc’ or company = ‘itv’;

select username from users where company = ‘bbc’ 
union
select username from users where company = ‘itv’;

现在,问题是,以下查询之间是否存在差异,我实际上不知道,但我怀疑优化器会使它更像第一个查询

select username from users where company = ‘bbc’ or company = ‘itv’;

select username from users where company = ‘bbc’ 
union all
select username from users where company = ‘itv’;
于 2012-12-06T19:07:19.260 回答
2

这取决于优化器根据数据大小、索引、软件版本等最终会做什么。

我猜想使用 OR 会给优化器一个更好的机会来找到一些效率,因为一切都在一个单一的逻辑语句中。

此外,UNION 有一些开销,因为它创建了一个重置​​集(没有重复)。如果公司被索引,则 UNION 中的每个语句都应该很快执行......不确定它是否真的会做双倍的工作。

底线

除非您真的迫切需要从查询中挤出所有速度,否则最好使用最能传达您意图的表单...... OR

更新

我还想说 IN。我相信以下查询将提供比 OR 更好的性能(这也是我更喜欢的形式):

select username from users where company in ('bbc', 'itv');

于 2012-12-06T19:07:25.140 回答
-1

在几乎所有情况下,unionorunion all版本都会对 users 表进行两次全表扫描。

or版本在实践中要好得多,因为它只会扫描表一次。如果可用,它还将只使用一次索引。

对于几乎任何数据库和任何情况,原始陈述似乎都是错误的。

于 2012-12-06T21:38:52.313 回答
-1

比尔·卡尔文的回答非常正确。当 OR 语句的两个部分都有自己的索引时,最好进行联合,因为一旦您有一小部分结果,就更容易对它们进行排序并消除重复项。总成本几乎低于只使用一个索引(对于其中一列)和对另一列进行表扫描(因为 mysql 只对一列使用一个索引)。

这通常取决于表的结构和需求,但在大型表中,联合给了我更好的结果。

于 2015-03-26T15:29:55.610 回答