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.pswp.cn/diannao/80106.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80106.shtml
英文地址,請注明出處:http://en.pswp.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 后,項目的…