Posted on 2011-08-18 11:52
瘋狂 閱讀(2713)
評論(0) 編輯 收藏 所屬分類:
database
SGA
系統全局區--System global area(SGA) 是一組共享的內存結構,它里面存儲了oracle數據庫實例(instance)的數據和控制文件信息。如果有多個用戶同時連接到數據庫,他們會共享這一區域,因此SGA也稱之為Shared Global Area。當數據庫實例啟動時,SGA的內存被自動分配;當數據庫實例關閉時,SGA內存被回收。
SGA是占用內存最大的一個區域,同時也是影響數據庫性能的重要因素。
SGA主要包括以下幾部分:
? 共享池
? 數據緩沖區
? 大型池
? Java池
? 日志緩沖區
上面幾部分內存加起來,就是SGA內存的總和。其中比較重要的是共享池和數據緩沖區,后面將會重點講解它們。
3.2.1 查看SGA
SGA是可以動態調整大小的,也就是說調整其大小是不用shutdown數據庫的。在初始化參數中設置可以設置sga_max_size這個參數,當SGA的各部分的和要大于設置的sga_max_size的參數的時候,設置的sga_max_size將會被忽略掉,而是將各部分的大小相加。當sga_max_size的大小大于各部分的大小相加時,會使用sga_max_size的參數。
SGA是占用內存最大的一個區域,同時也是影響數據庫性能的重要因素。
通過下面的命令來查看SGA:
show parameter sga;
結果如下圖:
SGA" alt="Oracle SGA" src="http://s7.sinaimg.cn/bmiddle/5421dfd2t770c7284c446&690">
sga_max_size的值就是SGA的大小,從上圖可以看出sga_max_size的大小是256M。
3.2.2 修改SGA
要修改SGA的大小,應使用以下命令:
alter system set sga_max_size=164M scope=spfile;
這里我修改為164M,你可以改成你想要的大小。由于sga_max_size是一個靜態參數,不能夠在運行時修改,因此這里的scope只能設置為spfile,新的內存大小將在Oracle重啟后生效。
結果如下圖:
SGA" alt="Oracle SGA" src="http://s1.sinaimg.cn/bmiddle/5421dfd2t724e0bd6aa40&690" real_src="http://s1.sinaimg.cn/bmiddle/5421dfd2t724e0bd6aa40&690">
3.2.3 共享池
共享池是對SQL,PL/SQL程序進行語法分析,編譯,執行的內存區域。
它包含三個部分:
? 庫緩沖區(Library Cache)包含SQL,PL/SQL語句的分析碼,執行計劃;
? 數據字典緩沖區(Data Dictionary Cache)表,列定義,權限;
? 用戶全局區(Usr Global Area)用戶MTS會話信息。
這三個部分都不可單獨定義大小,必須通過共享池間接定義。
你可能會問,為什么要緩存SQL語句呢?不緩存又能怎么樣呢?要想搞清楚這個問題,我們要先了解一個SQL在Oracle里的執行過程。
3.2.3.1 SQL執行過程
在Oracle里執行一個SQL語句,一般都要經過下面幾個步驟:
? Create a Cursor 創建游標;
? Parse the Statement 解析語句;
? Bind Any Variables 綁定變量;
? Run the Statement 運行語句;
? Close the Cursor 關閉游標;
如果是一個查詢SQL,則還要經過下面的步驟:
? Describe Results of a Query 描述查詢的結果集;
? Define Output of a Query 定義查詢的輸出數據;
? Fetch Rows of a Query 獲取查詢出來的行。
3.2.3.2 SQL解析過程
從上面的步驟可以看出,每執行一個SQL,都需要對它進行解析(Parse),而一個解析過程,需要完成下面的工作:
? 語法檢查,驗證它是否是合法的語句,有沒有語法錯誤;
? 語義檢查,實現數據字典的查找,以驗證是否符合表和列的定義,類型是否正確;
? (如果是CBO優化模式,關于CBO,請看后面Oracle的優化器一章)收集參考對象的統計;
? 在所要求的對象上獲取語法分析鎖,使得在語句的語法分析過程中不改變這些對象的定義;
? 檢查用戶的權限是否足夠;
? 從許多可能的執行路徑中選擇此語句最佳的執行計劃;
? 將它裝入共享SQL區;
? 生成語句的編譯版本(P-CODE)。
解析是一個昂貴的操作,因為解析過程中需要消耗許多資源,而且費時,正因為如此,Oracle創造了共享池的概念,共享池會自動將解析過的SQL緩存起來,以后碰到相同的SQL,就不用再解析了,這樣可以大大提高SQL的執行速度。
3.2.3.3 緩存SQL的原理
ORACLE執行SQL語句時,先將SQL語句的字串通過一個hash算法得出一個hash值,然后檢查共享池中是否已存在這個哈希值,若有就用已緩存的執行計劃來執行這個語句(即緩存命中,后面我們會提到共享池的命中率,就是這個概念),若沒有(即緩存缺失)則需進行解析。
由于Oracle是通過SQL字符的hash值來判斷是否為相同的SQL語句,因此,如果你的SQL有一點小小的變換,在Oracle看來,就是另外一個SQL了,會對它進行重新解析。
例如:
- select id, name from members where id = 1403
- select id, name From members where id = 1403
- select name, id from members where id = 1403
這三條SQL在Oracle看來就是三條不同的SQL。
3.2.3.4 綁定變量
在大部分時候,sql語句里有一些經常會變化的值。例如:
- select id, name from members where id = 1207
- select id, name from members where id = 1208
- select id, name from members where id = 1209
前面說過了,這樣的SQL其實是三條不同的SQL,因為它們的字符明顯不一樣。那我們該怎么樣才能讓它們成為同一條SQL呢?可以通過綁定變量來實現。
下面是一條含綁定變量的sql 語句:
- select id, name from members where id = :member_id
這樣不管member_id如何變化,Oracle都會認為這條SQL是同一條,就可以節省解析的成本了。
那么,在java開發中,怎么使用綁定變量呢?注意,不要認為下面的代碼是在使用綁定變量:
- Statement stmt=conn.createStatement();
- String member_id=member.id;
- String sql="select id,name from members where id ="+member_id;
- stmt.executeQuery(sql);
上面的例子里,當member.id的值為1207時,我們傳給stmt的SQL實際上是:
- select id, name from members where id = 1207
當member.id的值為1208時,就是:
- select id, name from members where id = 1208
它們在Oracle看來仍然是不同的SQL。
其實,在java中使用綁定變量非常簡單,只需要使用PreparedStatement對象就可以了。如下:
- String sql="select id,name from members where id =?";
- PreparedStatement pstmt=conn.createStatement(sql);
- pstmt.setString(1,member.id);//將member.id傳給第一個問號。
這樣,PreparedStatement會自動把這條SQL在傳給Oracle時轉化為類似下面的SQL:
- select id, name from members where id = :member_id
這樣就實現了綁定變量,它只需解析一次,不管member.id如何變化,都不用再做解析了。
我們使用的Hibernate,內部就是使用PreparedStatement來處理的,因此,我們不需要為使用綁定變量做任何事情,Hibernate已經幫我們做好了。
3.2.3.5 查看共享池
通過下面的命令查看共享池內存的大小:
- show parameter shared_pool_size;
結果見下圖:
SGA" alt="Oracle SGA" src="http://s3.sinaimg.cn/bmiddle/5421dfd2t770c782b44b2&690" real_src="http://s3.sinaimg.cn/bmiddle/5421dfd2t770c782b44b2&690">
3.2.3.6 修改共享池
通過下面的命令可以修改共享池內存的大小:
- alter system set shared_pool_size=90M scope=both; (這個我沒有執行成功)
shared_pool_size是一個動態參數,可以在運行時修改,因此這里的scope設置為both,新的內存大小馬上生效,并且還將修改保存在Oracle的啟動文件里。
3.2.3.7 查看共享池命中率
共享池命中率可以反映出SQL重復使用率的高低,命中率越高,說明SQL重復使用率越高,也就是節省的SQL解析時間越多,反映在系統上就是查詢數據越快。
可以通過以下命令查看命中率:
- select sum(pinhits) / sum(pins) * 100 "看命中率咯" from v$librarycache;
結果如下圖:
SGA" alt="Oracle SGA" src="http://s4.sinaimg.cn/bmiddle/5421dfd2t770c79207443&690" real_src="http://s4.sinaimg.cn/bmiddle/5421dfd2t770c79207443&690">
如果命中率低于95%,則要考慮調整共享池大小。我們知道,如果沒有在程序里使用綁定變量,那么就算共享池再大,也不會有什么好的效果,反而會有副作用。因此,更重要的事情是把使用最多的SQL改成綁定變量,你將會看到明顯的效果。
3.2.4 數據緩沖區
如果每次執行一個操作時,Oracle都必須從磁盤讀取所有數據塊并在改變它之后又必須把每一塊寫入磁盤,顯然效率會非常低。數據緩沖區存放需要經常訪問的數據,供所有用戶使用。修改數據時,首先從數據文件中取出數據,存儲在數據緩沖區中,修改/插入數據也存儲在緩沖區中,commit或DBWR(下面有詳細介紹)進程的其他條件引發時,數據被寫入數據文件。數據緩沖區的大小是可以動態調整的,但是不能超過sga_max_size的限制。
3.2.4.1 查看數據緩沖區
通過下面的命令查看數據緩沖區內存的大小:
- show parameter db_cache_size;
結果見下圖:
SGA" alt="Oracle SGA" src="http://s9.sinaimg.cn/bmiddle/5421dfd2t724e0c32f7b8&690" real_src="http://s9.sinaimg.cn/bmiddle/5421dfd2t724e0c32f7b8&690">
3.2.4.2 修改數據緩沖區
通過下面的命令可以修改數據緩沖區內存的大小:
alter system set db_cache_size=50M scope=both;
db_cache_size是一個動態參數,可以在運行時修改,因此這里的scope設置為both,新的內存大小馬上生效,并且還將修改保存在Oracle的啟動文件里。
3.2.4.3 查看數據緩沖區命中率
數據緩沖區也有一個命中率的概念,一般要求命中率在90%或95%以上,如果你的命中率過低,說明你的數據庫效率很低,需要調整數據緩沖區的大小。
可以通過下面的命令查看命中率:
- select (1 - ((physical.value - direct.value - lobs.value) / logical.value)) * 100 "命中率"
- from v$sysstat physical,
- v$sysstat direct,
- v$sysstat lobs,
- v$sysstat logical
- where physical.name = 'physical reads'
- and direct.name = 'physical reads direct'
- and lobs.name = 'physical reads direct (lob)'
- and logical.name = 'session logical reads';
結果如下:
SGA" alt="Oracle SGA" src="http://s8.sinaimg.cn/bmiddle/5421dfd2t770c7c5a49b7&690" real_src="http://s8.sinaimg.cn/bmiddle/5421dfd2t770c7c5a49b7&690">
轉自:http://blog.sina.com.cn/s/blog_5421dfd20100ffn8.html