Oracle SQL优化②——访问路径

前言

访问路径指的就是通过哪种扫描方式获取数据,比如全表扫描、索引扫描或者直接通过ROWID获取数据。想要完成SQL优化,就必须深入理解各种访问路径。本文章详细介绍常见的访问路径。

一.常见访问路径

1.TABLE ACCESS FULL

表示全表扫描,一般情况下是多块读,HINT: FULL(表名/别名)。等待事件为 db file scattered read。如果是并行全表扫描,等待事件为 direct path read。在Oracle11g中有个新特征,在对一个大表进行全表扫描的时候,会将表直接读入PGA,绕过buffercache,这个时候全表扫描的等待事件也是 direct path read。一般情况下,我们都会禁用该新特征。等待事件 direct path read在开启了异步I/O(disk_asynch_io)的情况下统计是不准确的。

alter system set "_serial_direct_read"=false;

全表扫描究竟是怎么扫描数据的呢?回忆一下Oracle的逻辑存储结构,Oracle最小的存储单位是块(block),物理上连续的块组成了区(extent),区又组成了段(segment)。对于非分区表,如果表中没有clob/blob字段,那么一个表就是一个段。全表扫描,其实就是扫描表中所有格式化过的区。因为区里面的数据块在物理上是连续的,所以全表扫描可以多块读。全表扫描不能跨区扫描,因为区与区之间的块物理上不一定是连续的。对于分区表,如果表中没有clob/blob字段,一个分区就是一个段,分区表扫描方式与非分区表扫描方式是一样的。
对一个非分区表进行并行扫描,其实就是同时扫描表中多个不同区,因为区与区之间的块物理上不连续,所以我们不需要担心扫描到相同数据块。
对一个分区表进行并行扫描,有两种方式。如果需要扫描多个分区,那么是以分区为粒度进行并行扫描的,这时如果分区数据不均衡,会严重影响并行扫描速度;如果只需要扫描单个分区,这时是以区为粒度进行并行扫描的。
如果表中有clob字段,clob会单独存放在一个段中,当全表扫描需要访问clob字段时,这时性能会严重下降,因此尽量避免在Oracle中使用clob。我们可以考虑将clob字段拆分为多个varchar2(4000)字段,或者将clob存放在nosql数据库中,例如 mongodb。

一般的操作系统,一次I/O最多只支持读取或者写入1MB数据。数据块为8KB的时候,一次I/O最多能读取128个块。数据块为16KB的时候,一次I/O最多能读取64个块,数据块为32KB的时候,一次I/O最多能读取32个块。
如果表中有部分块已经缓存在buffer cache中,在进行全表扫描的时候,扫描到已经被缓存的块所在区时,就会引起I/O中断。如果一个表不同的区有大量块缓存在buffer cache中,这个时候,全表扫描性能会严重下降,因为有大量的I/O中断,导致每次I/O不能扫描1MB数据。

如果表正在发生大事务,在进行全表扫描的时候,还会从undo读取部分数据。从undo读取数据是单块读,这种情况下全表扫描效率非常低下。因此,我们建议使用批量游标的方式处理大事务。使用批量游标处理大事务还可以减少对undo的使用,防止事务失败回滚太慢。

2.TABLE ACCESS BY USER ROWID

表示直接用ROWID获取数据,单块读
该访问路径是Oracle所有访问路径中性能是最好的

3.TABLE ACCESS BY ROWID RANGE

ROWID范围扫描,多块读。因为同一个块里面的ROWID是连续的,同一个EXTENT里面的ROWID也是连续的,所以可以多块读。

4.TABLE ACCESS BY INDEX ROWID

表示回表,单块读

5.INDEX UNIQUE SCAN

索引唯一扫描,单块读
对唯一索引或者对主键列进行等值查找,就会走索引唯一扫描。因为对唯一索引或者对主键列进行等值查找,CBO能确保最多只返回1行数据,所以这时可以走索引唯一扫描。
在所有Oracle访问路径中,性能仅次于TABLE ACCESS BY USER ROWID

6.INDEX RANGE SCAN

索引范围扫描,单块读,返回的数据是有序的(默认升序)。HINT:INDEX(表名/别名索引名)。对唯一索引或者主键进行范围查找,对非唯一索引进行等值查找,范围查找,就会发生 INDEX RANGE SCAN。等待事件为 db file sequential read。
因为索引IDXID是非唯一索引,对非唯一索引进行等值查找并不能确保只返回一行数据,有可能返回多行数据,所以执行计划会进行索引范围扫描。
索引范围扫描默认是从索引中最左边的叶子块开始,然后往右边的叶子块扫描(从小到大),当检查到不匹配数据的时候,就停止扫描。
在检查执行计划的时候我们要注意索引范围扫描返回多少行数据,如果返回少量数据,不会出现性能问题。如果返回大量数据,在没有回表的情况下也还好。如果返回大量数据同时还有回表,这时我们应该考虑通过创建组合索引消除回表或者使用全表扫描来代替它。

7.INDEX SKIP SCAN

索引跳跃扫描,单块读。返回的数据是有序的(默认升序)。HINT:INDEX_SS(表名/别名索引名)。
INDEX SKIP SCAN中有个SKIP关键字,也就是说它是跳着扫描的。那么想要跳跃扫描,必须是组合索引,如果是单列索引怎么跳?另外,组合索引的引导列不能出现在where条件中,如果引导列出现在where 条件中,它为什么还跳跃扫描呢,直接INDEX RANGE SCAN不就可以了?再有,要引导列基数很低,如果引导列基数很高,那么它“跳”的次数就多了,性能就差了。
当执行计划中出现了 INDEX SKIP SCAN,我们可以直接在过滤列上面建立索引,使用INDEX RANGE SCAN代替INDEX SKIP SCAN。

8.INDEX FULL SCAN

索引全扫描,单块读,返回的数据是有序的(默认升序)。HINT:INDEX(表名/别名索引名)。索引全扫描会扫描索引中所有的叶子块(从左往右扫描),如果索引很大,会产生严重性能问题(因为是单块读)。等待事件为db file sequential read。
它通常发生在下面3种情况。
分页语句。
SQL语句有order by选项,order by的列都包含在索引中,并且order by后列顺序必须和索引列顺序一致。order by的第一个列不能有过滤条件,如果有过滤条件就会走索引范围扫描(INDEX RANGE SCAN)。同时表的数据量不能太大(数据量太大会走TABLE ACCESS FULL+ SORT ORDER BY)。
在进行SORT MERGE JOIN的时候,如果表数据量比较小,让连接列走INDEX FUL SCAN可以避免排序。
当看到执行计划中有INDEX FULL SCAN,我们首先要检查INDEX FULL SCAN是否有回表
如果INDEX FULL SCAN没有回表,我们要检查索引段大小,如果索引段太大(GB级别),应该使用INDEX FAST FULL SCAN代替INDEX FULL SCAN,因为INDEX FAST FULL SCAN是多块读,INDEX FULL SCAN是单块读,即使使用了INDEX FAST FULL SCAN会产生额外的排序操作,也要用INDEX FAST FULL SCAN 代替INDEX FULL SCAN。
如果INDEX FULL SCAN有回表,大多数情况下,这种执行计划是错误的,因为INDEX FULL SCAN 是单块读,回表也是单块读。这时应该走全表扫描,因为全表扫描是多块读。如果分页语句走了INDEX FULL SCAN然后回表,这时应该没有太大问题

9.INDEX FAST FULL SCAN

索引快速全扫描,多块读。HINT:INDEX_FFS(表名/别名 索引名)。当需要从表中查询出大量数据但是只需要获取表中部分列的数据的,我们可以利用索引快速全扫描代替全表扫描来提升性能。索引快速全扫描的扫描方式与全表扫描的扫描方式是一样,都是按区扫描,所以它可以多块读,而且可以并行扫描。等待事件为db file scattered read,如果是并行扫描,等待事件为 direct path read。
现有如下SQL

select owner,object_name from test;

该SQL没有过滤条件,默认情况下会走全表扫描。但是因为Oracle是行存储数据库,全表扫描的时候会扫描表中所有的列,而上面查询只访问表中两个列,全表扫描会多扫描额外13个列,所以我们可以创建一个组合索引,使用索引快速全扫描代替全表扫描。

create index idx_ownername on test(owner,object_name,0);

以上SQL能否走 INDEX RANGE SCAN 呢?INDEX RANGE SCAN是单块读,SQL会返回表中大量数据,“几乎”会扫描索引中所有的叶子块。INDEX FAST FULL SCAN是多块读,会扫描索引中所有的块(根块、所有的分支块、所有的叶子块)。虽然INDEX RANGE SCAN与INDEX FAST FULL SCAN相比扫描的块少(逻辑读少),但是INDEX RANGE SCAN是单块读,耗费的I/O次数比INDEX FAST FULL SCAN的I/O次数多,所以INDEX FAST FULL SCAN 性能更好。
在做SQL优化的时候,我们不要只看逻辑读来判断一个SQL性能的好坏,物理I/O次数比逻辑读更为重要。有时候逻辑读高的执行计划性能反而比逻辑读低的执行计划性能更好,因为逻辑读高的执行计划物理I/O次数比逻辑读低的执行计划物理I/O次数低。
在 Oracle 数据库中,INDEX FAST FULL SCAN是用来代替TABLE ACCESS FULL的。因为Oracle是行存储数据库,TABLE ACCESS FULL会扫描表中所有的列,而INDEX FAST FULL SCAN只需要扫描表中部分列,INDEX FAST FULL SCAN就是由Oracle 是行存储这个“缺陷”而产生的。

10.INDEX FULL SCAN (MIN/MAX)

索引最小/最大值扫描,单块读,该访问路径发生在select max(column) from table;或者select min(column) from table;语句中。
只会访问“索引高度”个索引块,其性能与INDEX UNIQUE SCAN一样,仅次于TABLE ACCESS BY USER ROWID

11.MAT_VIEW REWRITE ACCESS FULL

物化视图全表扫描,多块读。物化视图本质上也是一个表,所以其扫描方式与全表扫描一样。如果开启了查询重写功能,而且SQK查询能够直接从物化视图中获得结果,就会走该访问路径。

二.单块读与多块读

单块读与多块读这两个概念对于掌握SQL优化非常重要,更准确地说是单块读的物理I/O次数和多块读的物理I/O次数对于掌握SQL优化非常重要。
从磁盘1次读取1个块到buffer cache就叫单块读,从磁盘1次读取多个块到buffer cache就叫多块读。如果数据块都已经缓存在buffer cache中,那就不需要物理I/O了,没有物理I/O也就不存在单块读与多块读。
绝大多数的平台,一次I/O最多只能读取或者写入1MB数据,Oracle的块大小默认是8K,那么一次I/O最多只能写入128个块到磁盘,最多只能读取128个块到buffer cache。在判断哪个访问路径性能好的时候,通常是估算每个访问路径的I/0次数,谁的I/O次数少,谁的性能就好。在估算I/O次数的时候,我们只需要算个大概就可以了,没必要很精确。

三.为什么有时候索引扫描比全表扫描更慢

假设一个表有100万行数据,表的段大小为1GB。如果对表进行全表扫描,最理想的情况下,每次I/O都读取1MB数据(128个块),将1GB的表从磁盘读入buffer cache需要1024次I/O。在实际情况中,表的段前16个extent,每个extent都只有8个块,每次I/O只能读取8个块,而不是128个块,表中有部分块会被缓存在buffer cache中,会引起I/O中断,那么将1GB的表从磁盘读入buffer cache可能需要耗费1500次物理I/O。
从表中查询5万行数据,走索引。假设一个索引叶子块能存储100行数据,那么5万行数据需要扫描500个叶子块(单块读),也就是需要500次物理I/O,然后有5万条数据需要回表,假设索引的集群因子很小(接近表的块数),假设每个数据块存储50行数据,那么回表需要耗费1000次物理I/O(单块读),也就是说从表中查询5万行数据,如果走索引,一共需要耗费大概1500次物理I/O。如果索引的集群因子较大(接近表的总行数),那么回表要耗费更多的物理I/O,可能是3000次,而不是1000次。
根据上述理论我们知道,走索引返回的数据越多,需要耗费的I/O次数也就越多,因此返回大量数据应该走全表扫描或者是INDEX FAST FULL SCAN,返回少量数据才走索引扫描。根据上述理论,我们一般建议返回表中总行数5%以内的数据,走索引扫描,超过5%走全表扫描。请注意,5%只是一个参考值,适用于绝大多数场景,如有特殊情况,具体问题具体分析。

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

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

相关文章

【CANOE】【Capl】【RS232】控制串口设备

系列文章目录 内置函数,来控制传统的串口设备,比如继电器等 文章目录 系列文章目录前言一、控制串口二、自定义相关的参数RS232Configure**函数语法****函数功能****参数说明****返回值****示例代码** 三、回调函数的使用RS232OnSend**函数语法****函数…

AX58100+STM32使用FSMC接口,运行EtherCAT Slave协议栈

目录 简介环境硬件接线MCU一侧的初始化时钟FSMC外部中断timer 协议栈生成EtherCAT SlaveSlave infomationgenerichardwareEtherCAT State MachineSynchronisationApplicaitonProcessDataMailbox OD TOOL 协议栈移植协议栈集成和错误初步解决启动协议栈 应用开发集成到TWINCAT集…

IC数字后端实现之大厂IC笔试真题(经典时序计算和时序分析题)

今天小编给大家分享下每年IC秋招春招必考题目——静态时序分析时序分析题。 数字IC后端笔试面试题库 | 经典时序Timing计算题 时序分析题1: 给定如下图所示的timing report,请回答一下几个问题。 1)这是一条setup还是hold的timing report?…

嵌入式系统与OpenCV

目录 一、OpenCV 简介 二、嵌入式 OpenCV 的安装方法 1. Ubuntu 系统下的安装 2. 嵌入式 ARM 系统中的安装 3. Windows10 和树莓派系统下的安装 三、嵌入式 OpenCV 的性能优化 1. 介绍嵌入式平台上对 OpenCV 进行优化的必要性。 2. 利用嵌入式开发工具,如优…

英伟达发布 Edify 3D 生成模型,可以在两分钟内生成详细的、可用于生产的 3D 资源、生成有组织的 UV 贴图、4K 纹理和 PBR 材质。

英伟达发布 Edify 3D 生成模型,可以利用 Agents 自动判断提示词场景中需要的模型,生成后将他们组合为一个场景。 Edify 3D 可以在两分钟内生成详细的、可用于生产的 3D 资源、生成有组织的 UV 贴图、4K 纹理和 PBR 材质。 相关链接 论文:htt…

抖音短视频矩阵源代码部署搭建流程

抖音短视频矩阵源代码部署搭建流程 1. 硬件准备 需确保具备一台性能足够的服务器或云主机。这些硬件设施应当拥有充足的计算和存储能力,以便支持抖音短视频矩阵系统的稳定运行。 2. 操作系统安装 在选定的服务器或云主机上安装适合的操作系统是关键步骤之一。推…

【Android+多线程】异步 多线程 知识总结:基础概念 / 多种方式 / 实现方法 / 源码分析

1 基本概念 1.1 线程 定义:一个基本的CPU执行单元 & 程序执行流的最小单元 比进程更小的可独立运行的基本单位,可理解为:轻量级进程组成:线程ID 程序计数器 寄存器集合 堆栈注:线程自己不拥有系统资源&#…

NLP论文速读(剑桥大学出品)|分解和利用专家模型中的偏好进行改进视觉模型的可信度

论文速读|Decompose and Leverage Preferences from Expert Models for Improving Trustworthiness of MLLMs 论文信息: 简介: 本文探讨的背景是多模态大型语言模型(MLLMs),这类模型通过结合视觉特征和文本空间来增强语…

CentOS8.5.2111(7)完整的Apache综合实验

一、实验目标 1.掌握Linux系统中Apache服务器的安装与配置; 2.掌握个人主页、虚拟目录、基于用户和主机的访问控制及虚拟主机的实现方法。 二、实验要求 练习使用linux系统下WEB服务器的配置方法。 三、实验背景 重庆工程学院为筹备“重庆工程大学”特申请了c…

零基础3分钟快速掌握 ——Linux【终端操作】及【常用指令】Ubuntu

1.为啥使用Linux做嵌入式开发 能广泛支持硬件 内核比较高效稳定 原码开放、软件丰富 能够完善网络通信与文件管理机制 优秀的开发工具 2.什么是Ubuntu 是一个以桌面应用为主的Linux的操作系统, 内核是Linux操作系统, 具有Ubuntu特色的可视…

JVM类加载和垃圾回收算法详解

文章目录 JVM一、JVM运行流程1. JVM执行流程 二、JVM运行时数据区1. 程序计数器(线程私有)2. 虚拟机栈 (线程私有)3. 本地方法栈(线程私有)4. 堆(线程共享)5. 元空间(线程…

iOS 17.4 Not Installed

0x00 系统警告 没有安装 17.4 的模拟器,任何操作都无法进行! 点击 OK 去下载,完成之后,依旧是原样! 0x01 解决办法 1、先去官网下载对应的模拟器: https://developer.apple.com/download/all/?q17.4 …

day04 企业级Linux安装及远程连接知识实践

1. 使用传统的网卡命名方式 在启动虚拟机时,按tab键进入编辑模式 添加命令: net.ifnames0 biosdevname0 这样linux系统会使用传统的网卡命名,例如eth0、eth1…… 2. 快照 做系统关键操作时,一定要使用快照(先将系统关机) 3.…

人体特定吸收率 (SAR) 分布建模

ANSYS HFSS 提供了一种建模 SAR 分布的方法! 2020 年对我们所有人来说都是充满挑战的一年,由于 COVID 19 限制和居家隔离,许多工程师不得不推迟开发时间表。ANSYS HFSS 为所有工程师提供了一种在家安全工作的好方法。隔离期间,您…

.NET9 - Swagger平替Scalar详解(四)

书接上回,上一章介绍了Swagger代替品Scalar,在使用中遇到不少问题,今天单独分享一下之前Swagger中常用的功能如何在Scalar中使用。 下面我们将围绕文档版本说明、接口分类、接口描述、参数描述、枚举类型、文件上传、JWT认证等方面详细讲解。…

计算(a+b)/c的值

计算(ab)/c的值 C语言代码C语言代码Java语言代码Python语言代码 💐The Begin💐点点关注,收藏不迷路💐 给定3个整数a、b、c,计算表达式(ab)/c的值,/是整除运算。 输入 输入仅一行&…

PICO 获取设备号 SN码

Unity版本 2020.3.42f1c1PICO SDK版本PICO Unity Integration SDK-3.0.5-20241105Pico设备pico 4ultra 注意 此api暂时只测试企业版本 pico 4ultra 代码 using Unity.XR.PICO.TOBSupport;private void Awake() {bool result PXR_Enterprise.InitEnterpriseService();Debug.L…

【大数据技术基础】 课程 第8章 数据仓库Hive的安装和使用 大数据基础编程、实验和案例教程(第2版)

第8章 数据仓库Hive的安装和使用 8.1 Hive的安装 8.1.1 下载安装文件 访问Hive官网(http://www.apache.org/dyn/closer.cgi/hive/)下载安装文件apache-hive-3.1.2-bin.tar.gz 下载完安装文件以后,需要对文件进行解压。按照Linux系统使用的…

[STM32]从零开始的STM32 FreeRTOS移植教程

一、前言 如果能看到这个教程的话,说明大家已经学习嵌入式有一段时间了。还记得嵌入式在大多数时候指的是什么吗?是的,我们所说的学习嵌入式大部分时候都是在学习嵌入式操作系统。从简单的一些任务状态机再到复杂一些的RTOS,再到最…

DAY133权限提升-Windows权限提升篇溢出漏洞土豆家族通杀全系补丁对比EXP筛选

知识点 1、Web到Win-系统提权-土豆家族 2、Web到Win-系统提权-人工操作 章节点: 1、Web权限提升及转移 2、系统权限提升及转移 3、宿主权限提升及转移 4、域控权限提升及转移 Windows提权: 1、内核溢出漏洞提权 2、数据库类型提权 3、第三方软件…