mysql SQL性能UNION与OR

envsm3lx  于 2023-11-16  发布在  Mysql
关注(0)|答案(6)|浏览(143)

我刚刚读了一篇优化文章的一部分,并对下面的语句进行了 segfaulted
使用SQL时,使用UNION替换OR语句:

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和某些表模式可能更有性能,但这并不像作者建议的那样绝对正确。

提问

我说错了吗?

8zzbczxx

8zzbczxx1#

要么你读的文章用了一个不好的例子,要么你误解了他们的观点。

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';


假设company上有一个索引,city上有一个单独的索引。假设MySQL通常在给定的查询中每个表只使用一个索引,那么应该使用哪个索引呢?如果它使用company上的索引,它仍然需要进行表扫描来查找city是伦敦的行。它将不得不对其中company是bbc的行进行表扫描。
UNION解决方案适用于这种情况。

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


现在每个子查询都可以使用索引进行搜索,子查询的结果由UNION组合。
一位匿名用户建议对我上面的答案进行编辑,但版主拒绝了编辑。这应该是一个评论,而不是编辑。建议的编辑的声明是UNION必须对结果集进行排序以消除重复行。这使得查询运行得更慢,因此索引优化是一个骗局。
UNION确实需要消除重复项,为了做到这一点,它会对结果集进行排序,因此会有一些开销,但它通常只需要对一个小的结果集进行排序。
在某些情况下,WHERE子句匹配表的很大一部分,在UNION期间进行排序的开销与简单地进行表扫描一样大。但是索引搜索减少结果集的情况更常见,因此对一小部分行进行排序的开销要比对一大部分行进行表扫描的开销小得多。
区别取决于表中的数据,以及搜索的术语。确定给定查询的最佳解决方案的唯一方法是在MySQL查询分析器中尝试两种方法并比较它们的性能。

ubby3x7f

ubby3x7f2#

这不是同一个查询。
我对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’;

3hvapo4f

3hvapo4f3#

这取决于优化器根据数据的大小、索引、软件版本等最终做什么。
我猜想使用OR会给给予优化器一个更好的机会来找到一些效率,因为所有的东西都在一个逻辑语句中。
另外,UNION也有一些开销,因为它创建了一个重置 set(没有重复)。如果 company 被索引,UNION中的每条语句都应该很快执行.

底线

除非你真的有一个迫切的需要,挤压每一点的速度,你的查询,它可能是更好的,只是去与形式,最好的沟通您的意图......或

更新

我还想提一下IN。我相信下面的查询将给予比OR更好的性能(它也是我更喜欢的形式):
第一个月

j1dl9f46

j1dl9f464#

这是我的基准测试结果

使用UNION时-查询花费了13.8699
行检查主要选择类型-247685
当使用OR时-查询花费了0.0126秒,并且行已检查,主要选择类型-495371
MySQL使用一个索引进行查询,所以当我们使用or时,MySQL使用一个列索引并扫描整个表以查找另一列。
另一部分工会同样的工作可以2倍
这就是为什么或快于联盟

3df52oht

3df52oht5#

几乎在所有情况下,unionunion all版本都会对users表进行两次全表扫描。
or版本在实践中要好得多,因为它只会扫描表一次。如果可用,它也只会使用索引一次。
对于任何数据库和任何情况,原始语句似乎都是错误的。

hfwmuf9z

hfwmuf9z6#

Bill Karwin的回答是非常正确的。当OR语句的两个部分都有自己的索引时,最好进行联合,因为一旦你有了一个小的结果子集,就更容易对它们进行排序并消除重复。总成本几乎比只使用一个索引(对于一个列)和对另一列进行表扫描(因为mysql只对一个列使用一个索引)少。
这取决于表的结构和一般需要,但在大表联盟给了我更好的结果。

相关问题