11g新特性之結果集快取

action929發表於2007-11-13

11g新特性之結果集快取

[@more@]

結果集快取(Result Set Caching)

快取是提高效能的一個常用手段,可以說在Oracle資料庫中,Cache無處不在。

Result Cache進一步又可以分為:Server Result Cache 和 Client Result Cache。前者透過伺服器端SGA來快取結果集,後者透過客戶端來快取結果集。

Client Result Cache:
在使用OCI應用程式時,可以透過客戶端記憶體來快取查詢的結果集,快取結果可以在所有session間共享,當查詢反覆執行時,查詢結果可以直接從客戶段的快取中獲得,從而極大地提高應用效率。
客戶端結果集快取並不使用伺服器端的記憶體,不會對伺服器的記憶體使用造成影響,這一點和Server Result Cache不同。

同Client Result Cache相關的檢視主要有:

SQL> select * from dict where table_name like '%CLIENT_RESULT_CACHE%';

TABLE_NAME COMMENTS
------------------------------ -----------------------------------------
V$CLIENT_RESULT_CACHE_STATS Synonym for V_$CLIENT_RESULT_CACHE_STATS
GV$CLIENT_RESULT_CACHE_STATS Synonym for GV_$CLIENT_RESULT_CACHE_STATS
CLIENT_RESULT_CACHE_STATS$ Synonym for CRCSTATS_$

相關的引數有:

SQL> select * from dict where table_name like '%CLIENT_RESULT_CACHE%';

TABLE_NAME COMMENTS
------------------------------ ----------------------------------------
V$CLIENT_RESULT_CACHE_STATS Synonym for V_$CLIENT_RESULT_CACHE_STATS
GV$CLIENT_RESULT_CACHE_STATS Synonym for GV_$CLIENT_RESULT_CACHE_STATS
CLIENT_RESULT_CACHE_STATS$ Synonym for CRCSTATS_$
client_result_cache_size設定為0,即為關閉Client Result Cache。

Server Result Cache:

Oracle Database 11g增加了關於資料快取的功能欄。在過去,Oracle 資料庫快取資料庫塊。這些資料庫塊能夠被快取在很多區域,例如預設緩衝池、保持緩衝池和回收緩衝池。不過資料庫的緩衝物件總是資料塊,而構造塊用於構建結果集。

從Oracle Database 11g開始,Oracle資料庫也能夠快取結果集了。如果你要對變化緩慢甚至從不改變的資料不斷地執行同一個查詢,你就會發現這個全新的伺服器端查詢結果快取功能非常管用。幾乎所有的應用軟體都能而且也將從這個特性中受益。

這個效能可以這樣概括:當你執行一個查詢時,Oracle Database 11g會先行檢視這個查詢的結果是不是已經有人計算過這個查詢的結果並且將其快取起來,如果是的,那麼資料庫就會從伺服器端查詢結果快取中重新獲取查詢結果,而不會去集結所有的資料庫塊並整個的從頭開始計算結果。執行第一次查詢要花上和平常查詢一樣的時間(因為資料庫是在計算結果),不過接下來的查詢幾乎可以算的上是即時的了,因為查詢的結果是直接返回的,而不是計算然後返回的。

有觀點認為這個特性與實時物化檢視類似(just-in-time materialized view)。在Oracle8i Database Release 1中,Oracle引入了物化檢視的概念。憑藉這個,DBA們就可以建立概要表,例如,他們能夠建立一個索引,而資料庫最佳化器會識別到這個概要表的存在,而且如果可能的話,最佳化器會利用它來對查詢作出應答,而不是查詢並處理儲存在基礎表中的詳細資訊。這種執行方式很有用,但是相當的靜態,更像是一個索引結構(indexing scheme.)。而Oracle Database 11g的伺服器端查詢結果快取功能只利用一個快取就能同時做到有效的建立並維持物化檢視。

下面用例子來說明這個新功能

SQL> create table t as select * from dba_objects;

表已建立。

SQL> set autotrace traceonly;
SQL> set timing on;
SQL> select owner,count(*) from t group by owner order by 2;

已選擇29行。

已用時間: 00: 00: 00.61

執行計劃
----------------------------------------------------------
Plan hash value: 81261667

----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 70916 | 1177K| 290 (3)| 00:00:04 |
| 1 | SORT ORDER BY | | 70916 | 1177K| 290 (3)| 00:00:04 |
| 2 | HASH GROUP BY | | 70916 | 1177K| 290 (3)| 00:00:04 |
| 3 | TABLE ACCESS FULL| T | 70916 | 1177K| 284 (1)| 00:00:04 |
----------------------------------------------------------------------------

Note
-----
- dynamic sampling used for this statement


統計資訊
----------------------------------------------------------
48 recursive calls
0 db block gets
1091 consistent gets
1013 physical reads
0 redo size
1018 bytes sent via SQL*Net to client
427 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
29 rows processed

可以看到,花了0.61秒,physical reads 1013次,還有一次記憶體排序。我們再次執行這個命令。

SQL> select owner,count(*) from t group by owner order by 2;

已選擇29行。

已用時間: 00: 00: 00.06

執行計劃
----------------------------------------------------------
Plan hash value: 81261667

----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 70916 | 1177K| 290 (3)| 00:00:04 |
| 1 | SORT ORDER BY | | 70916 | 1177K| 290 (3)| 00:00:04 |
| 2 | HASH GROUP BY | | 70916 | 1177K| 290 (3)| 00:00:04 |
| 3 | TABLE ACCESS FULL| T | 70916 | 1177K| 284 (1)| 00:00:04 |
----------------------------------------------------------------------------

Note
-----
- dynamic sampling used for this statement


統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
1018 consistent gets
0 physical reads
0 redo size
1018 bytes sent via SQL*Net to client
427 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
29 rows processed

可以看到時間降為了 0.06秒,這是由於資料已經進入到記憶體,不需要再次從磁碟上讀取了。所以 physical reads 為 0,執行速度也大為提升。但是consistent gets變化不大,sorts (memory) 也仍然存在。之後再執行幾次,可以發現,最快也就是0.06秒了,這是最快的速度了。
現在我們看看使用最新的result cache 技術。使用 hint result_cache。

SQL> select /*+ result_cache */ owner,count(*) from t group by owner order by 2;


已選擇29行。

已用時間: 00: 00: 00.06

執行計劃
----------------------------------------------------------
Plan hash value: 81261667

--------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost

--------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 70916 | 1177K| 29

| 1 | RESULT CACHE | 5dgw29pr788n6bn48qjyq6sabc | | |
| 2 | SORT ORDER BY | | 70916 | 1177K| 29

| 3 | HASH GROUP BY | | 70916 | 1177K| 29

| 4 | TABLE ACCESS FULL| T | 70916 | 1177K| 28

--------------------------------------------------------------------------------


Result Cache Information (identified by operation id):
------------------------------------------------------

1 - column-count=2; dependencies=(MAS9I.T); parameters=(nls); name="select /*


Note
-----
- dynamic sampling used for this statement


統計資訊
----------------------------------------------------------
4 recursive calls
0 db block gets
1087 consistent gets
0 physical reads
0 redo size
1018 bytes sent via SQL*Net to client
427 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
29 rows processed

第一次執行的時候,發現執行時間和統計資訊和上一次的沒什麼區別,但是執行計劃中可以發現有一個很大的區別,就是多了一行 | 1 | RESULT CACHE | 5dgw29pr788n6bn48qjyq6sabc | | | 。這說明就已經把結果存放到 cache 裡面了。我們再次執行該語句

SQL> select /*+ result_cache */ owner,count(*) from t group by owner order by 2;


已選擇29行。

已用時間: 00: 00: 00.00

執行計劃
----------------------------------------------------------
Plan hash value: 81261667

--------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost

--------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 70916 | 1177K| 29

| 1 | RESULT CACHE | 5dgw29pr788n6bn48qjyq6sabc | | |
| 2 | SORT ORDER BY | | 70916 | 1177K| 29

| 3 | HASH GROUP BY | | 70916 | 1177K| 29

| 4 | TABLE ACCESS FULL| T | 70916 | 1177K| 28

--------------------------------------------------------------------------------


Result Cache Information (identified by operation id):
------------------------------------------------------

1 - column-count=2; dependencies=(MAS9I.T); parameters=(nls); name="select /*


Note
-----
- dynamic sampling used for this statement


統計資訊
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
1018 bytes sent via SQL*Net to client
427 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
29 rows processed

可以發現,消耗的時間變為了0,執行速度超快啊。在這個利用到Result Cache的查詢中,consistent gets減少到0,直接訪問結果集,不再需要執行SQL查詢。這就是Result Cache的強大之處。現在我們另外開一個sqlplus,來執行這句sql。可以發現 ,仍然可以使用到cache中的資料。
當資料被修改後,cache中的資料能夠被oracle自動清除,以保證資料的一致性。

伺服器端結果集快取使用Shared Pool中的記憶體來進行結果快取,這部分記憶體使用可以透過v$sgastat檢視來查詢觀察:

SQL> select * from v$sgastat where lower(name) like '%result%';

POOL NAME BYTES
------------ -------------------------- ----------
shared pool Result Cache: State Objs 2852
shared pool Result Cache 98396
shared pool Result Cache: Memory Mgr 128
shared pool Result Cache: Bloom Fltr 2048
shared pool Result Cache: Cache Mgr 112

和Result Cache相關的檢視有:

SQL> select * from dict where table_name like '%RESULT_CACHE%';

TABLE_NAME COMMENTS
------------------------------ --------------------------------------------------------------------------------
V$CLIENT_RESULT_CACHE_STATS Synonym for V_$CLIENT_RESULT_CACHE_STATS
GV$RESULT_CACHE_DEPENDENCY Synonym for GV_$RESULT_CACHE_DEPENDENCY
GV$RESULT_CACHE_MEMORY Synonym for GV_$RESULT_CACHE_MEMORY
GV$RESULT_CACHE_OBJECTS Synonym for GV_$RESULT_CACHE_OBJECTS
GV$RESULT_CACHE_STATISTICS Synonym for GV_$RESULT_CACHE_STATISTICS
V$RESULT_CACHE_DEPENDENCY Synonym for V_$RESULT_CACHE_DEPENDENCY
V$RESULT_CACHE_MEMORY Synonym for V_$RESULT_CACHE_MEMORY
V$RESULT_CACHE_OBJECTS Synonym for V_$RESULT_CACHE_OBJECTS
V$RESULT_CACHE_STATISTICS Synonym for V_$RESULT_CACHE_STATISTICS
GV$CLIENT_RESULT_CACHE_STATS Synonym for GV_$CLIENT_RESULT_CACHE_STATS
CLIENT_RESULT_CACHE_STATS$ Synonym for CRCSTATS_$

11 rows selected

V$RESULT_CACHE_MEMORY 檢視來看Cache的使用情況。

V$RESULT_CACHE_STATISTICS 可以查詢Result Cache的統計資訊。

V$RESULT_CACHE_OBJECTS 記錄了Cache的物件。

DBMS_RESULT_CACHE 可以用於執行關於Result Cache的管理。

總結:如果結果集修改的頻率不是很高,而且被查詢的次數十分頻繁,那麼使用 Result Cache 技術可以極大地提升效能,但是不能濫用,由於存放result的記憶體大小有限制,只應該存放查詢次數最頻繁的Result,這個在開發的時候需要注意。

PS:在使用中發現,如果表是屬於sys使用者的時候,無法使用result cache技術。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/133835/viewspace-982057/,如需轉載,請註明出處,否則將追究法律責任。

相關文章