在Buffer Cache中自動大表快取

pxbibm發表於2016-08-05

約翰,在A銀行做DBA。凱特琳,新的技術長,她正在為資料庫效能問題由於長的I/O響應時間而沮喪。為了提高效能,她希望增加資料庫例項的緩衝區快取,以便在快取中快取更多的資料,從而減少了頻繁需要去讀磁碟。戴比,系統開發工程師,經歷了很多這樣的問題在她的職業生涯中,她解釋說,“我們的應用有很多全表掃描,資料庫的全表掃描使用的是直接路徑讀取(DPR)在表中的資料塊,不做緩衝區快取記憶體。”因此,新增實體記憶體到伺服器後,增加緩衝區快取,是不會幫助,因為緩衝區沒有用。應用程式可以透過加hits跳過DPRs,使用緩衝區快取記憶體,但在所有的應用需要修改成千上萬的查詢,這將是一個非常昂貴和耗時的過程,沒有人願意接受這種解決方案。為了提高全表掃描效能的唯一途徑,是提高I/O子系統的吞吐量,例如使用快閃記憶體儲存,但是快閃記憶體比較昂貴。
約翰向他們提出建議:在Oracle資料庫12c(12.1.0.2)釋出一個新功能可以使全表掃描被載入和儲存在一個大的緩衝區快取記憶體中。

為什麼不快取全表掃描?

在約翰解釋新的功能之前,辦公室裡的每個人都想知道為什麼一個完整的表掃描不會使用緩衝區快取。當一個連線到資料庫例項的會話從表中選擇資料時,資料庫伺服器程式從磁碟讀取適當的資料塊,並預設地將它們放入緩衝區快取中。每個塊進入緩衝區中的緩衝中。原因很簡單:如果另一個會話要訪問這些塊中的一些資料,它可以從快取區查詢,速度遠遠快於從磁碟上讀取。緩衝區的快取大小是有限的,通常小於整個資料庫,所以當快取滿了,一個新的資料塊要進來,資料庫迫使舊的緩衝區,很長一段時間沒有被訪問的塊被覆蓋。約翰繼續解釋,考慮選擇表的所有塊的全表掃描查詢的情況。如果該表非常大,它的塊將消耗緩衝區快取的很大一部分,迫使其他表的塊被覆蓋。這是不可能的,一個大表的所有塊將被定期訪問,所以在快取中的那些塊實際上並沒有幫助效能。但是,強制講其他表的塊,尤其是受歡迎的塊,擠出快取區,會降低資料庫中的應用程式的整體效能。這就是為什麼,資料庫不載入全表掃描到緩衝區快取中的原因。

Temperature
大家對約翰為什麼全表掃描不快取快取記憶體的原因的解釋感到非常滿意,但是,凱特琳,有另一個問題:如何決定Oracle資料庫緩衝區快取記憶體中的資料塊的去或留?

約翰解釋說,傳統的資料庫例項使用最近最少使用(LRU)列表來跟蹤多久前在緩衝區快取記憶體緩衝區的訪問。當一個緩衝區的塊第一次訪問,它被放在LRU列表的頭部。隨著時間的推移,當緩衝區中的其他塊被會話訪問時,他們會移動到LRU列表頭部,這會導致原始的緩衝區塊從列表的頭部向下滑動。當原始緩衝區塊再次被訪問時,它會移動到LRU列表的頭部,但如果它被不訪問,它一路下降到底部,並最終被從列表中移除掉。在這一點上,緩衝區的塊將從快取中移除。實際過程中,約翰趕忙補充,稍微複雜一點,因為例項還考慮其他因素,如多少次緩衝被觸動的(透過一個叫觸控計數的計數器)。

但在Oracle資料庫12c(12.1.0.2)中, 全表掃描可以快取到緩衝區中:資料庫有一個新的度量,溫度,用於識別一個物件的受歡迎度。訪問的物件的塊越多,該物件的溫度越高。而且由於溫度是基於物件的,而不是在塊上,它是一個更準確的衡量表的受歡迎度。
Big table

現在,利用新的特性,戴比可以快取大表,這個新的功能,約翰描述為“自動大表快取”。

但戴比看起來持懷疑態度。資料庫是巨大的,緩衝區快取記憶體儘管較大,仍然比資料庫大小小得多。事實上,有一些表是相當大的。當他們被載入到緩衝區快取中,他們將迫使很多流行的緩衝區的塊被覆蓋。所以,她沉思著,仍然存在風險。

風險仍然潛伏,約翰同意。因此,而不是冒險整個緩衝區快取,資料庫只是使一部分被用於快取大表。這是由初始化引數控制的。戴比想把高達百分之40的用於此目的的緩衝區,所以約翰用以下SQL語句:
SQL>alter system set db_big_table_cache_percent_target = 40;
這將留出百分之40的緩衝區快取用於大表快取。其他百分之60將不會被大表的全表掃描所使用,所以流行的緩衝區塊仍然可以存在在緩衝區中。這是一個動態引數,所以約翰不用重啟資料庫,即可重複效果演示。

Code Listing 1: Checking big table cache statistics (at first setup)

select * from v$bt_scan_cache;

BT_CACHE_ALLOC BT_CACHE_TARGET OBJECT_COUNT MEMORY_BUF_ALLOC MIN_CACHED_TEMP CON_ID
—————————————— ——————————————— ———————————— ———————————————— ——————————————— ——————
    .210158085              40            0                0            1000      0

select * from v$bt_scan_obj_temps;

no rows selected


兩個動態效能試圖顯示如何快取全表掃描的工作方式,v$bt_scan_cache顯示了全表掃描的概述。
列的含義如下:


BT_CACHE_ALLOC. Even though John allocated 40 percent to the big table cache, not all of that cache might be required. As the demand for buffers in the big table cache rises due to incoming big tables, more space will be allocated. This column shows the ratio of the buffer cache used by the big table cache right now to the overall size of the buffer cache; in our example, it’s 0.210158085, or about 21 percent, because there is no big table in the buffer cache yet.

BT_CACHE_TARGET. This column shows the target allocation percentage, 40 percent, as set by John earlier.

OBJECT_COUNT. This column shows how many objects are in the big table cache. Because John just set up this cache, there are no objects yet; hence, this shows 0.

MEMORY_BUF_ALLOC. This column shows how many buffers are allocated to the objects in the big table cache right now. Again, because John just set up the big table cache, this shows 0.

MIN_CACHED_TEMP. As John explained earlier, temperature is a new way to designate the usefulness of an object (for example, a table) in the big table cache. The more often a table is accessed, the higher its temperature and, hence, the more beneficial it is for the table to be in this cache. This column shows the minimum temperature of objects that will be considered for this cache. It shows 1,000; therefore, objects with temperatures below 1,000 will not be considered.

CON_ID. This column shows the container ID for a database in a multitenant environment.

The second view, V$BT_SCAN_OBJ_TEMPS, shows the details of the big table cache. The V$BT_SCAN_OBJ_TEMPS view includes the following columns:

TS#. This column shows the tablespace number an object resides in. You can join this view with the TS$ table to get the tablespace name.

DATAOBJ#. This column shows the data object number of the object. You can join this view with DBA_OBJECTS to get the object name.

SIZE_IN_BLKS. This column shows the number of blocks of this object that were considered for the big table cache in this database instance.

TEMPERATURE. This column shows the temperature of the object.

POLICY. This column shows how the object was cached: either partially or in its entirety.

CACHED_IN_MEM. This column shows how many blocks of this object are in the big table cache.

CON_ID. This column shows the container ID for a database in a multitenant environment.

約翰指出,v$bt_scan_obj_temps檢視沒有返回任何行。這並不奇怪,他補充說,因為他只是設定了大表的快取,但並沒有表已被快取。為了證明這個新的快取特性,約翰從資料庫中選擇一個大的表名為T1。首先,他用以下SQL查詢,查詢下該表多少塊由該表使用:

select blocks 
from user_tables 
where table_name = 'T1';
 
    BLOCKS
———————————————
    335952


T1表有 335,952 資料塊—這個表相當大,執行一個全表掃描:

select count(1) from t1;

 

執行全表掃描後, 這時兩個動態檢視顯示的資料和前期的不一樣了. 我們Code Listing 2. 試圖 V$BT_SCAN_CACHE 的 BT_CACHE_ALLOC 列現在顯示0.400012911, 表明大約有 40 % 的資料快取在 buffer cache 中.
Code Listing 2: Checking big table cache statistics (after full table scan operation)

select * from v$bt_scan_cache;

BT_CACHE_ALLOC BT_CACHE_TARGET OBJECT_COUNT MEMORY_BUF_ALLOC MIN_CACHED_TEMP CON_ID
—————————————— ——————————————— ———————————— ———————————————— ——————————————— ——————
    .400012911              40            1            49570            1000      0

select * from v$bt_scan_obj_temps;

   TS#    DATAOBJ# SIZE_IN_BLKS TEMPERATURE POLICY  CACHED_IN_MEM    CON_ID
——————  —————————— ———————————— ——————————— ——————— ————————————— —————————
196612       95956       335952        1000 MEM_PART        49570         0


 

接下來約翰指著V $ bt_scan_obj_temps檢視輸出結果,講述瞭如何使用快取的具體細節。dataobj #列顯示95956。約翰使用以下查詢來查詢是哪個物件:

select object_name
from dba_objects
where data_object_id = 95956;

OBJECT_NAME
—————————————————
T1


物件是T1表,約翰迫使執行了全表掃描。該表現在處於緩衝區快取中。然而,他指出,該表共335952塊,只有49570是在快取中,在cached_in_mem列。他解釋說,原因是,快取大表的緩衝區快取太小,不能夠容納表的所有塊。他透過POLICY的列的值,表明mem_part,表明只有一個表的一部分,而不是整個表載入到記憶體中。

“但我們現在有更多的記憶體,”戴比說。“當然,”約翰同意。他增加了SGA的大小,使用下面的SQL語句:


alter system set sga_target = 3G;

他還增加了大表快取的比例為百分為90:

alter system set db_big_table_cache_percent_target = 90;


這之後他再次執行T1表全表掃描,在Code Listing 3中有幾個有趣的資料輸出,他指出。首先,大表快取分配現在是緩衝區快取的86.5%。在大表快取中的物件的溫度是4000,之前是1000。由於在表上的全表掃描的數目增加。cached_in_mem列顯示為335952,與表中的塊的數量相同,表明整個表快取了。

Code Listing 3: Checking big table cache statistics (after increasing cache size)

select * from v$bt_scan_cache;

BT_CACHE_ALLOC BT_CACHE_TARGET OBJECT_COUNT MEMORY_BUF_ALLOC MIN_CACHED_TEMP CON_ID
—————————————— ——————————————— ———————————— ———————————————— ——————————————— 
    .865177265              90            1           175625            1000      0

select * from v$bt_scan_obj_temps;

   TS#    DATAOBJ# SIZE_IN_BLKS TEMPERATURE POLICY  CACHED_IN_MEM    CON_ID
——————  —————————— ———————————— ——————————— ——————— ————————————— —————————
196612       95956       335952        4000 MEM_ONLY       335952         


policy列這表明mem_only,這意味著表所有的塊快取在記憶體中。在這之後所有對T1的訪問,即使表是透過全表掃描訪問,只會從記憶體中讀取,不會讀磁碟。


戴比看起來還是有點不服氣,他指出,資料庫並沒有像約翰所顯示的那樣,只有一個大表。會有許多這樣的大的表。“資料庫的記憶體是有限的,不能無限增長,所以如何將資料庫中其他的表快取到快取中?”

這是很容易透過演示顯示,約翰的答覆。他執行全表掃描表T2:

SQL> select count(1) from t2;

然後,他再次檢查檢視,如Code Listing 4:所示。他指著v$bt_scan_obj_temps,試圖其中的dataobj #列顯示一個新的物件:95964。用之前的查詢,這個物件是表T2,這正是他在第二次全表掃描的物件。然而,policy列顯示的是mem_part,這意味著記憶體中快取的是表的一部分,不像表T1,完全在記憶體中。但表T2是最近訪問,戴比指出,資料庫T1表塊的快取不應該為T2的所有塊的騰出空間嗎?

Code Listing 4: Checking big table cache statistics (after adding second table)

select * from v$bt_scan_cache;

BT_CACHE_ALLOC BT_CACHE_TARGET OBJECT_COUNT MEMORY_BUF_ALLOC MIN_CACHED_TEMP CON_ID
—————————————— ——————————————— ———————————— ———————————————— ——————————————— ———
    .866228351              90            2           277731            1000      0

select * from v$bt_scan_obj_temps;

   TS#    DATAOBJ# SIZE_IN_BLKS TEMPERATURE POLICY  CACHED_IN_MEM    CON_ID
——————  —————————— ———————————— ——————————— ——————— ————————————— —————————
196612       95956       335952        4000 MEM_ONLY       335952         0
196612       95964       334149        1000 MEM_PART       102106         0
select object_name
from dba_objects
where data_object_id = 95964;

OBJECT_NAME
—————————————————
T2

不,回答約翰,這正是TEMPERATURE列的作用。T1比T2被訪問更頻繁(如圖所示的溫度,T1(4000)T2(1000) )。因此,T2比T1的優先順序低了。

繼續演示,約翰執行幾個全表掃描的T2。之後,他檢查了2個試圖快取統計資料,如Code Listing 5:所示。他指出表T1(95956 # dataobj)的溫度4000,這是低於T2(95964 # dataobj),T2現在已經加熱到溫度5000。這改變了表的優先順序。因為T2具有較高的溫度。事實上,表T2現在都在記憶體中,Policy列的值是mem_only。表T1的緩衝區只有部分在快取中,Policy列的值是mem_part。

Code Listing 5: Checking big table cache statistics (after temperature change)

select * from v$bt_scan_obj_temps;

   TS#    DATAOBJ# SIZE_IN_BLKS TEMPERATURE  POLICY CACHED_IN_MEM    CON_ID
——————  —————————— ———————————— ——————————— ——————— ————————————— —————————
196612       95964       334149        5000 MEM_ONLY       334149         0
196612       95956       335952        4000 MEM_PART       107376         0


戴比現在完全相信了。這不僅利用了額外的記憶體,減少磁碟上的負擔,並且沒有修改任何應用程式或資料庫物件的變化。這個新特性的快取記憶體記憶體量也可以動態調整,而不需要重啟資料庫。凱特琳聽完後欣喜若狂。大家都非常感謝約翰。

結論

Oracle資料庫12c(12.1.0.2)釋出之前,只有透過提高IO系統的吞吐量才能達到提高全表大表掃描。

大表快取功能在Oracle資料庫12c(12.1.0.2)的版本中,DBA可以透過分配緩衝區的一部分空間為全表掃描提供快取,可以減少磁碟訪問和顯著提高效能。

原文來自oracle官方,本人翻譯的有不準確的地方,歡迎大家一起交流。

參考文件

在Buffer Cache中自動大表快取

彭小波

性別:男: 現在定居:大連

DBA+東北社群 創始人

資料庫技術愛好者

+10Oracle資料庫使用經驗

+2Oracle培訓講師

手機:150 4113 1262



 

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

相關文章