【Oracle】也来记一次慢SQL的优化

本文创意来自:微信公众号“占小狼的博客”21年9月13日博文 “SQL要快:记一次慢SQL优化”

下文将用到的表:

复制代码
create table transfer(
id int,
from_account_id nvarchar2(20),
to_account_id nvarchar2(20),
amount int,
free int,
status int,
comments nvarchar2(20),
create_time timestamp default sysdate,
update_time timestamp default sysdate,
primary key(id));
复制代码

给表填充两百万测试数据:

复制代码
insert into transfer(id,from_account_id,to_account_id,amount,status,comments)
select rownum,
       dbms_random.string('*',dbms_random.value(6,20)),
       dbms_random.string('*',dbms_random.value(6,20)),
       dbms_random.value(1,91000),
       dbms_random.value(1,12),
       dbms_random.string('*',dbms_random.value(6,20))
from dual
connect by level<2000001;
复制代码

然后先找点数据出来下面查询要用:

复制代码
SQL>  select status,to_account_id from transfer where rownum<10;

    STATUS TO_ACCOUNT_ID
---------- ----------------------------------------
         7 YWSRBVSVWUVKUNZRFNHE
         7 IQNFNHLHQ
         5 QBXOPTUDODVILMSCC
         3 OQZDUIJ
         6 SZSAGORE
         4 UKFCUVCHULUKEQODLP
         2 YAAFOMVO
        10 UQHSEHGAUTNJBINHB
        10 XRXJMDYP

已选择9行。
复制代码

首先把原作者要优化的目标SQL拿出来跑一遍,现在是没有索引(除了主键索引)的情况。

无index查询
select id,from_account_id,to_account_id,amount,status,comments,create_time,update_time
from transfer
where status=10 and to_account_id='XRXJMDYP' and rownum<1500
order by amount desc,create_time asc

已用时间:  00: 00: 01.99

接近两秒,有点长,这还是Oracle数据库,换MySQL会更长。

现在打算给查询字段status,to_account_id和排序字段amount,create_time加联合索引,因为status的范围是1-12,按上面的筛法,取status=10的数据,那么无论其它条件如何选中的数据必然小于20%(1/12<0.2),那么加上的索引一定会用上的,不会出现所选数据大于两成而导致全表查询的情况发生。

 create index idx_tf_4 on transfer(status,to_account_id,amount,create_time);
 已用时间:  00: 00: 15.36

加索引花的时间不少。

再查一次看优化了多少:

有index查询
select id,from_account_id,to_account_id,amount,status,comments,create_time,update_time
from transfer
where status=7 and to_account_id='YWSRBVSVWUVKUNZRFNHE' and rownum<1500
order by amount desc,create_time asc
 已用时间:  00: 00: 00.06

已经是秒出,看来索引确实奏效了。

让我们再把索引删除。

drop index idx_tf_4;

删除这个索引是因为不想让它影响下面的新查询效果。

 

先筛选后连接,先筛选后排序是基本的优化SQL思想,按这个思想我们可以把符合的记录找出再排序。

select id,from_account_id,to_account_id,amount,status,comments,create_time,update_time
from transfer where id in (select id from transfer where status=10 and to_account_id='XRXJMDYP' and rownum<1500 )
order by amount desc,create_time asc

已用时间:  00: 00: 00.43

看,没加索引,只是用了id身上的固有索引,查询结果就是秒出,从此可以看出“先筛选后连接,先筛选后排序”的有效性。

前文说过Oracle CBO的强大,但CBO毕竟是机器,写出节省时间的SQL还需要人的积极参与。

现在秒出,再加个索引试试:

create index idx_tf_2 on transfer(status,to_account_id);
已用时间:  00: 00: 05.86

花的时间比四字段索引少三分之二,加完此索引后再查一次:

select id,from_account_id,to_account_id,amount,status,comments,create_time,update_time
from transfer where id in (select id from transfer where status=5 and to_account_id='QBXOPTUDODVILMSCC' and rownum<1500 )
order by amount desc,create_time asc
已用时间:  00: 00: 00.17

加索引确实有效果。

删除此索引把前面的索引加上:

复制代码
SQL> drop index idx_tf_2;

索引已删除。

已用时间:  00: 00: 00.06
SQL> create index idx_tf_4 on transfer(status,to_account_id,amount,create_time);

索引已创建。

已用时间:  00: 00: 09.87
复制代码

再看查询效果:

select id,from_account_id,to_account_id,amount,status,comments,create_time,update_time
from transfer where id in (select id from transfer where status=6 and to_account_id='SZSAGORE' and rownum<1500 )
order by amount desc,create_time asc
已用时间:  00: 00: 00.17

和加两字段索引差不多,这是因为idx_tf_2里的两字段也出现在了idx_tf_4中。

但是,加索引对插入更新的效果是负面的,换了SQL写法后已经是秒出,未必有再优化的必要,加了索引也只是在查询上锦上添花,插入更新是有损的,因此就本例来说,换新的先筛选后排序的SQL是最优解。

-END-

 

posted @   逆火狂飙  阅读(444)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2017-09-13 【高中数学/不等式/数学归纳法/等比数列】证明伯努利不等式(1+h)^n>1+nh的三种方式
2017-09-13 【高中数学/等比数列/基本不等式】已知正项等比数列{an}满足a_4^2=a_m*a_n,则9/m+1/n的最小值为?
2017-09-13 【高中数学/等比中项/极值/基本不等式】已知a>0,b>0,9是3^a与27^b的等比中项,求:(a^2+2)/a+(3b^2+1)/b的最小值?
2017-09-13 【高中数学/极值/三角函数】已知x,y>0,那么根号下x+根号下y/根号下(x+y)的最大值为?
2017-09-13 【高中数学/极值/基本不等式】已知正实数x,y满足xy+2x+3y=42 则xy+5x+4y的最小值为?
2017-09-13 【高中数学/三角函数/数形结合】求f(θ)=|(3+2sinθ)/cosθ| 的最小值
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示