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