SGA(SYSTEM Global Area )系統全局區
l 數據高速緩存
在Oracle進行數據處理的過程中,代價最昂貴的就是物理 I/O操作了。同樣的數據從內存中得到要比從磁盤上讀取快的多。因此,優化Oracle的一個重要的目標就是盡可能的降低物理 I/O操作。
Oracle的 Buffer Cache用於緩存從磁盤中讀取的數據,當 Oracle需要查找某些信息的時候,首先會在 BufferCache中尋找,如果找到了,則直接將結果返回。如果找不到,則需要對磁盤進行掃描, Oracle將在從磁盤掃描得到的結果返回的同時,會把這些數據在Buffer Cache中也保留一份,如果下次需要訪問相同的數據塊的時候,則不需要再次掃描磁盤,而是直接從 Buffer Cache中讀取即可。
2 數據高速緩存由初始化參數DB_CACHE_SIZE指定大小,由許多大小相等的緩存塊組成,這些緩存塊的大小和OS塊大小相同。這些緩存塊分為 3 大類:
n 髒緩存塊(Dirty buffers ):
髒緩存塊中保存的已被修改過的緩存塊。即當一條SQL語句對某個緩存塊中的數據進行修改後,該緩存塊就被標記為髒緩存塊。最後,髒緩存塊被DBWn進程寫入到硬盤的數據文件中,永久保留起來。
n 命中緩存塊(Pinned buffers ):
命中緩存塊中保存的是最近正在被訪問的緩存塊。它始終被保留在數據高速緩存中,不會被寫入數據文件。
n 空閒緩存塊(Freebuffers):
該緩存塊中沒有數據,等待被寫入數據。oracle從數據文件中讀取數據後,尋找空閒緩存塊,以便寫入其中。
2 標准數據庫緩沖區緩存分為以下三種:
n 保持(keep)緩沖池:長期保存在內存中,直到數據庫被關閉為止,其大小由BUFFER_POOL_KEEP指定。
n 再生(recycle)緩沖池:數據一旦用畢後就被換出內存中,其大小由BUFFER_POOL_RECYCLE指定。
n 默認(default)緩沖池:數據使用LRU調度算法來換出,其大小由DB_CACHE_SIZE 決定。
2 工作原理和過程LRU(最近最少使用 Least Recently Used )。Oracle通過 2 個列表(DIRTY、LRU)來管理緩存塊。
n DIRTY 列表中保存已經被修改但還沒有被寫入到數據文件中的髒緩存塊。
n LRU 列表中保存還沒有被移動到DIRTY列表中的髒緩存塊、空閒緩存塊、命中緩存塊。當某個緩存塊被訪問後,該緩存塊就被移動到LRU列表的頭部(Most Recent Used, MRU端),其他緩存塊就向LRU列表的尾部(Least Recently Used, LRU 端)移動。放在最尾部的緩存塊就最先被移出LRU列表。
說明:如果用戶執行的是全表掃描的操作,這些操作產生的數據緩沖不會放到 LRU端的 MRU端,而是放到LRU端。因為Oracle認為全表掃描得到的數據只是暫時的需要,這些數據以後被重用的機會很少,應該快速的清除出緩沖區,把空間留給其他的更常用的數據。可以在表的級別上改變這種處理方式。在建表的時候指定Cache語句會使得這張全表掃描得到的數據也放在 LRU鏈表的 MRU端。
n 數據高速緩存的工作原理過程是:
A、ORACLE在將數據文件中的數據塊復制到數據高速緩存中之前,先在數據高速緩存中找空閒緩存塊,以便容納該數據塊。Oracle 將從LRU列表的尾部開始搜索,直到找到所需的空閒緩存塊為止。
B、如果先搜索到的是髒緩存塊,則將該髒緩存塊移動到DIRTY列表中,然後繼續搜索。如果搜索到的是空閒緩存塊,則將數據塊寫入,然後將該緩存塊移動到DIRTY列表的頭部。
C、如果能夠搜索到足夠的空閒緩存塊,就將所有的數據塊寫入到對應的空閒緩存塊中。則搜索寫入過程結束。
D、如果沒有搜索到足夠的空閒緩存塊,ORACLE就先停止搜索,激活DBWn進程,開始將DIRTY列表中的髒緩存塊寫入到數據文件中。
E、已經被寫入到數據文件中的髒緩存塊將變成空閒緩存塊,並被放入到LRU列表中。執行完成這個工作後,再重新開始搜索,直到找到足夠的空閒緩存塊為止。
2 KEEP池和 RECYCLE池的使用
如果內存足夠大,可以容納所有的數據,則訪問任何數據都可以從內存中直接獲得,那麼效率肯定是最高的。但是在實際應用當中,經常是數據庫的大小達到了幾百個 GB甚至是幾個 TB,而 Oralce的可用內存只有幾個 GB大小。緩存中緩存的數據只能占到整個數據庫數據的很小一部分,因此,這就要求必須合理的分配內存的使用。
如果可使用的內存空間比較小,導致數據庫緩沖區的命中率比較低,則可以通過配置 KEEP池和 RECYCLE池,把性質不同的表分離到不同的數據緩沖區,以提高命中率,降低此操作對正常訪問的影響。
默認情況下,所有的表都是用 default池,它的大小就是緩沖區Buffer Cache的大小,由初始化參數 db_cache_size來決定。如果在建表或者修改表的時候指定 STORAGE(BUFFER_POOLKEEP)或者 STORAGE(BUFFER_POOLRECYCLE)語句,就設置這張表使用 KEEP或者 RECYCLE緩沖區。這兩個緩沖區的大小分別由初始化參數 db_keep_cache_size和db_recycle_cache_size來決定。
通過下面的sqlplus命令查看帶“cache_size”字符串的系統參數值
SQL> show parametercache_size
結果如下:
db_16k_cache_size big integer 0
db_2k_cache_size big integer 0
db_32k_cache_size big integer 0
db_4k_cache_size big integer 0
db_8k_cache_size big integer 0
db_cache_size big integer 0 --屬於SGA自動管理組件,值為0.
db_keep_cache_size big integer 0
db_recycle_cache_size big integer 0
SQL> alter system set db_keep_cache_size=16Mscope=both;
SQL> alter system setdb_recycle_cache_size=16M scope=both;
SQL> show parametercache_size
db_16k_cache_size big integer 0
db_2k_cache_size big integer 0
db_32k_cache_size big integer 0
db_4k_cache_size big integer 0
db_8k_cache_size big integer 0
db_cache_size big integer 0 --屬於 SGA自動管理組件,值為0.
db_keep_cache_size big integer 16M
db_recycle_cache_size big integer 16M
n KEEP池
KEEP池用來緩存那些經常會被訪問的表。
KEEP池使用緩沖區獨立於DEFAULT池,因此把最經常使用的表緩存到單獨的緩沖區中,使得數據庫的其他操作,如執行大量批操作也不會影響到這些在 KEEP緩沖區中的表,保證訪問這些最常使用的表的數據時,都可以從內存中直接獲得。
SQL> col name format a30
SQL> col value format a30
SQL> conn scott/scott
SQL> create tabletest_default(col number(3)) storage(buffer_pool default);
SQL> create tabletest_keep(col number(3)) storage(buffer_pool keep);
SQL> create table test_recycle(colnumber(3)) storage(buffer_pool recycle);
SQL> insert intotest_default values(1);
SQL> insert into test_keepvalues(1);
SQL> commit;
SQL> set autotrace on statistics
SQL> select * fromtest_default;
統計信息
1 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> select * fromtest_keep;
統計信息
1 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> show sga
Total System Global Area 528482304 bytes
Fixed Size 1249944 bytes
Variable Size 150998376 bytes
Database Buffers 369098752 bytes
Redo Buffers 7135232 bytes
SQL> select369098752/1024/1024 from dual; --計算DatabaseBuffers的大小為352M
在上面的例子中,建立了兩張表。 Test_default指定默認的default池,test_keep指定了keep池。分別插入了一條數據,然後打開自動跟蹤,對這兩張表進行查詢,由於剛剛執行了 INSERT語句,這兩條數據都存放在各自的緩沖區中,因此查詢的物理讀(physical reads)為 0,接著查看 buffer cache的值,發現大小為352M,SGA為 504M。
下面構造一個較大的批操作,插入的數據大於 504M,將 default區域覆蓋掉。
SQL> create tabletest_eat_memory (col1 varchar2(4000), col2 varchar2(4000), col3 varchar2(4000),col4 varchar2(4000), col5 varchar2(4000), col6 varchar2(4000), col7varchar2(4000), col8 varchar2(4000), col9 varchar2(4000), col10 varchar2(4000))storage(buffer_pool default);
SQL> insert intotest_eat_memory select rpad('1',4000,'1'), rpad('2',4000,'2'), rpad('3',4000,'3'),rpad('4',4000,'4'),rpad ('5',4000,'5'), rpad('6',4000,'6'), rpad('7',4000,'7'),rpad('8',4000,'8'), rpad('9',4000,'9'), rpad('0',4000,'0') from all_objectswhere rownum<=15000; --插入15000行數據
統計信息
10410 recursive calls
564195 db block gets
108584 consistent gets
620 physical reads
637527688 redo size --大約插入了638M數據
678 bytes sent via SQL*Net to client
803 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
91 sorts (memory)
0 sorts (disk)
15000 rows processed
SQL> commit;
執行完批操作後,對兩張表再次查詢。
SQL> select * fromtest_default;
統計信息
70 recursive calls
0 db block gets
13 consistent gets
12 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> select * fromtest_keep;
統計信息
70 recursive calls
0 db block gets
13 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
rows processed
SQL> show sga
Total System Global Area 528482304 bytes
Fixed Size 1249944 bytes
Variable Size 150998376 bytes
Database Buffers 369098752 bytes --default區域沒有變化
Redo Buffers 7135232 bytes
結果很明顯。由於 keep和 default池彼此獨立,對於 test_keep的查詢的物理讀仍然為0,而對 test_default的查詢則包含了12個物理讀。
上面的例子可以看出,使用 keep池可以保證那些指定 keep池的表不受其他表的影響。可以查詢v$bh視圖來查找到經常被使用的表,根據表的使用頻繁度來確定是否指定 keep池。
select o.object_name, count(*)from dba_objects o, v$bh bh where o.object_id = bh.OBJD and o.owner != 'SYS'group by o.object_name having count(*) > 100 order by count(*) desc
確定好使用 keep池的表後,可以根據這些表的實際大小之和來計算緩沖區的大小。由於這個大小可以比較准確的計算出來,因此可以對這些表使用 cache,以保證即使采用全表掃描得到的數據也可以被緩沖。
通常情況下,並不追求 keep池的命中率達到 100%,如果命中率為 100%,則說明給 keep池的內存空間過大,有部分內存被浪費。即使 keep池中緩存的都是些最經常訪問的表,這些訪問操作也不大可能訪問到表中所有的數據。因此,可以適當的減少 keep池的內存分配,使 keep池的命中率維持在接近 100%的數值。將這部分內存分配給其他的緩沖區,可以得到更高的效率。
可以采用下面的SQL語句來計算 KEEP池的命中率。
SQL> select name,physical_reads, db_block_gets, consistent_gets, 1 -(physical_reads /(db_block_gets + consistent_gets)) "hit ratio" fromv$buffer_pool_statistics where name = 'KEEP';
n RECYCLE池
RECYCLE池用來緩存那些不希望保存在內存中的表。例如很少進行掃描或者訪問的表。如果應用程序以一種隨機的方式訪問一張比較大的表,這些被緩沖的數據在被清除出內存之前,很少會有機會再次被訪問。這些數據存放在緩沖區當中,不僅會浪費內存空間,而且可能把其他的一些有可能被訪問的數據清除出去。這些數據沒必要保存在緩沖區當中,可以通過使用 RECYCLE池來避免這些數據對其他數據的影響。
調整參數db_recycle_cache_size的大小來設置recycle池。一般來說,不需要給 recycle池很大的內存空間,因為recycle池中的數據沒有什麼被緩存的價值。設置較小的緩沖區可以將更多的內存留給keep 和default池。但是,如果緩沖區太小的話,數據可能在事務結束之前就從內存從中被清除了,這會導致額外的性能問題。
SQL> truncate tabletest_eat_memory;
SQL> select * fromtest_default;
統計信息
0 recursive calls
0 db block gets
7 consistent gets
0 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL> alter tabletest_eat_memory storage(buffer_pool recycle);
SQL>insert intotest_eat_memory select rpad('1',4000,'1'), rpad('2',4000,'2'), rpad('3',4000,'3'),rpad('4',4000,'4'),rpad ('5',4000,'5'), rpad('6',4000,'6'), rpad('7',4000,'7'),rpad('8',4000,'8'), rpad('9' ,4000,'9'), rpad('0',4000,'0 ) from all_objectswhere rownum<=15000; --插入15000行數據
統計信息
10410 recursive calls
564195 db block gets
108584 consistent gets
620 physical reads
637527688 redo size --大約插入了638M數據
678 bytes sent via SQL*Net to client
803 bytes received via SQL*Net from client
4 SQL*Net roundtrips to/from client
91 sorts (memory)
0 sorts (disk)
15000 rows processed
SQL> commit;
SQL> select * fromtest_default;
統計信息
70 recursive calls
0 db block gets
0 consistent gets
12 physical reads
0 redo size
407 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
rows processed
在這個例子中,將進行批操作的表改為recycle池,在批操作執行完成後,發現 test_default表的數據仍然可以在default池中找到。這種方法屏蔽了批操作對系統的影響。
小結
對於大多數的系統而言,使用 default池就夠了。但是如果內存空間相對較小,或者對系統中表的使用情況有比較清晰的認識,則可以通過配置 keep池和 recycle池來細化內存的分配,提高數據緩沖區的命中率,降低批操作對系統的影響。
雖然 keep池、recycle池用來緩存不同類型的數據,但是他們的機制是相同的,他們采用的都是LRU算法。如果keep池分配的內存不足,那麼也會有部分數據被清除出內存;如果 recycle池的內存分配足夠,也可以保證其中的數據全部緩存。從本質上講, keep池和 recycle池並沒有什麼區別,只是名字不同而已。
如果給 keep池或者 recycle池分配的內存大小不合適,不但不會提高性能,而且會造成性能的下降。以 keep池為例,內存分配小了,這些經常被訪問的、數據就會有部分被清除出內存,導致命中率降低。如果內存分配過大,則導致 default池內存要相應的減少,default池不僅包括用戶部分數據,而且也包括數據字典的緩沖。因此, default池內存的不足,必然導致整個系統性能的下降。而且,由於真實環境中,所有的表的大小都處於變化之中,因此,需要經常對不同緩沖區的命中率進行檢查,並隨時調整緩沖區的大小以滿足數據不斷變化的需要。
l 重做日志高速緩存
2 重做日志高速緩存大小由初始化參數LOG_BUFFER指定,可以在運行期間修改該參數。
2 工作原理:為了加快訪問速度和工作效率,重做記錄並不直接寫入重做日志文件中,而是首先從數據高速緩存寫入重做日志高速緩存。當重做日志高速緩存中的重做記錄達到一定數量或某個時間點時,再由LGWR進程分批寫入重做日志文件中(即ORACLE 總是先日志後文件或先內存後磁盤)。由於重做日志文件是循環使用的,所以當重做日志文件切換時,還會由ARCn(如果啟用了歸檔日志模式)進程將即將要被覆蓋的重做日志文件中的數據寫入到歸檔日志文件中,作為備份。
SHOWPARAMETER LOG_BUFFER; ------查詢重做日志緩存的大小
SELECT* FROM V$SYSSTAT; ------查詢用戶進程等待重做日志緩存的次數。
l 共享池
2 共享池由初始化參數SHARED_POOL_SIZE指定,默認80MB,可以在運行期間手動修改該參數。
2 共享池中保存了最近執行的SQL語句、PL/SQL過程與包、數據字典信息、鎖、以及其他控制結構的信息。共享池是對SQL語句、PL/SQL程序進行語法分析、編譯、執行的內存區。共享池又分為兩部分:
n 數據字典緩存
ü 數據字典緩存用於存儲經常使用的數據字典信息。比如:表的定義、用戶名、口令、權限、數據庫的結構等。
ü Oracle運行過程中經常訪問該緩存以便解析SQL語句,確定操作的對象是否存在,是否具有權限等。如果不在數據字典緩存中,服務器進程就從保存數據字典信息的數據文件中將其讀入到數據字典緩存中。數據字典緩存中保存的是一條一條的記錄(就像是內存中的數據庫),而其他緩存區中保存的是數據塊信息。
n 庫緩存
ü 庫緩存大小與OPEN_CURSOR初始化參數相關,ORACLE中每條查詢語句都需要打開一個游標,OPEN_CURSOR默認值為300。
ü 庫緩存的目的就是保存最近解析過的SQL語句、PL/SQL過程和包。這樣一來,Oracle在執行一條SQL語句、一段PL/SQL 過程和包之前,首先在“庫緩存”中搜索,如果查到它們已經解析過了,就利用“庫緩存”中解析結果和執行計劃來執行,而不必重新對它們進行解析,顯著提高執行速度和工作效率。
2 Oracle長期運行後,共享池可能出現碎片,這時可以用以下語句清除共享池內的全部數據:alter system flush shared_pool;
2 實驗與案例
n 驗證數據塊緩存和共享池的作用
1. 用sys登陸sqlplus,執行統計用戶表空間個數的語句。
SQL>conn / as sysdba
SQL>set timing on
SQL>select count(*) from user_tablespaces;
由於是第一次執行該查詢,需要將外存的user_tablespaces信息讀入數據塊緩存並對其進行解析,再把解析結果存儲到共享池的庫緩存中,所以用時較多。
2. 第二次執行該查詢。由於不需要讀外存,且sql語句執行計劃在內存中,不需要硬解析,速度較快。
SQL>select count(*) from user_tablespaces;
3. 清空共享池,第三次執行。由於清除了共享池,需要重新解析sql語句,但所需數據還在數據庫塊緩存中,所以用時介於兩者之間。
SQL>select count(*) from user_tablespaces;
n 緩存命中率
ü 邏輯讀(LogicalReads):即從緩存中讀取數據。
ü 物理讀(PhysicalReads):即從物理磁盤上讀取數據。
SQL>select statistic#, name, value from v$sysstat where name in ('physical reads', 'dbblock gets', 'consistent gets')
說明:v$sysstat是用來動態跟蹤系統性能參數的數據字典表。查詢和計算命中率有關的三個數據庫行,分別是physical reads, db block gets, consistent gets。其中db block gets和 consistentgets的value值相加數據值為所有讀的總次數。邏輯讀次數為總和減去physical reads的value值。命中率為:邏輯讀次數/所有讀的總次數。
l 大池
2 由初始化參數LARGE_POOL_SIZE確定大小,可以使用ALTER SYSTEM語句來動態改變大池的大小。
2 大池是可選項的,DBA可以根據實際業務需要來決定是否在SGA區中創建大池。如果創建,將會自動的被各種各樣的進程拿來使用,本來這些進程是使用共享池的內存。如果沒有創建大池,則需要大量內存空間的操作將占用共享池的內存。
2 ORACLE 需要大力內存的操作有:
A、數據庫備份和恢復。
B、具有大量排序操作的SQL語句。
C、並行化的數據庫操作。
l JAVA池
2 由初始化參數JAVA_POOL_SIZE確定大小,控制在30-50MB比較合適。
2 用戶存放JAVA代碼、JAVA語句的語法分析表、JAVA語句的執行方案和進行JAVA程序開發。
2 可以使用ALTER SYSTEM SET JAVA_POOL_SIZE=0M SCOPE=SPFILE;調整其大小,語句在服務器初始化參數文件中修改該參數。必須重新啟動數據庫服務器才能使其生效。