不同列or运算优化经验

1、 问题

项目中对于以下这种语句写法比较常见

bash 复制代码
select count(1) from test1 where c1 in ('A1','A2','A3')
and (pcode!='03' or status in (1,2) );

计划:

or条件是来自两个不同的列,此时受到optimizer_or_nbexp参数规则影响,做成union_for_or2计划,即拆分扫描两次合并结果集,我们可以看到union 两部分都是索引扫描,用的是c1列的索引,那么or条件合并一起做,肯定比分开快一倍。所以我们可以考虑调整optimizer_or_nbexp参数合并来优化。

bash 复制代码
select /*+OPTIMIZER_OR_NBEXP(2)*/count(1) from test1 where c1 in ('A1','A2','A3')
and (pcode!='03' or status in (1,2) );

计划:

这里索引扫描就一次,达到优化效果。这种计划也可以通过case when写法来实现,即将or条件放入case when作为查询项后,最终作为查询条件去过滤。

2、改写

bash 复制代码
select count(1) from (
select *,case when pcode!='03' or status in (1,2) then 1 else 0 end as flag
from test1 where c1 in ('A1','A2','A3')
) tt where tt.flag=1;

计划:

计划和结果都符合预期。

3、小结

像这种写法优化,是从减少扫描次数去考虑。不同列的or运算可以考虑用case when去合并优化。

4、测试数据

bash 复制代码
create table test1(id varchar2(36) primary key,c1 varchar2(20),c2 varchar2(20),c3 varchar2(20),pcode varchar2(20),status int);
insert into test1 select sys_guid(),
'A'||to_char(round(dbms_random.value(1,100),0)),
'B'||to_char(round(dbms_random.value(1,1000),0)),
'C'||to_char(round(dbms_random.value(1,1000),0)),
'0'||to_char(round(dbms_random.value(1,9),0)),
round(dbms_random.value(1,5),0)
from dual connect by level<=800000;
commit;
create index IDX_DM_TEST1_C1 on test1(c1);
dbms_stats.gather_table_stats(USER,'TEST1',null,100);
相关推荐
这个DBA有点耶4 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
DBA_G4 天前
从地面到云霄:GBase数据库在民航三大场景的落地实践
数据库
自由能燃气设备4 天前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南
大数据·数据库·人工智能
科创致远4 天前
科创致远 ESOP 系统核心效能与实战价值展示
大数据·数据库·人工智能·精益工程
2601_962218614 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法
张洛闻Eren4 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
于平安4 天前
MySQL-触发器
数据库·mysql
白远山4 天前
上海24小时自助健身房解决方案实战指南与经验分享
java·数据库·架构·需求分析
Omics Pro4 天前
斯坦福Nature+Science|广义虚拟细胞基础大模型
数据库·人工智能·算法·机器学习·自然语言处理
2603_965148114 天前
AI+API选品:下一代智能商务助手雏形已现
java·大数据·数据库·人工智能·数据挖掘