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的字段只有 instructionidinstructtype

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 。

  1. 如果是表频繁连接的字段,就要考虑加索引了。
  2. not innot exists,(业界流传 not existsnot in 快)

    其实非也,如果主查询和子查询表大小相当,那么用 inexists 差别不大。

    如果子查询表大,用 exists 快,如果子查询表小,用 in 快。
  3. Where :数据量多的情况下,排除越多记录的条件应该是先执行。

    Oracle 下能排除掉多的条件放后面,因为 Oraclewhere是从右往左执行的,格式化 SQL 后也就是从下往上执行,这样写那么会先排除大量的数据,因而加快后续操作的速度。

    MySQL 正好和 Oracle 相反,MySQL 下的 Where 是从左往右执行的,格式化 SQL 之后也就是从上往下执行,

    因而 MySQLWhere 的条件应该是排除多的条件放前面。

记一次 Oracle 下的 SQL 优化过程的更多相关文章

  1. SQL优化过程中常见Oracle HINT

    在SQL语句优化过程中,我们经常会用到hint,现总结一下在SQL优化过程中常见Oracle HINT的用法: 1. /*+ALL_ROWS*/ 表明对语句块选择基于开销的优化方法,并获得最佳吞吐量, ...

  2. oracle中的SQL优化

    一.SQL语言的使用1.IN 操作符    用IN写出来的SQL的优点是比较容易写及清晰易懂,这比较适合现代软件开发的风格.    但是用IN的SQL性能总是比较低的,从ORACLE执行的步骤来分析用 ...

  3. Oracle ->> Oracle下实现SQL Server的TOP + APPLY

    今晚很好奇想知道Oracle下有没有APPLY子句?如果有那怎么实现SQL Server下的TOP + APPLY.结果自己写了个例子. with a as ( order by grp_factor ...

  4. centos下美团sql优化工具SQLAdvisor的安装

    1.克隆代码 cd /usr/local/src/git clone https://github.com/Meituan-Dianping/SQLAdvisor.git 2.安装依赖(ubuntu下 ...

  5. 记一次Sql优化过程

    这几天在写一个存储过程,反复优化了几次,从最开始的7分钟左右,优化到最后的几秒,并且这个过程中我的导师帮我指点了很多问题,这些指点都是非常宝贵的,独乐乐不如众乐乐,一起来分享这次的优化过程吧. 这个存 ...

  6. 记一次Entity Framework 项目的优化过程

    在博客园看了不少其他大神的经验.今天也抽空贡献点自己的经验(并不是说自己也是大神..小弟还只新手程序员去年才毕业的) 好了废话不多说,直接进入主题.(具体的好坏各位看官就随便看看吧..没有什么好坏之分 ...

  7. oracle存储过程及sql优化-(一)

             本篇主要介绍存储过程的结构 先简单介绍下: oracle存储过程与函数不同,oracle函数和存储过程都可以有多个输入,但是函数一般只有一个输出,而oracle可以有多个输出且与输入 ...

  8. oracle存储过程及sql优化-(三)

    接下来介绍上篇接触到的存储过程中的sql语句 insert into TMP_GT3_sbfgl_WJSTJB SELECT NSR.NSRSBH, NSR.NSRMC, NSR.SCJYDZ, ca ...

  9. oracle存储过程及sql优化-(二)

    接下来比较重要,我会先贴出一个存储过程,根据这个存储过程讲解 PROCEDURE AP_CXBB_GT3_SBFGL_SBFYJSQC (OUT_RECORD OUT SYS_REFCURSOR, P ...

  10. 记一次Oracle冷备恢复的过程

    一.故障来临 某日中午,市电意外中断,机房UPS电源由于负载过重而未接管供电,所有服务器全部重启...... 待所有服务器重启后,正在逐一检查设备和业务运行情况时,意外发生了.一台年代久远的HP PC ...

随机推荐

  1. Linux邮件mail.rc配置,发件服务配置

    Linux邮件mail.rc配置 前提条件 邮箱需要开启smtp功能 关闭selinux和防火墙 1.  安装mailx yum install -y mailx 2.  配置/etc/mail.rc ...

  2. 【读书笔记】组合计数中的行列式方法 专题2 欧拉回路,the BEST theorem

    目录 专题2-欧拉回路,the BEST theorem 一些定义 一个有向图是欧拉的充要条件 BEST定理 BSET定理推论 k-ary de Bruijn sequence定义 BSET theo ...

  3. 【CTF】系统调用号查询表

    32位 #ifndef _ASM_X86_UNISTD_32_H #define _ASM_X86_UNISTD_32_H 1 #define __NR_restart_syscall 0 #defi ...

  4. ChatGPT 与 Midjourney 强强联手,让先秦阿房宫重现辉煌!

    Midjourney 是一款非常特殊的 AI 绘画聊天机器人,它并不是软件,也不用安装,而是直接搭载在 Discord 平台之上,所有的功能都是通过调用 Discord 的聊天机器人程序实现的.要想使 ...

  5. CommunityToolkit.Mvvm8.1 viewmodel源生成器写法(3)

    本系列文章导航 https://www.cnblogs.com/aierong/p/17300066.html https://github.com/aierong/WpfDemo (自我Demo地址 ...

  6. 带你揭开神秘的Javascript AST面纱之Babel AST 四件套的使用方法

    作者:京东零售 周明亮 写在前面 这里我们初步提到了一些基础概念和应用: 分析器 抽象语法树 AST AST 在 JS 中的用途 AST 的应用实践 有了初步的认识,还有常规的代码改造应用实践,现在我 ...

  7. IDA 特征码生成和搜索脚本

    最近比较忙,就少写两句,直接附上源代码,其中的细节点就不再赘述,如有疑问,请留言. 一共就是实现了两个函数,一个用于搜索特征码 (SearchPattern),一个用于生成特征码 (GenerateF ...

  8. YII文件上传

    <span style="font-size:14px;">use yii\web\UploadedFile; public function actionDoarta ...

  9. MyBatisPlus解决逻辑删除与唯一索引的兼容问题

    需求背景 比如有张用户表,在插入或者更新数据的时候,我们需要 用户名称(username),不能重复. 我们首先考虑的是给该字段创建唯一索引 create unique index uni_usern ...

  10. 3. 面向对象编程(OOP):

    面向对象编程的本质就是:以类的方式组织代码.以对象的组织(封装)数据 抽象:就是把不同的物品的共同点剥离出来,构成一个类.如每个人都有2条腿,我们可以把2条腿剥离出来 构成一个类 类与对象的关系 类: ...