tft每日頭條

 > 圖文

 > oracle如何提高sql效率

oracle如何提高sql效率

圖文 更新时间:2024-06-29 08:04:28

select object_name from t whereobject_id=29;

PGA不同于SGA,它是僅供當前發起用戶使用的私有内存空間,用于用戶連接信息的保存和權限的保存,隻要該會話不斷開連接,下次系統不用再去硬盤中讀取數據,而直接從PGA内存區中獲取。

oracle如何提高sql效率(學習oracle體系并優化sql)1

SQL指令會立即匹配成一個唯一的hash值,該SQL指令進入2區進行處理,首先根據唯一的 hash 值查找SGA區的共享池是否存儲過這個SQL指令,

oracle如何提高sql效率(學習oracle體系并優化sql)2

如果找不到,則:

首先檢查SQL語句語法是否正确(比如from是否寫成了form)、語義是否正确(比如id字段根本就不存在)、是否有權限,沒問題則生成這條語句的唯一的hash值并存儲下來了。

接下來進行解析,比如select object_name from t where object_id=29;在object_id列有索引的情況下,是用索引讀更高效,還是全表掃描更高效呢?

Oracle要做出選擇。Oracle把兩種方式都估算一遍,看哪個代價(Cost)更低,就用哪種。這裡不是真正地分别執行兩次來比較。假設Oracle認定使用索引代價(Cost)更低,于是Oracle就選用了索引讀的執行計劃而放棄了全表掃描方式。接下來這個索引讀的執行計劃就立即被存儲起來,并且和之前存儲的該SQL指令的身份證(唯一hash值)對應在一起。

數據緩存區根據ID列上的索引從t表中查找object_id值為29的記錄,如果記錄不在緩沖區,數據緩存區則取Database數據文件區查找。如果查到了,就帶回數據緩存區,并由展現給用戶,如果找不到,也隻有就此應答。

oracle如何提高sql效率(學習oracle體系并優化sql)3

oracle如何提高sql效率(學習oracle體系并優化sql)4

數據文件查數據

學習體系結構的意義

Oracle 的共享池是為了第一次執行時保存解析過程,避免第二次執行時再做代價高昂的解析。而數據緩存區是為了第一次獲取數據時将這些數據從磁盤讀到數據緩存區,以便第二次可以避開磁盤查找,直接從數據緩存區找到數據,從而避免物理讀。

排序在PGA内存區中操作,如果尺寸裝得下就在内存中完成,否則超出部分會在臨時表空間中完成,造成性能低下。

LGWR 從日志緩存區中把日志寫出,并寫進日志文件,寫滿第1個寫第2個……全部寫完要循環寫的時候,在出現覆蓋日志時要把即将被覆蓋的日志先轉移出去,形成歸檔文件保存起來,用于數據庫的備份與恢複。

假如某數據庫是一個很大的數據庫,數據量龐大,訪問量非常高,而共享池卻非常小,共享池肯定很快就被放滿了,緩存的東西要不斷地被擠出,結果很多 SQL 語句都難以避免硬解析,于是整個數據庫開始運行緩慢。“——加大共享池!

某主機總共才4GB 内存,而運行在其平台上的數據庫是一個幾乎沒有什麼訪問量的小數據庫,可能100MB的共享池就足夠了,卻被開辟了3GB的SGA内存,500MB的PGA内存。但是由于操作系統内存不足,導緻主機運行緩慢,從而導緻數據庫運行緩慢——減少SGA的大小!

果由于數據緩存區過小導緻大數據量的數據庫産生大量的物理讀——在SGA自動管理的情況下,加大SGA的大小,也等同于加大了數據緩存區的大小,這樣數據緩存區夠大,裝的東西就多,物理讀自然就減少了,性能自然就提高了。

如果一個尺寸很大的排序由于内存無法裝下要在磁盤中進行,而操作系統卻閑置着大量的内存未使用——增加PGA的大小,争取容納下排序的尺寸,從而避免物理排序。

如果主機的内存不足,而某特定數據庫幾乎沒有什麼排序的應用——減小PGA,騰出占用的内存分配給操作系統使用。

假如一個數據庫系統存在大量的更新操作,産生了大量的日志需要從RedoBuffer中寫出到日志文件,結果日志寫滿然後切換到下一個日志的頻率不斷加快。切換過程中數據庫需要等待切換完成才可以正常運作,因為切換沒完成,LGWR就無法把Redo Buffer中的數據繼續寫出來,而數據庫中Redo Buffer産生的記錄總是先于數據緩存區産生的,這是串行的順序,那此時數據庫更新的動作就根本不可能成功,一定要等待日志切換成功。在日志頻繁地切換,更新一直在停停走走——日志組的這些日志越大,就越經得住寫,切換就越少,等待時間就越短,所以加大這些日志文件的尺寸

查詢的一緻性問題——當前鏡像無法找回原來的記錄,被覆蓋重寫時就會報錯退出,錯誤号是ORA-01555,Oracle甯願查詢失敗也不願意查詢出錯誤不一緻的結果。

現在某應用系統因為查詢老出ORA-01555錯誤返回不了結果給下一個模塊使用,導緻生産出現故障了——檢查這個語句為什麼執行這麼慢,讓這個語句執行得快一點,就不容易被更新直至覆蓋重寫啊;增大undo_retention的取值,比如寫一個很大的時間,讓回滾段在這段時間内都不允許被覆蓋重寫。

undo_retention隻是參考保留時間并非強制,除非另外設置undo表空間的Retention Guarantee屬性,使之強制保留。此外也可考慮增加undo表空間的大小。

案例

構造環境

oracle如何提高sql效率(學習oracle體系并優化sql)5

存儲過程,實現了将1到10萬的值插入t表的需求

oracle如何提高sql效率(學習oracle體系并優化sql)6

執行腳本

oracle如何提高sql效率(學習oracle體系并優化sql)7

共享池中緩存下來的SQL語句以及hash出來的唯一值,都可以在v$sql中對應的sql_text和sql_id字段中查詢到,而解析的次數和執行的次數分别可以從PARSE_CALLS和EXECUTIONS字段中獲取。

oracle如何提高sql效率(學習oracle體系并優化sql)8

每條語句都隻解析1次,執行1次,解析了10萬次

oracle如何提高sql效率(學習oracle體系并優化sql)9

綁定變量

insert into t values(99898)、insert into tvalues(99762)等這10萬條語句能合并成一種寫法,比如用變量代替具體值,成為insert into t values(:x),那這10萬條語句可以被hash成一個sql_id值,可以做到解析1次,執行10萬次?這樣可以大大減少解析時間。

oracle如何提高sql效率(學習oracle體系并優化sql)10

測試proc2過程(注意,重建表的目的是為了公平,測試都在無記錄的空表上進行,并且共享池都清空)

oracle如何提高sql效率(學習oracle體系并優化sql)11

語句被綁定變量了,解析次數變少了

oracle如何提高sql效率(學習oracle體系并優化sql)12

雖然插入的語句值各不相同,但是都被綁定為:x,所以被hash成唯一一個hash值,名稱為dxz576128adaw,很明顯可以看出解析1次,執行10萬次,這就是速度大幅度提升的原因了。

靜态改寫

execute immediate是一種動态SQL的寫法,常用于表名和字段名是變量、入參的情況,由于表名都不知道,當然不能直接寫 SQL 語句了,所以要靠動态 SQL語句根據傳入的表名參數來拼成一條SQL語句,由executeimmediate調用執行。但是這裡顯然不需要多此一舉,因為insert into tvalues(i)完全可以滿足需求,表名就是t啊。

oracle如何提高sql效率(學習oracle體系并優化sql)13

oracle如何提高sql效率(學習oracle體系并優化sql)14

oracle如何提高sql效率(學習oracle體系并優化sql)15

proc3也實現了綁定變量,而且動态SQL的特點是執行過程中再解析,而靜态SQL的特點是編譯的過程就解析好了。這點差别就是速度再度提升的原因。

批量提交

commit觸發LGWR将Redo Buffer寫出到Redo Log中,并且将回滾段的活動事務标記為不活動,同時在回滾段中記錄對應前鏡像記錄的所在位置,并标記為可以重寫,切記commit可不是寫數據的動作,寫數據将數據從DataBuffer刷出磁盤是由CKPT決定的。

所以commit開銷并不大,單次提交可能需要0.001秒即可完成。另外不管多大批量操作後的提交,僅針對commit而言,也是做這三件事,所花費的總時間不可能超過1秒。打個比方,100萬條更新批量執行後完成commit的提交可能也就需要0.8秒,但是100萬×0.001的時間可是遠大于1×0.8的時間。

oracle如何提高sql效率(學習oracle體系并優化sql)16

測試proc4的性能

oracle如何提高sql效率(學習oracle體系并優化sql)17

集合寫法

oracle如何提高sql效率(學習oracle體系并優化sql)18

oracle如何提高sql效率(學習oracle體系并優化sql)19

原先的一條一條插入的語句變成了一個集合的概念,變成了整批地寫進Data Buffer區裡,

直接路徑

oracle如何提高sql效率(學習oracle體系并優化sql)20

改用create table 的直接路徑方式來新建t表

oracle如何提高sql效率(學習oracle體系并優化sql)21

隻需要10秒即可完成,等同于插入速度為每秒100萬條

insert into t select ……的方式是将數據先寫到Data Buffer中,然後再刷到磁盤中。

create table t 的方式卻是跳過了數據緩存區,直接将數據寫進磁盤,這種方式又稱為直接路徑讀寫方式,因為原本是數據先到内存,再到磁盤,更改為數據直接到磁盤,少了一個步驟,因而速度提升了許多。

直接路徑讀寫方式的缺點在于由于數據不經過數據緩存區,所以在數據緩存區中一定讀不到這些數據,因此一定會有物理讀。但是在很多時候,尤其是海量數據需要遷移插入時,快速插入才是真正的第一目的,該表一般記錄量巨大,DataBuffer甚至還裝不下其十分之一、百分之一,這些數據共享的意義也不大,這時,一般會選擇用直接路徑讀寫的方式來完成海量數據的插入。

設置日志關閉nologging,并且設置parallel 16 表示用到機器的16個CPU,結果在筆記本環境下收效不是很明顯,因為我的環境是單核的機器。後來把如下SQL語句運行在強勁的服務器上,有16個CPU,下面的語句僅僅在4秒不到的時間内就完成了,速度相對于前面的火箭速度而言,快多了,幾乎是每秒300萬條的插入速度

oracle如何提高sql效率(學習oracle體系并優化sql)22

并行最大的缺點就是占用了大多數CPU的資源,如果是一個并發環境,很多應用在運行,因為這個影響了其他應用,導緻其他應用資源不足,将引發很多嚴重問題,所以需要三思而後行,了解清楚該機器是否允許這樣占用大部分資源。

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved