您好,登錄后才能下訂單哦!
本篇文章為大家展示了oracle result cache 結果集緩存的使用方法,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
結果集緩存
緩存是一種最常見的在計算機系統用來提高性能的技術.硬件和軟件被廣泛的使用.oracle數據庫也不會例外.例如在緩沖區緩存中緩存數據文件塊,在字典緩存中緩存字典信息,在庫緩存中緩存游標.在oracle11G中結果集緩存也是可用的.
結果集緩存是如何工作的
oracle數據庫引擎提供了三種結果集緩存:
服務器結果集緩存也叫查詢結果緩存,是一種服務器端緩存,它用來存儲查詢的結果集.
pl/sql函數結果集緩存是一種服務器端緩存,它用來存儲pl/sql函數返回的結果集.
客戶端結果集緩存是一種客戶端緩存,用來存儲查詢結果集.
服務器結果集緩存
服務器結果集緩存是用來避免重復執行查詢.簡單來說查詢第一次執行,它的結果集被存儲在共享池中.然后后續執行相同的查詢時從結果集緩存中直接提取結果集而不用重新計算.注意這兩個查詢被認為是相等的.因此能使用相同的結果集.另外如果出現綁定變量,那么它們的值必須相同.這是必須的,因為很明顯,綁定變量作為參數輸入并傳給查詢.因此不同的綁定變量值會有不同的結果集.注意結果集緩存是存儲在共享池中,對于一個指定的實例所有連接的會話都能共享相同的緩存條目.
下面來舉例說明.注意在查詢時指定了result_cache提示來啟用結果集緩存.第一次執行花了1.04秒.可以看到在執行計劃中操作result cache確定了對查詢啟用了結果集緩存.在執行計劃中starts列清楚的說明了所有的操作都至少要被執行一次.執行計劃中所有的操作都是必須的因為是第一次執行這個查詢.因此結果集緩存還不包含結果集.
SQL> alter session set statistics_level=all; SQL> SELECT /*+ result_cache */ 2 p.prod_category, c.country_id, 3 sum(s.quantity_sold) AS quantity_sold, 4 sum(s.amount_sold) AS amount_sold 5 FROM sh.sales s, sh.customers c, sh.products p 6 WHERE s.cust_id = c.cust_id 7 AND s.prod_id = p.prod_id 8 GROUP BY p.prod_category, c.country_id 9 ORDER BY p.prod_category, c.country_id; 已選擇81行。 已用時間: 00: 00: 01.04 SQL> select * from table(dbms_xplan.display_cursor(null,null,'all allstats')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID g9sxqz9qgutu7, child number 0 ------------------------------------- SELECT /*+ result_cache */ p.prod_category, c.country_id, sum(s.quantity_sold) AS quantity_sold, sum(s.amount_sold) AS amount_sold FROM sh.sales s, sh.customers c, sh.products p WHERE s.cust_id = c.cust_id AND s.prod_id = p.prod_id GROUP BY p.prod_category, c.country_id ORDER BY p.prod_category, c.country_id Plan hash value: 1866882273 -------------------------------------------------------------------------------- PLAN_TABLE_OUTPUT ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | Pstart| Pstop | A-Rows | A-Time | OMem | 1Mem | O/1/M | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 985 (100)| | | | 81 |00:00:00.01 | | | | | 1 | RESULT CACHE | cu8pf4s7jn9d05yda1swvwpd7y | 1 | | | | | | | 81 |00:00:00.01 | | | | | 2 | SORT GROUP BY | | 1 | 68 | 3808 | 985 (7)| 00:00:12 | | | 0 |00:00:00.01 | 73728 | 73728 | | |* 3 | HASH JOIN | | 1 | 968 | 54208 | 984 (7)| 00:00:12 | | | 0 |00:00:00.01 | 940K| 940K| | | 4 | VIEW | index$_join$_003 | 1 | 72 | 1512 | 3 (34)| 00:00:01 | | | 0 |00:00:00.01 | | | | |* 5 | HASH JOIN | | 1 | | | | | | | 0 |00:00:00.01 | 1269K| 1269K| | | 6 | INDEX FAST FULL SCAN| PRODUCTS_PK | 1 | 72 | 1512 | 1 (0)| 00:00:01 | | | 0 |00:00:00.01 | | | | | 7 | INDEX FAST FULL SCAN| PRODUCTS_PROD_CAT_IX | 1 | 72 | 1512 | 1 (0)| 00:00:01 | | | 0 |00:00:00.01 | | | | | 8 | VIEW | VW_GBC_9 | 1 | 968 | 33880 | 981 (7)| 00:00:12 | | | 0 |00:00:00.01 | | | | | 9 | HASH GROUP BY | | 0 | 968 | 26136 | 981 (7)| 00:00:12 | | | 0 |00:00:00.01 | 56M| 4744K| | |* 10 | HASH JOIN | | 1 | 918K| 23M| 941 (3)| 00:00:12 | | | 0 |00:00:00.01 | 3056K| 1398K| | | 11 | TABLE ACCESS FULL | CUSTOMERS | 1 | 55500 | 541K| 406 (1)| 00:00:05 | | | 0 |00:00:00.01 | | | | | 12 | PARTITION RANGE ALL| | 1 | 918K| 14M| 530 (3)| 00:00:07 | 1 | 28 | 0 |00:00:00.01 | | | | | 13 | TABLE ACCESS FULL | SALES | 28 | 918K| 14M| 530 (3)| 00:00:07 | 1 | 28 | 0 |00:00:00.01 | | | | -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第二次執行只花了0.03秒.在執行計劃中starts列顯示了所有操作的執行次數.RESULT CACHE被執一次.其它的操作沒有被執行.換句話說直接使用了存儲在結果集緩存中的結果集.
SQL> SELECT /*+ result_cache */ 2 p.prod_category, c.country_id, 3 sum(s.quantity_sold) AS quantity_sold, 4 sum(s.amount_sold) AS amount_sold 5 FROM sh.sales s, sh.customers c, sh.products p 6 WHERE s.cust_id = c.cust_id 7 AND s.prod_id = p.prod_id 8 GROUP BY p.prod_category, c.country_id 9 ORDER BY p.prod_category, c.country_id; 已選擇81行。 已用時間: 00: 00: 00.03 SQL> select * from table(dbms_xplan.display_cursor(null,null,'all allstats')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID g9sxqz9qgutu7, child number 0 ------------------------------------- SELECT /*+ result_cache */ p.prod_category, c.country_id, sum(s.quantity_sold) AS quantity_sold, sum(s.amount_sold) AS amount_sold FROM sh.sales s, sh.customers c, sh.products p WHERE s.cust_id = c.cust_id AND s.prod_id = p.prod_id GROUP BY p.prod_category, c.country_id ORDER BY p.prod_category, c.country_id Plan hash value: 1866882273 -------------------------------------------------------------------------------- PLAN_TABLE_OUTPUT ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | Pstart| Pstop | A-Rows | A-Time | OMem | 1Mem | O/1/M | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 985 (100)| | | | 162 |00:00:00.01 | | | | | 1 | RESULT CACHE | cu8pf4s7jn9d05yda1swvwpd7y | 1 | | | | | | | 162 |00:00:00.01 | | | | | 2 | SORT GROUP BY | | 0 | 68 | 3808 | 985 (7)| 00:00:12 | | | 0 |00:00:00.01 | 73728 | 73728 | | |* 3 | HASH JOIN | | 0 | 968 | 54208 | 984 (7)| 00:00:12 | | | 0 |00:00:00.01 | 940K| 940K| | | 4 | VIEW | index$_join$_003 | 0 | 72 | 1512 | 3 (34)| 00:00:01 | | | 0 |00:00:00.01 | | | | |* 5 | HASH JOIN | | 0 | | | | | | | 0 |00:00:00.01 | 1269K| 1269K| | | 6 | INDEX FAST FULL SCAN| PRODUCTS_PK | 0 | 72 | 1512 | 1 (0)| 00:00:01 | | | 0 |00:00:00.01 | | | | | 7 | INDEX FAST FULL SCAN| PRODUCTS_PROD_CAT_IX | 0 | 72 | 1512 | 1 (0)| 00:00:01 | | | 0 |00:00:00.01 | | | | | 8 | VIEW | VW_GBC_9 | 0 | 968 | 33880 | 981 (7)| 00:00:12 | | | 0 |00:00:00.01 | | | | | 9 | HASH GROUP BY | | 0 | 968 | 26136 | 981 (7)| 00:00:12 | | | 0 |00:00:00.01 | 56M| 4744K| | |* 10 | HASH JOIN | | 0 | 918K| 23M| 941 (3)| 00:00:12 | | | 0 |00:00:00.01 | 3056K| 1398K| | | 11 | TABLE ACCESS FULL | CUSTOMERS | 0 | 55500 | 541K| 406 (1)| 00:00:05 | | | 0 |00:00:00.01 | | | | | 12 | PARTITION RANGE ALL| | 0 | 918K| 14M| 530 (3)| 00:00:07 | 1 | 28 | 0 |00:00:00.01 | | | | | 13 | TABLE ACCESS FULL | SALES | 0 | 918K| 14M| 530 (3)| 00:00:07 | 1 | 28 | 0 |00:00:00.01 | | | | -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在執行計劃中要注意一個名字緩存ID它與操作result cache相關.如果知道這個緩存ID,可以查詢v$resul_cache_objects視圖來顯示關于緩存數據的信息.下面的查詢顯示緩存結果集已經被發布(換句話說可以使用).視圖信息會顯示緩存結果集是何進創建的,創建它花了多長時間,有多少行記錄被存儲和它被引用了多少次.其它提供關于緩存結果集信息的視圖還有v$result_cache_dependency,v$result_cache_memory和v$result_chace_statistics.
SQL> SELECT status, creation_timestamp, build_time, row_count, scan_count 2 FROM v$result_cache_objects 3 WHERE cache_id = 'cu8pf4s7jn9d05yda1swvwpd7y'; STATUS CREATION_TIMESTAMP BUILD_TIME ROW_COUNT SCAN_COUNT --------- ------------------ ---------- ---------- ---------- Published 2013-7-5 9:21:26 94 81 3
為了保證結果的一致性(也就是說結果集是相同的就是看它是來自緩存還是來自數據庫計算).每當查詢中所引用的對象發生改變,那么依賴于這些表的緩存條目將會無效.事實情況就是這樣,即使真正的改變沒有發生.例如.甚至一個select * for update語句后面緊跟著一個commit提交也會導致依賴于select表的緩存條目變為無效.
有一些動態初始化參數可以控制服務器結果集緩存:
result_cache_max_size:以byte為單位來指定在共享池中用于結果集緩存的內存總量.如果它被設置為0,這個功能將會被禁用.缺省值是一個比0大的值,它是從共享池中派生出來的.內存分配是動態的,因此初始化參數只能指定它的上限.可以使用下面的查詢來顯示當前分配的內存大小:
SQL> SELECT name, sum(bytes) FROM v$sgastat WHERE name LIKE 'Result Cache%' GROUP BY rollup(name); NAME SUM(BYTES) -------------------------- ---------- Result Cache 161680 Result Cache: Bloom Fltr 2048 Result Cache: Cache Mgr 208 Result Cache: Memory Mgr 200 Result Cache: State Objs 2896 167032 下面的語句顯示了resulr_cache_max_size的值為15424K SQL> show parameter result NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ client_result_cache_lag big integer 3000 client_result_cache_size big integer 0 result_cache_max_result integer 5 result_cache_max_size big integer 15424K result_cache_mode string MANUAL result_cache_remote_expiration integer 0
result_cache_mode:指定在什么情況下使用結果集緩存.可以將它設置為manual手動這是缺省值或者設置為force.當使用manual時結果集緩存只有當指定result_cache提示時才使用.當使用force時那么會對所有沒有使用no_result_cache提示的所有查詢使用結果集緩存.因為在大多數情況下我們只會對少量的查詢使用結果集緩存,所以讓該參數設置為它的缺省值manual當只需要使用時在查詢中指定result_cache來啟用它.
result_cache_max_result:指定單一個結果集緩存的占用result_cache_max_size服務器結果集緩存大小的百分比.它的缺省值是5.它的值可以是0到100的任何一個數字.超過這個限制的結果集緩存將是無效的.
result_cache_remote_expiration:指定基于遠程對象的結果集的有效時間(以分鐘為單位).這是必須的,因當遠程對象已經發生改變了基于這些遠程對象的失效的結果集緩存不能被執行.當經過初始化參數所指定的有效時間后這些結果集才變為無效.這個參數的缺省值是0,意味著基于遠程對象的查詢緩存功能被禁用.
初始化參數result_cache_max_size和result_cache_max_result只能在系統級別進行修改.其它的result_cache_mode
和result_cache_remote_expiration能在會話級別進行修改.
注意:將result_cache_remote_expiration參數設置為一個比0大的數字會導致過時的結果集緩存存在.因此只有你真正地理解這樣做的影響后才能將它設置為比0大.
使用結果集緩存有幾個很明顯的限制:
查詢使用非確定性的函數,序列和臨時表是結果集不會被緩存
查詢違反了讀一致性時結果集將不會被緩存.例如,當通過會話創建結果集時所引用的表正經歷大量的事務這樣的結果
集不會被緩存.
引用數據字典視圖的查詢的結果集不會被緩存.
dbms_result_cache包
可以使用dbms_result_cache包來管理結果集緩存,它提供了以下程序來進行管理:
bypass:在會話或系統級別臨時禁用或啟用結果集緩存.
flush:從結果集緩存中清空所有對象
invalidate:讓依賴于指定的數據庫對象的所有結果集緩存變為無效
invalidate_object:讓單個結果集緩存條目變為無效
memory_report:生成一個內存使用情況報告
status:顯示結果集緩存的狀態.
例如:
SQL> select dbms_result_cache.status from dual; STATUS -------------------------------------------------------------------------------- ENABLED
pl/sql函數結果集緩存
pl/sql函數結果集緩存類似于服務器結果集緩存,但是它支持pl/sql函數,還和服務器結果集緩存共享相同的內存結構.它的目的是在結果集緩存中存儲函數返回的值(僅僅只有函數返回的值,過程返回的值不能被緩存).明顯地使用不同輸入值的函數是以不同的緩存條目被緩存在結果集緩存中的.在下面的例子中顯示了一個啟用結果集緩存的函數.為了啟用pl/sql函數結果集緩存,要指定result_cache子句.還可以指定relies_on子句來指定函數依賴于哪個表來返回結果.
SQL> CREATE OR REPLACE FUNCTION f 2 RETURN NUMBER 3 RESULT_CACHE RELIES_ON(t) IS 4 l_ret NUMBER; 5 BEGIN 6 SELECT count(t.indi_id) INTO l_ret FROM impl_chenzhou.bs_insured t; 7 RETURN l_ret; 8 END; 9 / Function created
在下面的例子中將會調用函數2480625次f不使用結果集緩存(通過使用bypass過程來臨時禁用結果集緩存)共用了4.69秒
SQL> execute dbms_result_cache.bypass(bypass_mode => TRUE, session => TRUE); SQL> select count(f) from impl_chenzhou.bs_insured t; COUNT(F) ---------- 2480625 Elapsed: 00:00:04.69 在下面的例子中將會調用函數2480625次f使用結果集緩存共用了0.32秒 SQL> execute dbms_result_cache.bypass(bypass_mode => FALSE, session => TRUE) SQL> select count(f) from impl_chenzhou.bs_insured t; COUNT(F) ---------- 2480625 Elapsed: 00:00:00.32
注意:如果relies_on子句沒有指定或者包含錯誤信息,當函數依賴的對象發生修改結果集緩存不會變為無效.因此可能會出現過時的結果集.
使用pl/sql函數結果集有一些限制,下面的函數不能使用結果集緩存:
使用out和(或者)in out參數的函數
定義了使用調用者權限的函數
管道化表函數
從匿名塊調用函數
使用in參數或者返回值有以下類型的函數:LOB,REF CURSOR,對象和記錄
客戶端結果緩存集
客戶端結果集緩存是用客戶端緩存來存查詢的結果集.它的目的和工作類似于服務器端結果集緩存.與服務器端的實現進行比較有兩個重要的不同.第一它避免了需要在客戶端/服務器之間來回地執行sql語句.這是一大優點.第二結果集的失效是基于一種輪詢機制,因此一致性不能保證這是一大缺點.
為了實現這種輪詢客戶端必須定期地執行數據庫調用來檢查數據庫引擎看看它的結果集緩存是否已經變為無效了.為了輪詢的開銷最小化,每一次客戶端由于其它原因執行一個數據庫調用時它將檢查結果集緩存的有效性.這樣,就可以避免掉那些用于對緩存的結果集進行失效操作的數據庫調用.使客戶端能持續地執行"正常的"數據庫調用.
盡管它是客戶端緩存但還是要在服務器端來啟用它.下面有些參數來控制客戶端緩存:
client_result_cache_size:指定每一個客戶端進程能使用的結果集緩存的最大內存大小以byte為單位.如果它設置為0,這也是缺省值那么這個功能將禁用.這個初始化參數是靜態的只能在實例級別進行修改.修改完后必須對實例進行重啟才會生效.
client_result_cache_lag:指定兩次數據庫調用之間的最大時間間隔以毫秒為單位.也就是說它指定無效的結果集能在客戶端緩存中保留多長的時間.缺省值是3000.這個初始化參數是靜態的只能在實例級別進行修改.修改完后必須對實例進行重啟才會生效.
oci_result_cache_max_size:會覆蓋服務器端設置的初始化參數client_result_cache-size.然而要注意是如果在服務器禁用了結果集緩存這個參數將不能激活它.
oci_result_cache_max_rset_size:指定單個結果集緩存最多能使用的內存大小以byte為單位.
oci_result_cache_max_rset_rows:指定單個結果集緩存最多能存儲的返回行數.
何時使用
當你遇到由程序反復執行相同的操作所導致的性能問題時,你要么減少執行的頻率要么減少操作的響應時間.理想的情況時兩者都做.然而有時(例如由于應用程序代碼不能修改)你只能實現后者.為了減少響應時間可以使用各種優化技術,如果還不能滿足要求那就只能使用高級優化技術了象結果集緩存.基本上要有效使用結果集緩存要滿足兩個條件.第一相對于修改數據來說同樣的數據查詢的更頻繁.第二要有足夠的內存來存儲結果集.
在大多數情況下不能對所有的查詢都啟用結果集緩存.事實上在大多數時候只有特定的查詢才能從結果集緩存中獲益而對于其它的情況來說,結果集緩存只不過是一種純粹的額外的開銷說不定還會使用緩存過載.還要記住的是服務器端緩存是對所有會話共享的,因此它們的訪問是要同步的(它們也會象所有的共享資源一樣變成一個串處理點).因此只有在真正查詢請求它們的時候才會結果集緩存.也就是說只當真正需要使用它們來提高性能時才在查詢中指定result_cache提示.
服務器端結果集緩存無法完全避免執行一個查詢的額外開銷.這意味著如果一個查詢在不使用結果集緩存的情況下對于每一行執行了最少的邏輯讀(不是物理讀)了,那么使用結果集緩存性能不會提高很多.請記住高速緩存和結果集緩存都是存儲在相同的共享內存中的.
pl/sql函數結果集緩存對于經常在sql語句中使用的函數來說特別有用.事實上常遇到這樣的情況被處理或被返回的每一行都會調用一次這個函數,同時輸入的參數也只有幾個不同的值,然而這個函數經常從pl/sql中被頻繁地調用它能使用結果集緩存.
因為一致性的問題客戶端緩存只應該用在只讀表或主要是讀的表上.
最后要注意的是可以同進使用服務器和客戶端結果集緩存.然而對于客戶端執行的查詢不能選擇只使用服務器結果集緩存而不使用客戶端結果集緩存.也就是說兩種結果集緩存都會被使用.
上述內容就是oracle result cache 結果集緩存的使用方法,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。