oracle数据库优化--基本概念
oracle性能不好,首要檢查數據庫服務器的硬件配置。包括內存參數調整,oracle9i以后可以在 企業管理器 enterprise manager 中 例程--配置--內存 中查看內存以及pool的大小,通過建議值來設置,該工作應該隔段時間就檢查一次,因為pool的設置和實際的數據量是相關的。
一般windows32位服務器上,分配給oracle的內存不必超過1.7G,因為尋址能力就這么大,多余了也是浪費。整個物理內存的70%應該分配給oracle。
在 例程--配置--內存 中,可以看到共享池share pool,它里面存放的是package,procedure,function,常用sql,以及oracle數據字典等信息。因為這些信息是常用的,置入此內存可以避免經常解析和io讀取,以提高性能。高速緩沖區(SGA)的作用時,將之前查詢的結果集置入次內存,以方面再次查詢時可以直接從內存讀取,減少IO.還有一個PGA的區,是與用戶連接的session有關的,以及用來排序的區域。在8i以前沒個session都回分配一塊內存用來排序,而9i以后,所有用戶session可以共享,這樣避免一個session的pga不夠而另外用戶的pga浪費的情況。
一般來說,數據庫調優順序是:磁盤(讀的次數越少越好,因此需要改變查詢策略,優化查詢sql來減少讀取次數)、網絡(數據庫服務器與應用服務器交互時,如果通過網絡,則網絡帶寬可能會有限制,因為帶寬分上下行,并且還會傳輸其他網絡數據,因此帶寬也是個要考慮的因素)、內存、CPU(后兩者如果太差,性能肯定不好)。
oracle查詢優化方式,兩種:RBO,CBO
RBO rule based optimize 基于規則的優化 8i以前采用。因此關聯查詢中,要注意表的順序
CBO cost based optimize 基于成本的優化 8i(包括)以后采用。與表的順序、where中字段順序無關。
關于索引:
B-TREE索引,結構如下:
root
/ | /
branch1 ........
/|/ ......................
leaf1......
leaf節點的結構是這樣的:
|索引頭|列長度|列內容|rowid(s)|
一個葉子節點的大小大概是8192*8bit,因此一個字段的長度即使是50,那么一個節點大概能分成100個子節點,那么100萬的記錄,也只需要3級節點即可索引完畢,因此一般b-tree的深度不超過4級,這樣根據b-tree來查找一條記錄,最多只需遍歷4個節點找到rowid,再根據rowid查找磁盤即可得到最終記錄數據。
對某列查詢的結果集記錄數如果通常都小于7%,則應該在該列添加索引。對b-tree來說,where xx is null條件是不會利用索引的,因此建議這種列應該設置默認值,以避免該列的值存在null的情況,同樣group by 中如果該列有null索引也可能無效。
bitmap索引:
bitmap索引的結構也是樹形結構,但是葉子節點的結構與b-tree不一樣。bitmap葉子節點的結果大概如下:
<key1 start-rowid end-rowid bitmap>
<key2 start-rowid end-rowid bitmap>
......
其中bitmap的內容是110010100011100001這樣的01組合形式,它的長度與start-rowid和end-rowid之間包含的rowid數量一致。這樣假設范圍內第9個rowid對應列的內容是key1,那么kei1對應的bitmap中第9個字符的值就是1,否則就是0。同樣每個塊的大小是8192*8,那么一個bitmap索引的葉子節點大概能索引10000條記錄。
bitmap索引對null的字段依然有效,具體null的值在bitmap中是取0還是專門有個keyX的值是null來區分需要再查證。bitmap索引對or條件的查詢效果非常好,它不適應與索引列的值經常變化的情況,如果索引列的值經常變化,那么對bitmap索引將是災難性的,因為它要鎖定所有相關的葉子節點所在的塊來更新bitmap的值,它適用于決策支持系統。
函數索引:是b-tree索引的一種
函數索引需要注意的是,實際sql中用到的函數掩碼的格式、大小寫需要與簡歷索引中函數掩碼的格式、大小寫一致,否則函數索引可能無效。另外trunc(),trim[可以采用ltrim(rtrim(col_xxx))的方式來避免bug]索引可能會有不正常的情況,may be bug。建立函數索引需要當前用戶有query rewrite的權限才能建立。
因為函數分為確定性函數和非確定性函數,因此建立函數索引只能建立在確定性函數上。確定性函數的意思是:針對同一個傳入值,該函數將在任何時候任何情況下都返回一個確定的結果。
reverse索引:反轉索引 是函數索引的一種
它通過反轉記錄的值,來得到高效的查詢性能。在特殊的一些列中可以采用。
為表添加索引并執行analyze分析(后面會提到分析方式)后,執行執行某個sql時,數據庫將根據分析的結果來確定它認為最優化的方式讀取數據庫得到最終結果,這種基于成本的優化由數據庫自動完成。如果要強制某個sql優先采用某個索引,可以添加hint來實現,即sql書寫成如下格式:
select /*index(user1.index_xxxx)*/ from table11 where .... 這樣實際執行中會優先采用user1.index_xxxx這個索引,其中user1表示索引所在的owner,index_xxxx表示索引的名稱(而不是索引列的名稱)
為優化查詢,一個規則是:盡早過濾更多的數據
通過plsql developer軟件,view一個table,在general選項卡中,可以看到 Initial extent/next extent/%increase/max extent等內容,這些內容界定了該table的擴展大小方式等。initail extent表示初始大小,next extent表示當前extent不夠用時下次增加的extent大小,%increase表示增加的比例,max extent表示最多可擴展的次數。其中next extent 和%increase的設置需要注意,因為此二者是相關的,如果擴展次數較多時,可能會發現next extent的變得非常大,甚至上G都有可能。
在plsql developer中,新建一個explain plan window(執行計劃窗口),將實際要執行的sql輸入到窗口中,再按F5或者F8,則將顯示數據庫基于成本的執行計劃。第一列description中,顯示了實際查詢會通過全表掃描還是索引等,一般來說全表掃描必將導致性能下降。其中最后三列值得注意:
cost 表示成本,通過數據庫io訪問和cpu性能計算得來
cadinality 根據遍歷索引或者全表掃描的記錄計算得來
bytes 表示訪問的數據量
一個優化后的sql查詢,以上3個值應該是越小越好。
oracle10g以后,oracle將會自動分析各個table,以便每次執行查詢時都能獲得最佳速度。之前版本必須手工分析(后面會提到分析方式)。
高水平線概念:
每個table有個高水平線,它將記錄該table最后一次extent的塊的最后一個點的物理地址,如rowid.實際執行全表掃描時,將掃描table的起點到該高水平線之前所有的數據塊。因此即使對改表執行了delete操作,這些delete的記錄會有一個標記標志其已經刪除,但是全表掃描依然會掃描這些即使delete掉的數據塊,因此會影響性能。所以如果要刪除一個表的全部記錄,應該采用truncate關鍵字,必要的時候可以重建改表 alter table xxx rebuild;
分析表 analyze :
執行分析的語句是
全表分析:analyze table xxx compute statistics;
分析5%的數據(速度更快)以及特定列和索引:analyze table xxx estimate statistics sample 5 percent for table for all indexes for all indexed columns;
執行analyze后,oracle會將分析結果存入數據字典中,而數據字典會存在共享池share pool中,因此執行sql時會馬上查詢該數據字典并得到優化的執行路徑從而快速得到查詢結果。
關于綁定變量:
看下面這段代碼:
declare
v_aa varchar2(2);
v_temp number :=0;
v_aa :='00';
select col_22 into v_temp from table_xx where col_11 =v_aa;---sql1
....
v_aa :='01';
select col_22 into v_temp from table_xx where col_11 =v_aa;---sql2
....
上述代碼中v_aa就是采用了綁定變量的方式,可以看到,以上sql1和sql2一模一樣,oracle在實際執行時,只需要在執行sql1時做詞法、語法、編譯、安全檢查等分析,而執行sql2時,它會發現該sql已經在共享池share pool中存在了,因此就省去了詞法、語法、編譯、安全檢查等分析等分析過程,從而提高性能。但是很多時候,我們采用的是如下方式:
select col_22 into v_temp from table_xx where col_11 ='00';---sql1
select col_22 into v_temp from table_xx where col_11 ='01';---sql2
結果oracle不認為這兩個sql是一致的,因此執行sql2之前又會做詞法、語法、編譯、安全檢查等分析,則性能下降。
在實際程序開發中,如java中,我們建議采用perparedstatement就是這個原理。而在oracle過程函數中,游標是會默認的被認為是綁定變量方式的,因此如果采用了游標,就不必專門再定義一個變量來利用該策略。
但是有時候綁定變量可能也會導致性能下降,如某表有10萬條記錄,其中性別這一列分男、女兩個值。如果使用了綁定變量where gender= v_gender 的方式,oracle可能會采用全表掃描的方式來查詢(why?),而如果采用了硬編碼where gender='男'的方式,則直接利用了gender列上的索引則會非常快。
柱狀圖分析
對某一列進行柱狀圖分析,將會得到該列各種值存在的比例,從而可以避免綁定變量方式可能帶來的低效.
關于全索引:
如果某個查詢的結果以及where中條件列都在一個索引里面,則可以利用上全索引方式來達到高效。如:
select a,b from t_xxxx where id='zz'非常的慢,而這種sql又會經常頻繁的執行,則可以添加一個索引:id,a,b(條件列id要放在第一位)這種全索引。這樣執行上述sql時,只需要檢索索引就能得到結果,而索引的查詢是非常高效的。在9i之前,這種索引需要注意字段的順序。
物化視圖:meterialized view
要創建物化試圖,必須enable query rewrite
物化試圖的刷新方式有 fast、complete 方式。物化視圖會將視圖的結果集存入一個table中固化,并且可以在table上添加索引,因此能提高性能。實際運用mview時,可以直接查詢mview對應的固化table,也可以查詢與mview創建語句條件一致的原始表,oracle會自動從mview對應的table來做檢索,而不會檢索原始表。
視圖的聯合方式:交叉型、星型
如4個表的一個聯合,則實際聯合方式可能是
tab1------tab2
| |
| |
tab3------tab4
也可能是
tab1----tab2----tab3
|
|
tab4
不同的聯合方式,每次兩兩聯合過濾的數據不一樣,則速度也可能不一樣。
關于toad工具中比較有用的幾個點:
如
dba-healthy check,能查詢出數據命中率、緩存丟失率等。
最大緩存命中率應該>95%的才算好,否則說明必須要進行調整了
庫緩存、字典緩存丟失率應該是0才好
分區數據占用率應<5%
dba-server statistics
tols-sga-trace等
數據分區:
通常一個表的記錄超過1千萬就應該考慮采用分區的方式。分區相當于將一個大表分成很多個小表
分區方式有:hash(計算出列的hash值來根據hash值分區)
range(范圍分區)-----》list(從range引申出來的方式)
分區也是在某個字段上進行的,分區后再添加索引,必須添加分區索引而不是全索引
符合分區時,可以采用先range再hash或者先list再hash的方式,符合分區不能采用先hash再xx的方式。
將經常訪問的枚舉、字典、對照表置入緩沖區能提高性能
8i以前:alter table xxx cache;
8i后:alter table storage (buffer_pool keap);
緩存有三種方式:
default:默認方式,置入緩存中,如果緩存空間不夠,根據某種算法可能會被移出緩存
keep:一直放入keep池中,始終不會清除
recycle:只要空間不夠,就會清除。因此比default方式的更容易被清除。
總結
以上是生活随笔為你收集整理的oracle数据库优化--基本概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: window mobile 防止系统休眠
- 下一篇: 一道经典的SQL面试题