pl/sql性能優化技巧

1.為什么要進行SQL語句的性能優化

? ? ? 對于數據量不大的數據操作中,SQL語句的優不優化操作所帶來的收益并不大,但是當數據量增加到大量的情況下時,SQL的執行時間就會清楚的告訴我們語句效率的高低之分,每一條SQL語句的執行都有一定的步驟和順序,遵循優化的規則編寫SQL語句,可以從根本上優化數據的增刪改查操作(這里尤其突出“查”的操作,因為我們知道對數據庫操作有80%都是查的操作,而增刪改占比20%),從而提高SQL的執行效率。通往羅馬的路有很多,尋找到最優的一條,我們才能更快更好的到達羅馬。這就是我們之所以要對SQL語句優化的原因。

2.如何測試我們編寫的SQL 語句的性能

? ? oracle專門提供了對SQL語句性能分析的功能,就是執行計劃,通過對執行計劃的分析,我們可以清楚的知道SQL語句執行的效率。

什么是執行計劃?

? ? ?oracle數據庫在執行SQL語句時,oracle的優化器會根據一定的規則確定SQL語句的執行路徑,以確保SQL語句能以最優性能執行.在oracle數據庫系統中為了執行SQL語句,oracle可能需要實現多個步驟,這些步驟中的每一步可能是從數據庫中物理檢索數據行,或者用某種方法準備數據行,讓編寫SQL語句的用戶使用,oracle用來執行語句的這些步驟的組合被稱為執行計劃。

當執行一個SQL語句時oracle經過了4個步驟:

???? ①.解析SQL語句:主要在共享池中查詢相同的SQL語句,檢查安全性和SQL語法與語義。

???? ②.創建執行計劃及執行:包括創建SQL語句的執行計劃及對表數據的實際獲取。

???? ③.顯示結果集:對字段數據執行所有必要的排序,轉換和重新格式化。

???? ④.轉換字段數據:對已通過內置函數進行轉換的字段進行重新格式化處理和轉換.

明白SQL語句的執行流程和執行計劃的概念,我們現在應該要知道如何使用執行計劃,查看SQL語句的性能:

1.pl/sql中選中SQL語句,按F5即可以調出執行計劃窗口,如下所示

上面就是便是對于sql語句的執行計劃,具體參數分析如下:

基數(Rows):Oracle估計的當前操作的返回結果集行數;

字節(Bytes):執行該步驟后返回的字節數;

耗費(COST)、CPU耗費:Oracle估計的該步驟的執行成本,用于說明SQL執行的代價,理論上越小越好(該值可能與實際有出入);

時間(Time):Oracle估計的當前操作所需的時間;

Description中參數的解析:

? ? (1) 全表掃描(TABLE ACCESS FULL )

?? ??? ?Oracle會讀取表中所有的行,并檢查每一行是否滿足SQL語句中的 Where 限制條件;

?? ??? ?全表掃描時可以使用多塊讀(即一次I/O讀取多塊數據塊)操作,提升吞吐量;

?? ??? ?使用建議:數據量太大的表不建議使用全表掃描,除非本身需要取出的數據較多,占到表數據總量的 5% ~ 10% 或以上

? ? (2) 通過ROWID的表存取(TABLE ACCESS BY ROWID)

?? ??? ?行的rowid指出了該行所在的數據文件,數據塊及行在該塊中的位置,所以通過rowid來存取數據可以快速定位到目標數據上,是oracle存取單行數據的最快方法。

? ? (3) 索引掃描(TABLE ACCESS BY INDEX SCAN)

?? ?? ? ?先通過索引找到對象的rowid值,然后通過rowid值直接從表中找到具體的數據,能大大提高查找的效率。

SQL性能判斷依據:

1.SQL執行的時間盡量短;

2.耗費和CPU耗費盡可能的降低;

3.觀察Description的參數,有索引的字段應當顯示索引掃描,出現全表掃描時一定要進行推敲是否合理。

性能的比較是在于,對于獲得同意結果的sql語句,進行執行計劃的分析,獲取最優的SQL語句,那么所獲得的結果(也就是字節數和基數),應當是不改變的。

----------------------------------------------------------------------------

以上都是對于SQL語句性能的分析和查看,下面我們就要進行對SQL語句的優化

優化規則一:注意連接查詢時的表順序

?? ?? ? 首先先明白Oracle分析器對表數據進行連接查詢的規則是:從右到左的順序處理from子句的表,以第一張表為基礎表(驅動表)進行排序和合并的方式進行連接。

?? ?? ? 因此連接查詢時表順序的規則為:

當連接表為兩張時,必須選擇記錄條數的表作為基礎表;(基礎表就是按照連接查詢規則,從右至左的第一張表則為基礎表)

當連接表超過兩張時,需要優先選擇交叉表作為基礎表,若沒有交叉表時,則優先選擇記錄條數較少的表作為基礎表。(交叉表為既被A表也被B表所引用的表,既包含A表內容也包含B表內容的C表)

原因在于:選擇少記錄條數的表作為基礎表的原因在于,減少表與表之間合并的基準數,以誰作為基礎表,那么其基準數據量就以誰,如果基準表的數據量很大,那么會造成很多不必要的冗余數據產生。

優化規則二:指定where的條件順序

?? ?? ?首先先要明白Oracle分析器對where子句的執行順序的規則是:自下而上的順序解析where子句(也就是從后往前的執行)

?? ?? ? 因此where的條件順序規則為:

? ? 表連接條件必須在where條件中的前部;

? ? 過濾條件必須在where條件中的尾部。


原因在于:在處理多表連接查詢時,應給先要進行數據的篩選再進行數據是排序和合并,這樣可以先篩選掉部分無用的數據,合并多表數據時,整體速度就得到了一定的提高。

優化規則三:避免使用*符號

原因在于:使用*符號,Oracle需要先尋找到表對應的數據字典信息,將數據字典中的所有列信息取出來,然后依次轉化為列名,再進行數據的顯示,在這個轉化的過程就已經耗費了一定的時間,降低了效率。

優化規則四:多使用where而不是having作為篩選語句

?? ?? ? 首先先要明白where子句和having子句作用的具體情況:

?? ?? ? 1.where子句和having子句都可以過濾數據,但是where子句不能使用聚集函數,如count max min avg sum等函數。

?? ??? ?2.通常將Having子句與Group By子句一起使用,當利用Group By進行分組時,可以沒有Having子句,但Having出現時,一定會有Group By。

?? ?? ?3.WHERE語句是在GROUP BY語句之前篩選出記錄,而HAVING是在各種記錄都篩選之后再進行過濾。也就是說HAVING子句是在從數據庫中提取數據之后進行篩選的,因此在編寫SQL語句時,盡量在篩選之前將數據使用WHERE子句進行過濾。

因此執行的順序應該總是這樣:

? ①.使用WHERE子句查詢符合條件的數據;

? ②.使用GROUP BY子句對數據進行分組;

? ③.在GROUP BY分組的基礎上運行聚合函數計算每一組的值;

? ④.用HAVING子句去掉不符合條件的組。

這里再補充幾大子句的使用順序:

where 子句 --- group by子句 --- having 子句 --- order by子句

原因在于:先多數據進行篩選再進行有效數據分組,這樣可以大大的減少冗余數據量,提高效率。

優化規則五:合理的選擇in和exists;使用not exists代替not in

?? ?? ? 首先也要先明白:

?? ??? ?in和exists的原理,區別

?? ??? ?? ? 1.in 是把外表和內表作Hash Join連接,但是此時是將內表(存在in判斷的表)作為基礎表(驅動表)進行連接的,在

此就可以引出如何選擇這兩者的條件,in不對null進行判斷;

?? ??? ?? ? 2.exists 是把外表作為循環,每一次的循環都會對內表的條件進行判斷,一步步的遍歷判斷找到符合條件的數據。

? ? ?? ??? ?合理選擇in和exists的條件:

?? ??? ??? ?? ? 當子查詢所查詢出的結果集少,而主查詢數據量大時,選擇in反而比exists更高效;當子查詢所查詢出的結果集大,而主查詢數據量小時,選擇exists比in更高效。

?? ??? ?not in和not exists的原理,區別

?? ??? ?? ? 1.not in 是最為耗時耗資源的方式,將內外表均進行全表掃描,不使用索引,可想而知not in方式是非常不明智的選擇;

?? ??? ?? ? 2.not exists 則不然,主查詢仍然是遍歷主表的所有數據,但是子查詢中可以使用索引進行查詢,從而大大提高效率。

總結:in與exists應該合理的選擇;而not in和not exists則應該使用not exists代替not in。

優化規則六:or兩邊的字段都是有索引時,盡量使用union進行替代

UNION 操作符用于合并兩個或多個 SELECT 語句的結果集。

請注意,1.UNION 內部的 SELECT 語句必須擁有相同數量的列;2.列也必須擁有相似的數據類型;3.每條 SELECT 語句中的列的順序必須相同。

默認地,UNION 操作符選取不同的值(去除重復值)。如果允許重復的值,請使用 UNION ALL。

清楚其實union連接的兩條語句,如果判斷字段是有索引的,那么會分別進行索引掃描,若兩者都沒有索引,那就相當于兩次全表掃描,效率就還不如or了。

使用union替代or的前提條件在于:作用的兩個列字段都是有索引的,如果都是沒有索引的話,那還不如用or的效率高;還有一點是如果字段相同,所要判斷的值不同的話,使用in的效率比or的更高。

原因在于:使用or時會使引擎不使用索引掃描,而采用全表掃描,這樣效率則極為低下,使用union分開之后,兩個查詢都使用了索引掃描,那么效率很不同了。

empno和ename均有索引的情況下

select?empno,ename,job,sal?from?emp?where?empno?>?7500?OR?ename?LIKE?'S%';??

使用union

select?empno,ename,job,sal?from?emp?where?empno?>?7500???

UNION??

select?empno,ename,job,sal?from?emp?where?ename?LIKE?'S%';??

優化規則七:多使用decode函數來替代IF ELSE和UNION語句

IF ELSE語句主要是繁瑣的嵌套判斷,這就好比我們常用三元運算符來取代if else的判斷,這樣既可以簡化代碼,也可以提高部分效率;

UNION語句主要是連接兩條具有相同輸出結果的SQL語句,本質上來說還是兩條SQL語句的執行,只是將結果進行重復(union)或者不重復(union all)的合并;

而decode函數則是一條SQL語句進行多類型的操作,簡化了需要嵌套判斷的過程(包含三元運算符的意思),也取代了分多條SQL語句進行操作的問題,使用一條SQL就可以解決眾多的問題,一次掃描即可,那么可想而知效率肯定是提高不少的。

使用union解決

select?count(*),SUM(sal)?from?emp?where?deptno=20;??

union??

select?count(*),SUM(sal)?from?emp?where?deptno=30;?

使用decode函數

SELECT?COUNT?(DECODE?(deptno,?20,?'X',?NULL))?dept20_count,??

? ? ? ??COUNT?(DECODE?(deptno,?30,?'X',NULL))?dept30_count,??

? ? ? ??SUM?(DECODE?(deptno,?20,?sal,?0))?dept20_sal,??

? ? ? ??SUM?(DECODE?(deptno,?30,?sal,?0))?dept30_sal??

??FROM?emp;

具體的decode函數的用法,詳見另一筆記《Decode函數的用法》

以下為項目中用到的優化

原生:selectcount(*)fromv_group_dynamic_msg dwhered.group_id=110000000000920andd.crente_date>=(selectm.last_visit_datefromv_grp_member mwherem.psn_id=1000000727052andm.grp_id=d.group_id)

改為exists

優化:selectcount(*)fromv_group_dynamic_msg dwhered.group_id=110000000000920andexists(select1fromv_grp_member mwherem.psn_id=1000000727052andm.grp_id=d.group_idandd.crente_date>=m.last_visit_date)

篩選再判斷

再優化:selectcount(*)fromv_group_dynamic_msg dwhereexists(select1fromv_grp_member mwhered.crente_date>=m.last_visit_dateandm.psn_id=1000000727052andm.grp_id=d.group_id)andd.group_id=110000000000920

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容

  • 望 天空 一無所有 在你離開之后 我收起信箋和筆 寫下這一句詩 經過就會留下 你的訊息 裝作無所謂 笑著讓故事掠過...
    一直兵戈閱讀 139評論 0 1
  • 公交奇遇記(一) 小夢買了一杯黑米豆漿,看到自己要乘坐的公交車來了,趕緊吮吸了一下吸管,掏出一元錢,大吼一聲“師傅...
    奈瀟瀟閱讀 819評論 0 2
  • 一個人在家第三天,除卻人為的播放歌曲的聲音,這房子真讓人耳根清凈。在寂靜中身邊的一切卻變得可喜起來,僅僅是靜靜地看...
    有閑時光閱讀 198評論 0 0