Oracle--SQL性能优化与提升策略

  前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除

一、导致性能问题的内在原因

系统性能问题的底层原因主要有三个方面:

  • CPU占用率过高导致资源争用和等待
  • 内存使用率过高导致内存不足并需要使用磁盘虚拟内存
  • I/O占用率过高导致磁盘访问需要等待。

性能影响的优先级从高到低依次是CPU-->内存-->I/O。在PL/SQL性能优化中,重点是减少I/O瓶颈,即尽量减少对磁盘I/O的访问

根据上述分析,PL/SQL优化的核心思想可以总结为以下几点:

  • 避免使用过多复杂的SQL脚本,以减少系统的解析过程
  • 避免进行无用的计算,例如避免出现死循环等低效代码
  • 避免浪费内存空间,例如避免执行不必要的SQL脚本,以免导致内存不足
  • 充分利用内存中的计算和访问速度快的优势
  • 尽可能减少磁盘的访问数据量
  • 尽可能减少磁盘的访问次数,这是PL/SQL优化中的重要原则

二、如何进行SQL优化

1、选择最有效率的表名顺序

Oracle的解析器从右到左处理FROM子句中的表名,因此最后写的表(基础表 driving table)最先处理。在多表查询时,建议将记录最少的表作为基础表,以减少连接操作的数据量。Oracle会通过排序和合并方式连接表:先扫描并排序基础表,再扫描其他表并与基础表匹配。这种处理顺序对查询性能至关重要,建议按照此规则编写SQL语句。目前主要使用基于成本的优化器(CBO),它会自动评估最佳执行计划,但遵循上述规则有助于提升SQL效率。

 --例如:员工表emp有16384条记录,而部门表dept有1条记录,选择dept作为基础表  select count(*) from emp,dept;      --选择dept作为基础表耗时0.96sselect count(*) from dept,emp;      --选择emp作为基础表耗时26.09s

2、WHERE子句中的连接顺序

ORACLE 采用自下而上的顺序解析 WHERE 子句,根据这个原理,表之间的连接必须写在其他 WHERE 条件之前

 --低效:select dept.deptno,emp.jobfrom emp.deptwhere emp.job='MANAGER' AND emp.deptno=dept.deptno;​--优化后:select dept.deptno,emp.jobfrom emp.deptwhere emp.deptno=dept.deptno AND emp.job='MANAGER';

3、SELECT子句中避免使用'*'

在SELECT子句中使用动态SQL列引用“*”虽然方便,但效率低下。Oracle解析时会通过查询数据字典将“”转换为所有列名,这增加了额外的开销和时间成本。因此,建议在SELECT子句中尽量避免使用“”,而是明确列出所需的列名,以提高查询效率。

4、用EXITS 替代 IN

使用EXISTS替换IN效果有时不明显,但在基础表查询需联接另一表时,EXISTS通常提高效率,因EXISTS找到匹配即停止搜索

 --低效select *from table_name1where column1 in(select column1 from table_name2where column2=str_column2and column3='xxxx');​--优化后:select *from table_name1where exists(select 1 from table_name2where column1=table_name2.column1and column2=str_column2and column3='xxxx');

5、用 NOT EXISTS 替代 NOT IN

Oracle 10g前 NOT IN 效率低,10g 虽改进但仍存在问题。建议用 NOT EXISTS 替代 NOT IN ,因 NOT IN 对子查询表全表遍历且需内部排序合并,效率低。改写为 NOT EXISTS 可提升效率

 --低效:select * from table_name1where column1 NOT IN(select column1 from table_name2where column3='xxxx');​--优化后:select *from table_name1where not exists(select 1 from table_name2where column1=table_name2.column1and column3='xxxx');

6、用表连接替换 EXISTS

子查询的表和主表查询是多对一的情况,一般采用表连接的方式比 EXISTS 更有效率

 --低效:select table name1.*from table name1where exists (select 1 from table_name2where column1 =table name1.column1and column2='xxxx'and column3='xxxxxx');--优化后:SELECT table_name1.*FROM table namel,table name2 Wheretable_name1.column1=table_name2.column1and table_name2.column2='xxxx'and column3='xxxx';

7、减少对表的查询

该问题是我们编程中出现过的问题,请大家一定注意,并且该类问题优化可以带来较大性能的提升

 --低效:cursor cur_table_lj1 isselect column1from table1where column1 = str_column1 and column2='1111';cursor cur_table1_lj2 isselect column1from table1where column1 =str_column1 and column2='2222';​for rec_lj1 in cur_table1 loop业务逻辑1处理end loop;for rec_lj2 in cur_table2 loop业务逻辑2处理end loop;​--优化后:cursor cur_tablel_lj1 isselect column1,column2from table1where column1 =str_columnl and column2 in ('11111','22222');​for rec_ljl in cur_tablel lj1 loopif rec_lj1.column2='11111' then业务逻辑1处理.…..end if;if rec lj1.column2='22222' then业务逻辑2处理....end if,end loop;

高效的做法使用同样的条件(或者说是索引)只访问一次磁盘,低效的做法访问了2次磁盘,这样速度差 别将近2倍。

8、避免循环(游标)里面嵌查询

游标中不能有游标或update、delete等语句,只能有select语句,但在实际编程中难以完全避免,需尽量减少。优化方法是将游标循环中的查询语句提前到游标查询中一次性查询出来,减少磁盘访问次数,提升效率。如果无法避免游标中使用查询语句,要确保查询语句使用索引,提高查询速度。

9、尽量用 union all 替换 all

Union 会去掉重复的记录,会有排序的动作,会浪费时间。因此在没有重复记录的情况下或可以允许有重,复记录的话,要尽量采用 uoion all 来关联

10、group by 优化

Group by需要查询后分组,速度慢影响性能,如果查询数据量大,并且分组复杂,这样的査询语句在性能上是有问题的。采用 group by的也一定要进行优化

 --低效:select table1.column1,table2.column2table2.column3,sum(column5),table1.column4from table1,table2where table1.column1=table2.column1and table1.column4='xxxxxx'group py table1.column1,table2.column2table2.column3,table2.column4​--优化后:select table1.column1,table2.column2,table2.column3,gzze,table1.column4from(select column1,sum(column5) gzzefrom table1 group by column1) table1,table2where table1.column1=table2.column1and column4='xxxx';

11、尽量避免用 order by

使用 ORDER BY 会因查询后排序而拖慢速度,尤其数据量大时。尽管有时无法避免使用 ORDER BY ,但需注意排序列表应符合索引,这样能显著提升速度。

12、用where 子句替换Having 子句

避免使用HAVING子句,因为它会在检索完所有记录后才对结果集进行过滤,这个过程需要排序、总计等操作。如果能通过WHERE子句限制记录数量,就能减少这方面的开销。

 --低效:select column1,count(1) from table1group by column1having column1 in ('1','2');--优化后:select column1,count(1) from table1where column1 in ('1','2')group by column1;

HAVING 中的条件一般用于对一些集合函数的比较,如 COUNT() 等等。除此而外,一般的条件应该写在 WHERE 子句中

13、使用表的别名(alias)

在SQL语句中连接多个表时,使用表的别名并将其前缀于每个列名,可减少解析时间及因列名歧义引发的语法错误。

14、COMMIT 使用

  • 提交频率过高会浪费时间,尽管单次提交时间短。
  • 提交可释放资源,在大量数据更新时需及时提交。
 --cur_table1 有5000万数据n_count :=0For arec in cur_table1 loopInsert into table ...n_count := n_count + 1;If n_count = = 100000 then      --10万一提交commit;n_count := 0End if;End loop;Commit;

15、减少多表关联

  • 表关联越多,查询速度越慢,建议表关联不超过3个(子查询也算表关联)。
  • 大数据量表关联会影响索引效率,可采用建立临时表的方法来提高速度。

三、索引使用优化

1、避免在索引列上使用函数或运算

在实际编程中要注意:在索引列上使用函数或运算,查询条件不会使用索引。

 --不使用索引select * from table1where column1='xxx'and to_char(column2,'yyyymm')='200801';或者select * from table1where column1='xxx'and column2+1=sysdate;​--使用索引select * from table1where column1='xxx'and column2=to_date('200801','yyyymm');或者select * from table1where column1='xxx'and column2=sysdate -1;

2、避免改变索引列的类型

索引列的条件如果类型不匹配,则不能使用索引。

3、避免在索引列上使用NOT

避免在索引列上使用 NOT , NOT 不会使查询条件使用索引。对于 != 这样的判断也不能使用索引,因为索引只能告诉你什么存在于表中,而不能告诉你什么不存在于表中。

 --低效:select * from table1 where not column1='10';​--优化后:select * from table1 where column1 in ('20','30');

4、用>=替代>

虽然效果不是特别明显,但建议采用这种方式

 --低效:select * from table1 where column1 > '10';​--优化后:select * from table1 where column >= '20';

特别说明:两者的区别在于,前者 DBMS 首先定位到 column1=10的记录并且向前扫描到第一个column1 大于 10 的记录,而后者 DBMS 将直接跳到第一个 column1 等于 20 的记录

5、避免在索引列上使用 IS NULL和IS NOT NULL

在Oracle中,索引列使用 IS NULL 或 IS NOT NULL 时不会利用索引,因为空值不存储于索引列。这会导致Oracle停用索引

 --低效:select * from table1 where column1 is not null;​--优化后:select * from table1 where column1 in ('10','20','30');

6、带通配符(%)的like语句

%在常量前面索引就不会使用。

 --不使用索引:select * from table1 where column1 like '%210104';select * from table1 where column1 like '%210104%';​--使用索引:select * from table1 where column1 like '210104%';

7、总是使用索引的第一个列

如果索引是建立在多个列上,只有在它的第一个列被 where 子句引用时,优化器才会选择使用该索引。

 --如:table1的复合索引(column1,column2,column3)--低效(不会使用索引):select * from table1 where column2='110' and column3='200801';​--优化后(会使用索引):select * from table1 where column1 = '10001000';

如果不使用索引第一列基本上不会使用索引,使用索引要按照索引的顺序使用,另外使用复合索引的列越多,查询的速度就越快

8、 关于索引建立

索引可大幅提升查询速度,但也占用空间。过多索引会影响 INSERT 、 DELETE 和 UPDATE 操作的速度,因这些操作会改变索引顺序,需Oracle调整,导致性能下降。因此,要合理创建有效索引,编程时符合索引规则,而非让索引适应编程。

示例:在某项目数据转换中,采用游标循环插入2000万条数据耗时4小时,因目标表索引过多。解决方法是先删除索引再执行转换脚本,不到1小时完成,重建所有索引仅需半小时。

四、对于千万级的大表应该怎么优化

1、制定优化方案

针对Oracle数据库千万级大表的读、写、计算优化,可采取以下措施:

优化读:
  • 建立合适索引,使用索引覆盖查询避免全表扫描。
  • 使用分区表,将大表拆分,查询时只需扫描部分数据。
  • 增加内存,扩大数据库缓存区,减少磁盘I/O操作。
  • 优化SQL语句,避免子查询、减少连接操作。
优化写:
  • 使用并行写入,将数据写入多个表或节点。
  • 采用批量写入,减少写入操作次数。
  • 减少索引数量,避免过多索引影响写入性能。
  • 避免使用触发器,减少额外的I/O操作。
优化计算:
  • 使用分布式计算,分散计算任务到多个节点。
  • 采用并行计算,将任务划分成多个子任务并行执行。
  • 使用合适的数据结构,减少计算时间。
  • 优化SQL语句,减少计算操作的数据量。

2、优化方案总结

总结优化方案的几种方法:

  • 建立合适的索引:索引可提升查询速度,但过多或不合适的索引会影响数据库性能,需根据实际情况合理建立。
  • 分区表:将大表分成多个小表,提高查询速度和维护效率。
  • 优化SQL语句:减少数据库的I/O操作,提高查询效率。可采用优化查询语句、查询条件,避免使用子查询等方式。
  • 增加内存:扩大数据库缓存区和内存,减少磁盘I/O操作,提高查询效率。
  • 优化磁盘I/O:使用RAID技术、SSD硬盘等方式提升磁盘I/O速度,增强数据库性能。

    学习永无止境,让我们共同进步!!

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

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

相关文章

【go】什么是Go语言中的GC,作用是什么?调优,sync.Pool优化,逃逸分析演示

Go 语言中的 GC 简介与调优建议 Go语言GC工作原理 对于 Go 而言,Go 的 GC 目前使用的是无分代(对象没有代际之分)、不整理(回收过程中不对对象进行移动与整理)、并发(与用户代码并发执行)的三…

【unity实战】Animator启用root motion根运动动画,实现完美的动画动作匹配

文章目录 前言1、动画分类2、如何使用根位移动画? 一、根位移动画的具体使用1、导入人形模型2、导入动画3、配置动画参数4、配置角色Animator动画状态机5、使用代码控制人物前进后退 二、问题分析三、Humanoid动画中的Root Motion机制及相关配置1、Humanoid动画中的…

中间件--ClickHouse-10--海量数据存储如何抉择ClickHouse和ES?

在Mysql数据存储或性能瓶颈时,采用冷热数据分离的方式通常是一种选择。ClickHouse和Elasticsearch(ES)是两个常用的组件,但具体使用哪种组件取决于冷数据的存储目的、查询模式和业务需求等方面。 1、核心对比 (1&…

服务器运维:服务器流量的二八法则是什么意思?

文章目录 用户行为角度时间分布角度应用场景角度 服务器流量的二八法则,又称 80/20 法则,源自意大利经济学家帕累托提出的帕累托法则,该法则指出在很多情况下,80% 的结果是由 20% 的因素所决定的。在服务器流量领域,二…

springboot对接豆包大模型

文档地址: 豆包大模型-火山引擎 模型广场地址: 账号登录-火山引擎 首先来到模型广场,选取你需要的模型,我这边要做图片理解的应用,所以选用了Doubao-1.5.vision-pro. 点立即体验,进入一个新的页面,可以上传图片,然后…

数据通信学习笔记之OSPF其他内容3

对发送的 LSA 进行过滤 当两台路由器之间存在多条链路时,可以在某些链路上通过对发送的 LSA 进行过滤,减少不必要的重传,节省带宽资源。 通过对 OSPF 接口出方向的 LSA 进行过滤可以不向邻居发送无用的 LSA,从而减少邻居 LSDB 的…

智能安全用电系统预防电气线路老化、线路或设备绝缘故障

智能安全用电系统预防电气线路老化、线路或设备绝缘故障 智能安全用电系统,犹如一位忠实而敏锐的卫士,主要针对低压供电网中一系列潜在的危险状况进行了全方位且行之有效的预防和保护。 智能安全用电系统在低压供电网这个复杂的体系中,电气线…

使用Intel Advisor工具分析程序

使用Intel Advisor工具分析程序 Intel Advisor是一款性能分析工具,主要用于识别代码中的向量化机会、线程化和内存访问模式等问题。以下是使用Intel Advisor分析程序的基本步骤: 安装与准备 从Intel官网下载并安装Intel Advisor(通常作为I…

【UniApp】Vue2 scss 预编译器默认已由 node-sass 更换为 dart-sass

从 HBuilderX 4.56 ,vue2 项目也将默认使用 dart-sass 预编译器。 vue2开发者sass预处理注意: sass的预处理器,早年使用node-sass,也就是vue2最初默认的编译器。 sass官方推出了dart-sass来替代。node-sass已经停维很久了。 另…

智慧能源安全新纪元:当能源监测遇上视频联网的无限可能

引言:在数字化浪潮席卷全球的今天,能源安全已成为国家安全战略的重要组成部分。如何构建更加智能、高效的能源安全保障体系?能源安全监测平台与视频监控联网平台的深度融合,正为我们开启一扇通向未来能源管理新世界的大门。这种创…

C++游戏服务器开发之⑦redis的使用

目录 1.当前进度 2.守护进程 3.进程监控 4.玩家姓名添加文件 5.文件删除玩家姓名 6.redis安装 7.redis存取命令 8.redis链表存取 9.redis程序结构 10.hiredisAPI使用 11.基于redis查找玩家姓名 12.MAKEFILE编写 13.游戏业务实现总结 1.当前进度 2.守护进程 3.进程监…

db中查询关于null的sql该怎么写

正确示例 # 等于null select * from 表名 where 字段名 is NULL; # 不等于null select * from 表名 where 字段名 is not NULL;若需要同时判断字段不等于某个值且不为null select * from users where age ! 30 and age is not null; select * from users where age ! 30 or a…

从“堆料竞赛”到“体验深耕”,X200 Ultra和X200s打响手机价值升维战

出品 | 何玺 排版 | 叶媛 vivo双旗舰来袭! 4月21日,vivo X系列春季新品发布会盛大开启,带来了一场科技与创新的盛宴。会上,消费者期待已久的X200 Ultra及X200s两款旗舰新品正式发布。 vivo两款旗舰新品发布后,其打破…

多模态大语言模型arxiv论文略读(三十二)

Proximity QA: Unleashing the Power of Multi-Modal Large Language Models for Spatial Proximity Analysis ➡️ 论文标题:Proximity QA: Unleashing the Power of Multi-Modal Large Language Models for Spatial Proximity Analysis ➡️ 论文作者&#xff1a…

基于贝叶斯优化的Transformer多输入单输出回归预测模型Bayes-Transformer【MATLAB】

Bayes-Transformer 在机器学习和深度学习领域,Transformer模型已经广泛应用于自然语言处理、图像识别、时间序列预测等多个领域。然而,在一些实际应用中,我们面临着如何高效地优化模型超参数的问题。贝叶斯优化(Bayesian Optimiz…

Ruby 正则表达式

Ruby 正则表达式 引言 正则表达式(Regular Expression,简称Regex)是一种强大的文本处理工具,在编程和数据处理中有着广泛的应用。Ruby 作为一种动态、灵活的编程语言,同样内置了强大的正则表达式功能。本文将详细介绍…

kubernetes》》k8s》》删除命名空间

使用 kubectl delete ns 命名空间 --force --grace-period0 如果还删除不掉 需要 kubectl get namespace 命名空间 -o json > x.json vim x.json kubectl replace --raw “/api/v1/namespaces/命名空间/finalize” -f ./x.json

玩转Docker | 使用Docker部署DashMachine个人书签工具

玩转Docker | 使用Docker部署DashMachine个人书签工具 前言一、DashMachine介绍DashMachine简介DashMachine使用场景二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署DashMachine服务下载镜像创建容器创建容器检查容器状态检查服务端口安全设置四、访问Das…

SQL进阶知识:一、高级查询

今天介绍下关于高级查询的详细介绍,包括子查询、连接查询、分组查询等,并结合MySQL数据库提供实际例子。 一、子查询(Subqueries) 子查询是嵌套在另一个查询中的查询语句,通常用于提供条件过滤、生成临时数据集等。子…

【Git】Git Revert 命令详解

Git Revert 命令详解 1. Git Revert 的基本概念 Git Revert 是一个用于撤销特定提交的命令。与 Git Reset 不同,Git Revert 不会更改提交历史,而是会创建一个新的提交来撤销指定提交的更改。这意味着,使用 Git Revert 后,项目的…