不同列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);
相关推荐
XLYcmy6 小时前
信息检索报告数字经济赋能城市低碳治理的路径研究——基于“传统数据库 + 生成式人工智能”双轮驱动的检索实践 检索实施与结果分析 Web of Science
数据库·ai·llm·prompt·ssci·deepseek·wos
Decay__6 小时前
21_MySQL 优化案例集 —— 慢 SQL 优化、索引重构与参数调整收益对比
运维·数据库·sql·mysql·架构
codigger7 小时前
MySQL 深分页优化:limit 100000, 10 慢在哪,怎么救
数据库·sql·mysql·程序员
麦壳饼7 小时前
SonnetDB 5.0 正式发布:增强 SQL 与事务,开放九模型 MCP 读写
数据库·人工智能·sql·sonnetdb
Decay__16 小时前
18_MySQL 智能巡检方案 —— 巡检项清单 / 一键巡检脚本 / 健康评分
运维·数据库·sql·mysql·架构
java_logo16 小时前
Docker 部署 Liquibase:轻松搭建数据库变更管理
数据库·docker·容器·数据库管理·liquibase·轩辕镜像·数据库变更
凤凰院凶涛QAQ18 小时前
《MySQL内核拆解:从SQL到InnoDB》(四) : 联合查询 & 视图
数据库·sql·mysql
码农小河6618 小时前
基于SSM+JSP的高校专业信息管理系统【附源码+数据库】
java·开发语言·数据库
张小姐的猫18 小时前
【MySQL】访问 & 数据流动原理
android·数据库·mysql·adb·1024程序员节