(Oracle)SQL优化案例:隐式转换优化

项目场景

项目现场的某个kettle模型执行非常缓慢,原因在于某个SQL执行效率非常的低。甲方得知此事要求公司赶紧优化,负责该模块的同事对SQL优化并不熟悉。所以作为一个立志成为优秀DBA的ETL工程师,我自告奋勇:不是DBA,就不能搞SQL优化了吗?

查询效率慢的SQL格式如下,因为涉及到项目隐私,所以对表名、字段名做了匿名化处理。

SELECT
INFO.ID,
INFO.NAME,
INFO.AGE,
INFO.SEX,
MP.ADDR,
MP.PHONE
FROM INFORMATION INFO
LEFT JOIN MP ON MP.ID = INFO.ID
WHERE INFO.ID = 1234567

很简单的一个SQL。每次查询都是按照 INFO.ID = xxx 这个条件进行查询,每次只会返回1行数据。且关联字段 MP.ID 与 INFO.ID 都有索引,没有大字段。但每次执行查询,大概都要耗时2s左右;不要觉得这个耗时很短,因为有大量的数据需要查询出来进行同步,这个速度就不可被接受了。 

两张表的数据量如下

SELECT COUNT(*) FROM INFORMATION --3667874
SELECT COUNT(*) FROM MP --2125263

问题分析

以下是上述SQL格式的执行计划,是项目上真实SQL的执行计划。我已经将对此次优化的无关执行计划信息删除,只保留了执行计划和谓词信息;且将涉及项目隐私部分的表名字段名改写

Plan hash value: 3295416379-------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                   | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                        |      1 |        |       | 29513 (100)|          |      1 |00:00:01.20 |     108K|
|   1 |  NESTED LOOPS OUTER          |                        |      1 |      1 |   115 | 29513   (1)| 00:00:02 |      1 |00:00:01.20 |     108K|
|   2 |   TABLE ACCESS BY INDEX ROWID| INFORMATION            |      1 |      1 |    98 |     3   (0)| 00:00:01 |      1 |00:00:00.01 |       4 |
|*  3 |    INDEX UNIQUE SCAN         | UK_20230901211918_5341 |      1 |      1 |       |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |
|*  4 |   TABLE ACCESS FULL          | MP                     |      1 |      1 |    17 | 29510   (1)| 00:00:02 |      1 |00:00:01.20 |     108K|
-------------------------------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------3 - access("A"."ID"=1234567)4 - filter((TO_NUMBER("MP"."ID")=1234567 AND "A"."ID"=TO_NUMBER("MP"."ID")))

通过执行计划我们可以分析出:

  • 连接方式 (执行计划:Id=1)

MP表和INFO表的连接方式是 NESTED LOOPS OUTER;因为此查询返回数据量少,每次执行只会返回1行数据,所以走嵌套循环连接是正确的。

  • 访问路径 (执行计划:Id=2)

INFO.ID=1234567 这个谓词过滤是走了索引ROWID扫描的;返回数据量少,走索引,也是正确的。

  • 访问路径(执行计划:Id=4) 

对MP表的访问路径是TABLE ACCESS FULL(全表扫描)。这个就有问题了,MP表有上百万条数据,走全表扫描肯定是低效的、错误的。MP表上的ID字段是有索引的,为什么没有走索引呢?我们继续往下看。

  • 谓词信息 

从谓词信息我们可以看到MP表在进行谓词过滤时,将MP表的ID字段从varchar类型的值通过to_number()转换成了number类型;因为使用了to_number()函数,索引索引失效。此转换属于是Oracle在比对不同数据类型的字段或者表达式时,自动发生的隐式转换;隐式转换的目的肯定是好的,但是在此处对SQL查询效率影响可太大了。

那么对于这个SQL优化而言,需要做的其实就是消除隐式转换带来的影响。那怎么消除嘞?大家继续看下面的SQL改写。

我不晓得会不会有朋友疑问,为什么发生隐式转换的是MP.ID 而不是 INFOMATION.ID。

我在这里多解释一句:

可以从执行计划中看出来,

距离NESTED LOOPS OUTER这个连接方式关键字下方最近的一张表就是驱动表。

这也就意味着,驱动表INFOMATION传一个number类型的数据给MP表,那么MP表必须对自己的字段进行转换才可以进行等值匹配。

SQL改写 

 

这是改写后的SQL,现在查询只需要0.05左右,速度提高了几十倍。完全可以满足ETL要求了。

SELECT
INFO2.ID,
INFO2.NAME,
INFO2.AGE,
INFO2.SEX,
MP.ADDR,
MP.PHONE
FROM (SELECT CAST(INFO.ID AS VARCHAR2(10) AS ID,INFO.NAME,INFO.AGE,INFO.SEX FROM INFORMATION INFO WHERE INFO.ID = 1234567) INFO2
LEFT JOIN MP ON MP.ID = INFO2.ID

 该SQL的执行计划如下,同样的,为了隐私表名和字段名我做了匿名化处理。

Plan hash value: 3589640507---------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                           | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
---------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                                |      1 |        |       |     9 (100)|          |      1 |00:00:00.01 |       8 |
|   1 |  NESTED LOOPS OUTER          |                                |      1 |      1 |   119 |     5   (0)| 00:00:01 |      1 |00:00:00.01 |       8 |
|   2 |   TABLE ACCESS BY INDEX ROWID| INFORMATION                    |      1 |      1 |    98 |     3   (0)| 00:00:01 |      1 |00:00:00.01 |       4 |
|*  3 |    INDEX UNIQUE SCAN         | UK_20230901211918_5341         |      1 |      1 |       |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |
|   4 |   TABLE ACCESS BY INDEX ROWID| MP                             |      1 |      1 |    21 |     2   (0)| 00:00:01 |      1 |00:00:00.01 |       4 |
|*  5 |    INDEX UNIQUE SCAN         | UK_20230901210612_192177       |      1 |      1 |       |     1   (0)| 00:00:01 |      1 |00:00:00.01 |       3 |
---------------------------------------------------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------3 - access("INFO"."ID"=1234567)5 - access("MP"."PID"=CAST("INFO"."ID" AS VARCHAR2(20)))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/815428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ES6 关于Class类的继承 extends(2024-04-10)

1、简介 类Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。extends 的写法比 ES5 的原型链继承,要清晰和方便很多。 class Foo {constructor(x, y) {this.x x;this.y y;console.log(父类构造函数)}toString() {return ( this.x …

《由浅入深学习SAP财务》:第2章 总账模块 - 2.7 总账模块报表 -2.7.1 对外报表:资产负债表及利润表

总账模块报表既包括对外报告的资产负债表、损益表、现金流量表,也包括企业自身用于查询和分析的各类报表,如科目余额表等。 2.7.1 对外报表:资产负债表及利润表 在SAP中,出具资产负债表和利润表的标准方法是先在后台建立一套“会…

971: 统计利用先序遍历创建的二叉树的深度

解法&#xff1a; 1.先序遍历创建二叉树链表形式 2.求二叉树的深度 用后序遍历实现&#xff1a; 1.后序遍历求节点A左右子树高度 2.对节点A&#xff1a; 1.取左右子树较大高度 2.返回高度1&#xff08;即以节点A为根节点的子树的最大深度&#xff09; 例如 #include <ios…

LINUX命令行后台运行matlab程序

UBUNTU安装了matlab&#xff0c;需要后台运行matlab程序。 一、MobaXterm程序&#xff08;非后台&#xff09; 使用mobaxterm程序&#xff0c;ssh连接ubuntu&#xff0c;在对应账号中输入matlab&#xff0c;即可基于mobaxterm自带的Xserver可视化界面&#xff0c;打开matlab界…

RobotFramework功能自动化测试框架基础篇

概念 RobotFramework是什么&#xff1f; Robot Framework是一款python编写的功能自动化测试框架。具备良好的可扩展性&#xff0c;支持关键字驱动&#xff0c;可以同时测试多种类型的客户端或者接口&#xff0c;可以进行分布式测试执行。主要用于轮次很多的验收测试和验收测试…

网页的基本结构

VScode中HTML的自动补全&#xff1a; 自动补全&#xff1a;例如标签 <h1></h1> 1.输入<h1>后其会自动给其补全 2. 进输入h1 tab键 网页的基本结构&#xff1a; 网页的基本结构只需要在VScode当中输入&#xff1a;&#xff01; tab键即可 <!DOCTYPE html…

ARM v8 Cortex R52内核 08 内存保护单元 Memory Protection Unit

ARM v8 Cortex R52内核 08 内存保护单元 Memory Protection Unit 8.1 About the MPU Cortex R52 处理器具有两个可编程的MPU&#xff0c;由EL1和EL2控制。每个MPU允许将4GB内存地址划分为多个区域。 每个内存区域由基地址、限制地址、访问权限和内存属性定义。 对于数据访问…

阿里对象储存OSS的SDK使用

对象存储OSS 该功能的实现使用了阿里的&#xff1a;对象存储OSS技术。 在阿里对象存储空间的文件可以 以链接 的形式进行访问: 文件访问路径规则 &#xff1a;https://BucketName.Endpoint/ObjectName 该技术的使用方式有很多&#xff0c;针对于SDK的简单实现官网上也有教程…

【网络编程】高性能并发服务器源码剖析

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的网络编程系列之洪水网络攻击&#xff0c;在这篇文章中&#xff0c;你将会学习到在网络编程中如何搭建一个高性能的并发服务器&#xff0c;并且我会给出源码进行剖析&#xff0c;以及手绘UML图来帮助大家来理解&#xf…

教你将配置好的conda环境迁移到其它设备

文章目录 问题分析存在的方法环境要求方法步骤1. 下载conda pack2. 打包原环境3. 新设备还原环境4. 查看环境 问题分析 好不容易配置好的conda环境&#xff0c;要在另一个设备上运行&#xff0c;还要重新配置&#xff0c;好麻烦。 存在的方法 pip install -r requirement.txt …

Node.js留言板(超详细注释)

目录结构如下 app.js // 一.引入模块 var http require(http);// 用于创建 HTTP 服务器和处理 HTTP 请求 var fs require(fs);// 用于读取和写入文件 var url require(url);// 用于解析URL// 创建留言数据对象 var msgs [{ name: 牛二, content: "我是妞儿", cr…

场景:数据库死锁

来自hollis八股文 流程图 前置知识 数据库上锁锁住的不是行&#xff0c;而是索引的主键 比如我对id 1的主键进行上锁&#xff0c;实际上是对查询使用的主键的key 1 进行上锁 对非聚簇索引操作时&#xff0c;首先会对非聚簇索引上锁&#xff0c;然后在请求主键的锁 比如我…

为什么开关电源变压器的耦合不可能为100%?什么是漏感?

一、为什么开关电源变压器的耦合不可能为100%&#xff1f; 变压器耦合度是指变压器初级绕组和次级绕组之间能量传递的效率&#xff0c;它反映了变压器在电磁感应过程中&#xff0c;初级侧磁通量能够有多少比例被次级侧有效利用。理论上&#xff0c;理想的变压器耦合度应该是10…

08 Php学习:if语句、Switch语句

PHP 条件语句 当您编写代码时&#xff0c;您常常需要为不同的判断执行不同的动作。您可以在代码中使用条件语句来完成此任务。 在 PHP 中&#xff0c;提供了下列条件语句&#xff1a; if 语句 - 在条件成立时执行代码 if…else 语句 - 在条件成立时执行一块代码&#xff0c;…

Java实现短信发送并校验,华为云短信配合Redis实现发送与校验

Java实现短信发送并校验&#xff0c;华为云短信配合Redis实现发送与校验 安装sms4j和redis <dependency><groupId>org.dromara.sms4j</groupId><artifactId>sms4j-spring-boot-starter</artifactId><version>3.2.1</version> <…

WPS基础使用

个人笔记&#xff08;整理不易&#xff0c;有帮助&#xff0c;收藏点赞评论&#xff0c;爱你们&#xff01;&#xff01;&#xff01;你的支持是我写作的动力&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 个人随笔…

单路高清HDMI编码器JR-3211HD

产品简介&#xff1a; JR-3211HD单路高清HDMI编码器是专业的高清音视频编码产品&#xff0c;该产品具有支持1路高清HDMI音视频采集功能&#xff0c; 1路3.5MM独立外接音频输入&#xff0c;编码输出双码流H.264格式&#xff0c;音频MP3/AAC格式。编码码率可调&#xff0c;画面质…

SHARE 203S PRO:倾斜摄影相机在地灾救援中的应用

在地质灾害的紧急关头&#xff0c;救援队伍面临的首要任务是迅速而准确地掌握灾区的地理信息。这时&#xff0c;倾斜摄影相机成为了救援测绘的利器。SHARE 203S PRO&#xff0c;这款由深圳赛尔智控科技有限公司研发的五镜头倾斜摄影相机&#xff0c;以其卓越的性能和功能&#…

QtCreater 使用

QtCreater 创建项目 1.刚进入 QtCreater 的界面是这样的一个界面 ① 创建一个新的文件&#xff0c;那么我们就选择左上角的 “文件” ② 点击新建文件&#xff0c;或者也可以直接使用快捷键 CtrlN 此时就会弹出对话框&#xff0c;让我们选择想要创建的文件&#xff1a; Appli…

python爬虫-----爬虫解析—xpath(第十八天)

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…