在sql中,使用union替换or,一定会带来好处,这个是正确的还是错误的说法?

yekeyishuo 2020-05-06 09:03:07
在sql中,使用union替换or,一定会带来好处,这个是正确的还是错误的说法?能否举个例子
...全文
627 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
Rotel-刘志东 2020-05-11
  • 打赏
  • 举报
回复
具体的业务场景下是不同的,不能说union 替代or就一定是好的,这种说法是不对的。
nayi_224 2020-05-07
  • 打赏
  • 举报
回复
引用 7 楼 昵称是可以中文吗 的回复:
@nayi_224,https://blog.csdn.net/z69183787/article/details/86611410 等于号也可以走索引的哦
不同数据库之间执行原理不同,别混着看! oracle中组合索引单查后面的列大概率不走索引。t1.b = 'b55654'已经触发了一次全表扫描,t1.a = 55654是走索引的,但是从整个查询来看,不会改善效率。
卖水果的net 2020-05-06
  • 打赏
  • 举报
回复
这个是正确的还是错误的说法 这个说法过于教条
  • 打赏
  • 举报
回复
@nayi_224,https://blog.csdn.net/z69183787/article/details/86611410 等于号也可以走索引的哦
  • 打赏
  • 举报
回复
引用 5 楼 nayi_224 的回复:
[quote=引用 4 楼 昵称是可以中文吗 的回复:] 单单从代码看,感觉union 是两次查询表,而 or是查询一次表,只是查询条件不同

select * 
  from my_big_table t1 
 where t1.a = 55654
    or t1.b = 'b55654';
 
select * 
  from my_big_table t1 
 where t1.a = 55654
union 
select * 
  from my_big_table t1 
 where t1.b = 'b55654'
讨论效率的时候不能这样看。你应该看这是 table access full 还是index scan。在特定条件下,后者即使查询100遍,也可能比前者快。当然这些都需要分情况讨论。[/quote] 你好,你上面的回答说建立这个联合索引后两个查询都没走索引,但是我在哪里看到过,好像是查询条件是like前端匹配时会走索引的。如果单单是这样查询也不走索引? from my_big_table t1 where t1.a = 55654

create index idx_my_big_table on my_big_table(a, b);
select * 
  from my_big_table t1 
 where t1.a = 55654
union 
select * 
  from my_big_table t1 
 where t1.b = 'b55654'
lhdz_bj 2020-05-06
  • 打赏
  • 举报
回复
这个错误的说法,具体还得看场景,一般来讲,or影响SQL语句走正确的索引时会考虑用union改写SQL,但有时也不是这样的,既然or没问题,为什么还要用union改写呢?
nayi_224 2020-05-06
  • 打赏
  • 举报
回复
引用 4 楼 昵称是可以中文吗 的回复:
单单从代码看,感觉union 是两次查询表,而 or是查询一次表,只是查询条件不同

select * 
  from my_big_table t1 
 where t1.a = 55654
    or t1.b = 'b55654';
 
select * 
  from my_big_table t1 
 where t1.a = 55654
union 
select * 
  from my_big_table t1 
 where t1.b = 'b55654'
讨论效率的时候不能这样看。你应该看这是 table access full 还是index scan。在特定条件下,后者即使查询100遍,也可能比前者快。当然这些都需要分情况讨论。
  • 打赏
  • 举报
回复
引用 3 楼 nayi_224 的回复:
这是个扯淡的说法。说这话的人的本意是or会导致不走索引,改为union可以走索引。但是实际使用的时候会有多种情况。 oracle11g测试
create table my_big_table as select level a, cast('b' || level as varchar2(8)) b from dual connect by level <= 200000;
create index idx_my_big_table on my_big_table(a, b);
下面两个查询是等效的,但是都不会走索引
select * 
  from my_big_table t1 
 where t1.a = 55654
    or t1.b = 'b55654';

select * 
  from my_big_table t1 
 where t1.a = 55654
union 
select * 
  from my_big_table t1 
 where t1.b = 'b55654'
再换一个正确的索引试试
create table my_big_table2 as select level a, cast('b' || level as varchar2(8)) b from dual connect by level <= 200000;
create index idx_my_big_table2_1 on my_big_table2(a);
create index idx_my_big_table2_2 on my_big_table2(b);
又可以看到优化器自作主张给转成了bitmap。 用hint强制修改执行计划 从这个执行计划可以看出确实改成union效率更高,但是优化器会自动帮你做这一步,并且这是根据统计信息做的智能判断,无需手动改成union。 再来一组数据奇葩的
create table my_big_table3 as select mod(level, 2) a, cast('b' || level as varchar2(8)) b from dual connect by level <= 200000;
create index idx_my_big_table3_1 on my_big_table3(a);
create index idx_my_big_table3_2 on my_big_table3(b);
select * from my_big_table3 t1 where t1.a = 1 or t1.b = 'b1235'; 或者说只要带上 t1.a = 1 这个条件,你再怎么折腾它都不会走索引。 再用我刚才工作时写的一个sql举个例子

select *
  from aaa.tab1 t1
 where t1.aaaa_date = '20200504'
   and t1.day_id = substr('20200504', 7, 2)
   and t1.aaaa_no = '01'
   
   and (
   		(#{levelType} = '1') 
   		or (#{levelType} = '2' and #{saleId} = t1.col1) 
   		or (#{levelType} = '3' and #{saleId} = t1.col2)
   )
aaa.tab1表一个分区虽然有40w数据,但是我本来就是要全表查询,为什么要改写?就算我只查几条数据也不会改写,因为这张表上没有索引,如果没有索引,上面所说的全部都会不成立
单单从代码看,感觉union 是两次查询表,而 or是查询一次表,只是查询条件不同

select * 
  from my_big_table t1 
 where t1.a = 55654
    or t1.b = 'b55654';
 
select * 
  from my_big_table t1 
 where t1.a = 55654
union 
select * 
  from my_big_table t1 
 where t1.b = 'b55654'
nayi_224 2020-05-06
  • 打赏
  • 举报
回复
这是个扯淡的说法。说这话的人的本意是or会导致不走索引,改为union可以走索引。但是实际使用的时候会有多种情况。 oracle11g测试
create table my_big_table as select level a, cast('b' || level as varchar2(8)) b from dual connect by level <= 200000;
create index idx_my_big_table on my_big_table(a, b);
下面两个查询是等效的,但是都不会走索引
select * 
  from my_big_table t1 
 where t1.a = 55654
    or t1.b = 'b55654';

select * 
  from my_big_table t1 
 where t1.a = 55654
union 
select * 
  from my_big_table t1 
 where t1.b = 'b55654'
再换一个正确的索引试试
create table my_big_table2 as select level a, cast('b' || level as varchar2(8)) b from dual connect by level <= 200000;
create index idx_my_big_table2_1 on my_big_table2(a);
create index idx_my_big_table2_2 on my_big_table2(b);
又可以看到优化器自作主张给转成了bitmap。 用hint强制修改执行计划 从这个执行计划可以看出确实改成union效率更高,但是优化器会自动帮你做这一步,并且这是根据统计信息做的智能判断,无需手动改成union。 再来一组数据奇葩的
create table my_big_table3 as select mod(level, 2) a, cast('b' || level as varchar2(8)) b from dual connect by level <= 200000;
create index idx_my_big_table3_1 on my_big_table3(a);
create index idx_my_big_table3_2 on my_big_table3(b);
select * from my_big_table3 t1 where t1.a = 1 or t1.b = 'b1235'; 或者说只要带上 t1.a = 1 这个条件,你再怎么折腾它都不会走索引。 再用我刚才工作时写的一个sql举个例子

select *
  from aaa.tab1 t1
 where t1.aaaa_date = '20200504'
   and t1.day_id = substr('20200504', 7, 2)
   and t1.aaaa_no = '01'
   
   and (
   		(#{levelType} = '1') 
   		or (#{levelType} = '2' and #{saleId} = t1.col1) 
   		or (#{levelType} = '3' and #{saleId} = t1.col2)
   )
aaa.tab1表一个分区虽然有40w数据,但是我本来就是要全表查询,为什么要改写?就算我只查几条数据也不会改写,因为这张表上没有索引,如果没有索引,上面所说的全部都会不成立

17,086

社区成员

发帖
与我相关
我的任务
社区描述
Oracle开发相关技术讨论
社区管理员
  • 开发
  • Lucifer三思而后行
  • 卖水果的net
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧