幾個簡單的步驟大幅提高Oracle性能--我優化資料庫的三闆斧。
資料庫優化的讨論可以說是一個永恒的主題。資深的Oracle優化人員通常會要求提出性能問題的人對資料庫做一個statspack,貼出資料庫配置等等。還有的人認為要抓出執行最慢的語句來進行優化。但實際情況是,提出疑問的人很可能根本不懂執行計劃,更不要說statspack了。而我認為,資料庫優化,應該首先從大的方面考慮:網絡、伺服器硬體配置、作業系統配置、Oracle伺服器配置、資料結構組織、然後才是具體的調整。實際上網絡、硬體等往往無法決定更換,應用程式一般也無法修改,是以應該着重從資料庫配置、資料結構上來下手,首先讓資料庫有一個良好的配置,然後再考慮具體優化某些過慢的語句。我在給我的使用者系統進行優化的過程中,總結了一些基本的,簡單易行的辦法來優化資料庫,算是我的三闆斧,呵呵。不過請注意,這些不一定普遍使用,甚至有的會有副作用,但是對OLTP系統、基于成本的資料庫往往行之有效,不妨試試。(注:附件是Burleson寫的用來報告資料庫性能等資訊的腳本,本文用到)
一.設定合适的SGA
常常有人抱怨伺服器硬體很好,但是Oracle就是很慢。很可能是記憶體配置設定不合理造成的。(1)假設記憶體有512M,這通常是小型應用。建議Oracle的SGA大約240M,其中:共享池(SHARED_POOL_SIZE)可以設定60M到80M,根據實際的使用者數、查詢等來定。資料塊緩沖區可以大緻配置設定120M-150M,8i下需要設定DB_BLOCK_BUFFERS,DB_BLOCK_BUFFER*DB_BLOCK_SIZE等于資料塊緩沖區大小。9i 下的資料緩沖區可以用db_cache_size來直接配置設定。
(2)假設記憶體有1G,Oracle 的SGA可以考慮配置設定500M:共享池配置設定100M到150M,資料緩沖區配置設定300M到400M。
(3)記憶體2G,SGA可以考慮配置設定1.2G,共享池300M到500M,剩下的給資料塊緩沖區。
(4)記憶體2G以上:共享池300M到500M就足夠啦,再多也沒有太大幫助;(Biti_rainy有專述)資料緩沖區是盡可能的大,但是一定要注意兩個問題:一是要給作業系統和其他應用留夠記憶體,二是對于32位的作業系統,Oracle的SGA有1.75G的限制。有的32位作業系統上可以突破這個限制,方法還請看Biti的大作吧。
二.分析表和索引,更改優化模式
Oracle預設優化模式是CHOOSE,在這種情況下,如果表沒有經過分析,經常導緻查詢使用全表掃描,而不使用索引。這通常導緻磁盤I/O太多,而導緻查詢很慢。如果沒有使用執行計劃穩定性,則應該把表和索引都分析一下,這樣可能直接會使查詢速度大幅提升。分析表指令可以用ANALYZE TABLE 分析索引可以用ANALYZE INDEX指令。對于少于100萬的表,可以考慮分析整個表,對于很大的表,可以按百分比來分析,但是百分比不能過低,否則生成的統計資訊可能不準确。可以通過DBA_TABLES的LAST_ANALYZED列來檢視表是否經過分析或分析時間,索引可以通過DBA_INDEXES的LAST_ANALYZED列。
下面通過例子來說明分析前後的速度對比。(表CASE_GA_AJZLZ大約有35萬資料,有主鍵)首先在SQLPLUS中打開自動查詢執行計劃功能。(第一次要執行/RDBMS/ADMIN/utlxplan.sql來建立PLAN_TABLE這個表)
通過SET AUTOTRACE ON 來檢視語句的執行計劃,通過SET TIMING ON 來檢視語句運作時間。
請注意上面分析中的TABLE ACCESS(FULL),這說明該語句執行了全表掃描。而且查詢使用了21.38秒。這時表還沒有經過分析。下面我們來對該表進行分析:
表已分析。已用時間: 00: 05: 357.63。然後再來查詢:
請注意,這次時間僅僅用了0.71秒!這要歸功于INDEX(FAST FULL SCAN)。通過分析表,查詢使用了PK_AJZLZ索引,磁盤I/O大幅減少,速度也大幅提升!下面的實用語句可以
用來生成分析某個使用者的所有表和索引,假設使用者是GAXZUSR:
解釋:上面的語句生成了兩個sql檔案,分别分析全部的GAXZUSR的表和索引。如果需要按照百分比來分析表,可以修改一下腳本。通過上面的步驟,我們就完成了對表和索引的分析,可以測試一下速度的改進啦。建議定期運作上面的語句,尤其是資料經過大量更新。
當然,也可以通過dbms_stats來分析表和索引,更友善一些。但是我仍然習慣上面的方法,因為成功與否會直接提示出來。
另外,我們可以将優化模式進行修改。optimizer_mode值可以是RULE、CHOOSE、FIRST_ROWS和ALL_ROWS。對于OLTP系統,可以改成FIRST_ROWS,來要求查詢盡快傳回結果。這樣即使不用分析,在一般情況下也可以提高查詢性能。但是表和索引經過分析後有助于找到最合适的執行計劃。
三.設定cursor_sharing=FORCE 或SIMILAR
這種方法是8i才開始有的,oracle805不支援。通過設定該參數,可以強制共享隻有文字不同的語句解釋計劃。例如下面兩條語句可以共享:
這個方法可以大幅降低緩沖區使用率低的問題,避免語句重新解釋。通過這個功能,可以很大程度上解決硬解析帶來的性能下降的問題。個人感覺可根據系統的實際情況,決定是否将該參數改成FORCE。該參數預設是exact。不過一定要注意,修改之前,必須先給ORACLE打更新檔,否則改之後oracle會占用100%的CPU,無法使用。對于ORACLE9i,可以設定成SIMILAR,這個設定綜合了FORCE和EXACT的優點。不過請慎用這個功能,這個參數也可能帶來很大的負面影響!
四.将常用的小表、索引釘在資料緩存KEEP池中
記憶體上資料讀取速度遠遠比硬碟中讀取要快,據稱,記憶體中資料讀的速度是硬碟的14000倍!如果資源比較豐富,把常用的小的、而且經常進行全表掃描的表給釘記憶體中,當然是在好不過了。可以簡單的通過ALTER TABLE tablename CACHE來實作,在ORACLE8i之後可以使用ALTER TABLE table STORAGE(BUFFER_POOL KEEP)。一般來說,可以考慮把200資料塊之内的表放在keep池中,當然要根據記憶體大小等因素來定。關于如何查出那些表或索引符合條件,可以使用本文提供的access.sql和access_report.sql。這兩個腳本是著名的Oracle專家 Burleson寫的,你也可以在讀懂了情況下根據實際情況調整一下腳本。對于索引,可以通過ALTER INDEX indexname STORAGE(BUFFER_POOL KEEP)來釘在KEEP池中。
将表定在KEEP池中需要做一些準備工作。對于ORACLE9i 需要設定DB_KEEP_CACHE_SIZE,對于8i,需要設定buffer_pool_keep。在8i中,還要修改db_block_lru_latches,該參數預設是1,無法使用buffer_pool_keep。該參數應該比2*3*CPU數量少,但是要大于1,才能設定DB_KEEP_CACHE_BUFFER。buffer_pool_keep從db_block_buffers中配置設定,是以也要小于db_block_buffers。設定好這些參數後,就可以把常用對象永久釘在記憶體裡。
五.設定optimizer_max_permutations
對于多表連接配接查詢,如果采用基于成本優化(CBO),ORACLE會計算出很多種運作方案,
從中選擇出最優方案。這個參數就是設定oracle究竟從多少種方案來選擇最優。如果設定太大,那麼計算最優方案過程也是時間比較長的。Oracle805和8i預設是80000,8建議改成2000。對于9i,已經預設是2000了。
六.調整排序參數
(1) SORT_AREA_SIZE:預設的用來排序的SORT_AREA_SIZE大小是32K,通常顯得有點小,一般可以考慮設定成1M(1048576)。這個參數不能設定過大,因為每個連接配接都要配置設定同樣的排序記憶體。
(2) SORT_MULTIBLOCK_READ_COUNT:增大這個參數可以提高臨時表空間排序性能,該參數預設是2,可以改成32來對比一下排序查詢時間變化。注意,這個參數的最大值與平台有關系。