记一次 Oracle 下的 SQL 优化过程
1. 介绍
事情是这样的,UAT 环境的测试小伙伴向我扔来一个小 bug,说是一个放大镜的查询很慢,转几分钟才出数据,我立马上开发环境试了一下,很快啊我说,放大镜的数据立马就出来了,然后我登录 UAT 环境一看,诶是有些慢 ,于是开始了我的排查之旅...
2. 过程
首先我立马拿到了执行的 SQL 在开发环境的数据库执行了下,很快,都在 1s 左右,感觉没啥问题啊,然后我就在页面上点点点,发现好像上面有一个相关联的下拉框,如果选中的有数据,再点击这个放大镜就会慢一点,然后我登录 UAT 环境一试,哦不是这个问题,于是只能开始排查 SQL 了。
百度了一圈 Oracle 性能调优,大多很空泛,没有一个通用的、具体的、可执行的步骤。但是找到了排查前必备的查看执行计划explain plan。
以下是正儿八经的优化过程:
2.1 查看该条 SQL 的执行计划
2.1.1 生成执行计划
在要排查的SQL前面加上explain plan for,例如以下的例子:
explain plan for
SELECT
*
FROM
SOURCE_LISTEX_202101
WHERE
pass_id = '012101200123001025061320201201002852';
2.1.2 查看执行计划
推荐使用该 SQL 去查询执行计划 (为什么?因为简短好记)
select * from table(dbms_xplan.display)
或者
SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE'));
查出来的应该是这个样子:
Plan hash value: 1335523602
-----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 44479 | 38M| 17411 (1)| 00:03:29 |
| 1 | TABLE ACCESS BY INDEX ROWID | SOURCE_LISTEX_202101 | 44479 | 38M| 17411 (1)| 00:03:29 |
|* 2 | INDEX RANGE SCAN | LISTEX_202101_PASS_ID | 17792 | | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("PASS_ID"='012101200123001025061320201201002852')
而且如果你的 SQL 长了之后会发现,Operation 列是会有缩进的,缩进代表层级关系,就很乱,这里我推荐 Datagrip的右键可视化Explain plan。
使用方法为:选中SQL,右键Explain Plan,就可以查看啦,大概长这个样子:
其中点击 Explain Plan (Raw),也是可以的,就是查看原生的执行计划样子,大概长这样:
2.1.3 分析执行计划
在 1.2 节可视化那个图中,我们主要看表格中的 Total Cost, 它代表着该条操作的总消耗,我们根据层级关系逐个排查,找到最为耗时的操作,排查发现此处两个Full Scan 全表扫描的性能消耗占据了全部总消耗的98% ((384+384)/779)
之后根据执行计划的层级关系我们去 SQL 中找到这两个全表扫描对应的部分:

查一下 sett_ebankinstruct 这个表的数量 有近十万条,看了一下表的定义,一个索引都没加。。。
在此次 SQL 中,使用sett_ebankinstruct的字段只有 instructionid 和 instructtype。
instructionid : 很有可能会作为关联条件去连接多个表,并且该字段不会频繁的update,故在该字段上加索引。
如何加索引呢?
create index 索引名称
on 表名 (字段);
在此处加索引的 SQL 为:
create index IDX_SETT_EBANKINSTRUCT_INSTRID
on SETT_EBANKINSTRUCT (INSTRUCTIONID);
instructtype : 考虑到 instructtype 只是类型,并且使用的情况可能就是 = 或者in (具体的几个值),于是就不用加。
我们添加索引之后发现,第一个Full Scan 全表扫描已经消失,因为在 sp.id = se.instructionid 进行表连接的时候走了索引,但是第二个Full Scan全表扫描仍然存在,说明此处并未走索引 :

原因是此处使用 not in ,括号里的instructionId并未走内部子查询的索引,那么怎么改成走索引呢?将其改写成 not exists 即可。

再次查看下执行计划,发现两个全表扫描都消失了,都变成了索引扫描(Index Scan):

对比优化前后Total Cost:
优化前:779
优化后:62
优化提升:92%
3. 结论
如果排查确实是 SQL 问题,就直接看 执行计划 ,重点关注占用Total Cost的部分,然后查看对应的 SQL 。
- 如果是表频繁连接的字段,就要考虑加索引了。
not in改not exists,(业界流传not exists比not in快)
其实非也,如果主查询和子查询表大小相当,那么用in和exists差别不大。
如果子查询表大,用exists快,如果子查询表小,用in快。Where:数据量多的情况下,排除越多记录的条件应该是先执行。
Oracle下能排除掉多的条件放后面,因为Oracle的where是从右往左执行的,格式化 SQL 后也就是从下往上执行,这样写那么会先排除大量的数据,因而加快后续操作的速度。
MySQL正好和Oracle相反,MySQL下的Where是从左往右执行的,格式化 SQL 之后也就是从上往下执行,
因而MySQL下Where的条件应该是排除多的条件放前面。
记一次 Oracle 下的 SQL 优化过程的更多相关文章
- SQL优化过程中常见Oracle HINT
在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...
- oracle中的SQL优化
一.SQL语言的使用1.IN 操作符 用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格. 但是用IN的SQL性能总是比较低的,从ORACLE执行的步骤来分析用 ...
- Oracle ->> Oracle下实现SQL Server的TOP + APPLY
今晚很好奇想知道Oracle下有没有APPLY子句?如果有那怎么实现SQL Server下的TOP + APPLY.结果自己写了个例子. with a as ( order by grp_factor ...
- centos下美团sql优化工具SQLAdvisor的安装
1.克隆代码 cd /usr/local/src/git clone https://github.com/Meituan-Dianping/SQLAdvisor.git 2.安装依赖(ubuntu下 ...
- 记一次Sql优化过程
这几天在写一个存储过程,反复优化了几次,从最开始的7分钟左右,优化到最后的几秒,并且这个过程中我的导师帮我指点了很多问题,这些指点都是非常宝贵的,独乐乐不如众乐乐,一起来分享这次的优化过程吧. 这个存 ...
- 记一次Entity Framework 项目的优化过程
在博客园看了不少其他大神的经验.今天也抽空贡献点自己的经验(并不是说自己也是大神..小弟还只新手程序员去年才毕业的) 好了废话不多说,直接进入主题.(具体的好坏各位看官就随便看看吧..没有什么好坏之分 ...
- oracle存储过程及sql优化-(一)
本篇主要介绍存储过程的结构 先简单介绍下: oracle存储过程与函数不同,oracle函数和存储过程都可以有多个输入,但是函数一般只有一个输出,而oracle可以有多个输出且与输入 ...
- oracle存储过程及sql优化-(三)
接下来介绍上篇接触到的存储过程中的sql语句 insert into TMP_GT3_sbfgl_WJSTJB SELECT NSR.NSRSBH, NSR.NSRMC, NSR.SCJYDZ, ca ...
- oracle存储过程及sql优化-(二)
接下来比较重要,我会先贴出一个存储过程,根据这个存储过程讲解 PROCEDURE AP_CXBB_GT3_SBFGL_SBFYJSQC (OUT_RECORD OUT SYS_REFCURSOR, P ...
- 记一次Oracle冷备恢复的过程
一.故障来临 某日中午,市电意外中断,机房UPS电源由于负载过重而未接管供电,所有服务器全部重启...... 待所有服务器重启后,正在逐一检查设备和业务运行情况时,意外发生了.一台年代久远的HP PC ...
随机推荐
- Linux邮件mail.rc配置,发件服务配置
Linux邮件mail.rc配置 前提条件 邮箱需要开启smtp功能 关闭selinux和防火墙 1. 安装mailx yum install -y mailx 2. 配置/etc/mail.rc ...
- 【读书笔记】组合计数中的行列式方法 专题2 欧拉回路,the BEST theorem
目录 专题2-欧拉回路,the BEST theorem 一些定义 一个有向图是欧拉的充要条件 BEST定理 BSET定理推论 k-ary de Bruijn sequence定义 BSET theo ...
- 【CTF】系统调用号查询表
32位 #ifndef _ASM_X86_UNISTD_32_H #define _ASM_X86_UNISTD_32_H 1 #define __NR_restart_syscall 0 #defi ...
- ChatGPT 与 Midjourney 强强联手,让先秦阿房宫重现辉煌!
Midjourney 是一款非常特殊的 AI 绘画聊天机器人,它并不是软件,也不用安装,而是直接搭载在 Discord 平台之上,所有的功能都是通过调用 Discord 的聊天机器人程序实现的.要想使 ...
- CommunityToolkit.Mvvm8.1 viewmodel源生成器写法(3)
本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址 ...
- 带你揭开神秘的Javascript AST面纱之Babel AST 四件套的使用方法
作者:京东零售 周明亮 写在前面 这里我们初步提到了一些基础概念和应用: 分析器 抽象语法树 AST AST 在 JS 中的用途 AST 的应用实践 有了初步的认识,还有常规的代码改造应用实践,现在我 ...
- IDA 特征码生成和搜索脚本
最近比较忙,就少写两句,直接附上源代码,其中的细节点就不再赘述,如有疑问,请留言. 一共就是实现了两个函数,一个用于搜索特征码 (SearchPattern),一个用于生成特征码 (GenerateF ...
- YII文件上传
<span style="font-size:14px;">use yii\web\UploadedFile; public function actionDoarta ...
- MyBatisPlus解决逻辑删除与唯一索引的兼容问题
需求背景 比如有张用户表,在插入或者更新数据的时候,我们需要 用户名称(username),不能重复. 我们首先考虑的是给该字段创建唯一索引 create unique index uni_usern ...
- 3. 面向对象编程(OOP):
面向对象编程的本质就是:以类的方式组织代码.以对象的组织(封装)数据 抽象:就是把不同的物品的共同点剥离出来,构成一个类.如每个人都有2条腿,我们可以把2条腿剥离出来 构成一个类 类与对象的关系 类: ...