閱讀28 返回首頁    go 阿裏雲 go 技術社區[雲棲]


ORACLE--SGA之數據緩衝區(Data Buffer)

暨上通過預編譯闡述道共享池最後到SGA,這裏進一步說明一下SGA中另一個大塊,數據緩衝區,攜帶提及一點數據文件和表空間,後續專門會說明這塊。

 

首先了解下SGA種大致有那些東西,這些東西隨著數據庫版本的增加會有所增加,不過大致上應該一致,這也是基本所有的體係結構都會描述的東西:

 

在認識數據緩衝區前,先記住幾個常用的視圖:

X$BH、GV$BH、V$BH、V$FIXED_TABLE、V$FIXED_VIEW_DEFINITION、DICT、DICT_COLUMNS。

 

以及兩個包:DBMS_SPACE 和 DBMS_ROWID的一些常用內容,在後麵會逐漸用到時說明部分使用方式,不過還是先要創建一個表,不然什麼測試工作也做不了:

 

在一個用戶下創建一個表:

CREATE TABLE TEST_OBJECTS
  AS SELECT * FROM USER_OBJECTS;

 

如果那個用戶下沒有什麼對象,那就多複製幾次數據,才能填充一些數據,數據成倍增長:

 

INSERT INTO TEST_OBJECTS
SELECT * FROM TEST_OBJECTS;

COMMIT;

 

 

此時第一個,常規使用下,一個常用的對象就是ROWID,那麼看下它由哪幾部分組成:

對象編號、文件編號、文件內塊號、塊內部行號碼,我們看下一張表內部每條數據的這些信息:

SQL>SELECT dbms_rowid.rowid_relative_fno(ROWID) "文件編號",
       dbms_rowid.rowid_object(ROWID) "對象編號",
       dbms_rowid.rowid_block_number(ROWID) "塊編號",
       dbms_rowid.rowid_row_number(ROWID) "塊內部行號碼"
    FROM TEST_OBJECTS t;

 

  文件編號   對象編號     塊編號 塊內部行號碼
---------- ---------- ---------- ------------
         4      54646        588            0
         4      54646        588            1
         4      54646        588            2
         4      54646        588            3
         4      54646        588            4
         4      54646        588            5
         4      54646        588            6
         4      54646        588            7
         4      54646        588            8
         4      54646        588            9
         4      54646        588           10
         4      54646        588           11
         4      54646        588           12
         4      54646        588           13
         4      54646        588           14
         4      54646        588           15
         4      54646        589            0
         4      54646        589            1
         4      54646        589            2
         4      54646        589            3

 

其實對象編號是永遠不會變化的,一般情況下也在同一個文件中,所以主要看的是BLOCK的信息。

付:文件號是對應數據文件的編號,對應視圖DBA_DATA_FILES的FILE_ID字段。

     對象編號是對象在整個數據庫的唯一標識,對應DBA_OBJECTS的OBJECT_ID字段。

 

 

此時通過分析表:

BEGIN
     dbms_stats.gather_table_stats('SCOTT','TEST_OBJECTS');
END;

後查詢統計信息:

SELECT BLOCKS, NUM_ROWS

FROM USER_TABLES

WHERE TABLE_NAME = 'TEST_OBJECTS';

 

    BLOCKS   NUM_ROWS
---------- ----------
        16       1024

 

再查詢用戶段信息:

SQL> SELECT t.segment_name,t.blocks FROM USER_SEGMENTS T
  2  WHERE T.segment_name='TEST_OBJECTS';

SEGMENT_NAME                                                                         BLOCKS
-------------------------------------------------------------------------------- ----------
TEST_OBJECTS                                                                             16

 

在查詢根據上述統計出來的信息:

SQL> SELECT COUNT(DISTINCT dbms_rowid.rowid_block_number(ROWID))
  2     FROM TEST_OBJECTS;

COUNT(DISTINCTDBMS_ROWID.ROWID
------------------------------
                            13

 

為什麼不一樣,因為內部有保留塊,記錄表頭、位圖信息,數據庫始終比這個實際的段要小,通過測試可以發現,每次增長都會以8個塊增長,但是數據實際的值,記錄實際數據塊大小,當發現兩者之和大於實際大小,就需要擴展空間了。

 

 

上麵有點開場白,這裏再想下試驗前需要明白,數據緩衝區用於在數據從磁盤中讀取數據後到內存是以“”為基本單位,不論塊中存儲多少行數據,分別有“單塊讀”和“多塊讀”兩種方式,讀入內存後,此時未了避免下次再重磁盤上去讀取,減少磁盤讀取開銷,此時將這些塊放入內存中,並采用LRU鏈表進行管理(ORACLE 8I後並非完全的LRU算法),當對這些數據修改時,內存采用一致性讀塊進行管理(一個塊最多對應6個一致性讀塊),當數據緩衝區不夠用的時候,就會將接使用較少的部分提取出來,將其替換到磁盤上去(其實就是在內存中將其指針刪除),為簡單證明這個情況,我們需要做一個簡單試驗,剛才創建的表,我們找幾個塊出來做實驗(588塊和589塊吧,對象編號上述已經查詢出來是:54646,文件號也能通過上述看出是:),我們首先通過X$BH視圖查看其實用情況。

 

--X$BH需要在DBA用戶下才可以使用,即使在全局數據字典:

V$FIXED_TABLE、V$FIXED_VIEW_DEFINITION、DICT

也找不到他的身影,因為它基本不被外界使用;

順便說下全局視圖:

V$FIXED_TABLE  查詢所有的V$視圖定義和X$視圖信息,GV$視圖普遍為集群類使用。

V$FIXED_VIEW_DEFINITION 查詢所有V$視圖、V$的定義部分

DICT 查詢到所有字典的字典列表信息

三者很多信息都是重複的,關鍵字段有些變化。

通過V$FIXED_VIEW_DEFINITION視圖可以找到X$BH定義了GV$BH,由GV$BH的大部分字段組成了V$BH。

另外如果要查詢兩個塊下麵的數據如何查詢:

定位一下這兩個快不是很好查,怎麼查詢呢,因為隻是實驗,也不用管太多,隻要能得到要的結論即可,此時塊信息是需要588~599兩個塊,那麼我們怎麼查詢數據呢,通過ROWID,就需要DBMS_ROWID包來創建: ROWID >= DBMS_ROWID.ROWID_CREATE(1, 54646, 4, 588, 0)
AND ROWID < DBMS_ROWID.ROWID_CREATE(1, 54646, 4, 600, 0);

DBMS_ROWID.ROWID_CREATE用於創建ROWID,參數按順序為:類型(直接寫1即可),對象編號、文件編號、文件內塊號、塊內行號。

扯遠了,回到話題,開始試驗下:

而X$BH視圖看下有那些字段(一看看花眼了,找到想要的就行了):

SQL> DESC X$BH
 名稱
 -------------
 ADDR
 INDX
 INST_ID
 HLADDR
 BLSIZ
 NXT_HASH
 PRV_HASH
 NXT_REPL
 PRV_REPL
 FLAG
 RFLAG
 SFLAG
 LRU_FLAG
 TS#
 FILE#
 DBARFIL
 DBABLK
 CLASS
 STATE
 MODE_HELD
 CHANGES
 CSTATE
 LE_ADDR
 DIRTY_QUEUE
 SET_DS
 OBJ
 BA
 CR_SCN_BAS
 CR_SCN_WRP
 CR_XID_USN
 CR_XID_SLT
 CR_XID_SQN
 CR_UBA_FIL
 CR_UBA_BLK
 CR_UBA_SEQ
 CR_UBA_REC
 CR_SFL
 CR_CLS_BAS
 CR_CLS_WRP
 LRBA_SEQ
 LRBA_BNO
 HSCN_BAS
 HSCN_WRP
 HSUB_SCN
 US_NXT
 US_PRV
 WA_NXT
 WA_PRV
 TCH
 TIM

需要的字段有:文件號、對象編號、塊號、TOUCH熱度信息,分別對應字段:file#、obj、dbablk、tch信息,查看一下:

SQL> SELECT file#,dbablk,tch FROM x$bh
  2  WHERE obj = 54646
  3  AND dbablk in(588,589)
  4  ORDER BY dbablk;

     FILE#     DBABLK   TCH
---------- ---------- ----------
         4        588          8
         4        589          8

此時發現已經有一些操作,此時開始對第589塊上任意一行數據查詢(另起一個會話):

SELECT *
  FROM TEST_OBJECTS T
 WHERE ROWID = DBMS_ROWID.ROWID_CREATE(1, 54646, 4, 589, 0);

然後再執行上述SQL

SQL> /

     FILE#     DBABLK        TCH
---------- ---------- ----------
         4        588          8

         4        589          9 

有興趣可以多做幾次,每次都會有變化,注意,可能對同一個塊查詢出多條記錄,那是一致性讀的問題,很多漲塊信息也在裏麵。

然後再執行一下清空數據緩衝區的操作,其實就是清空熱點度的問題:

SQL> ALTER SYSTEM FLUSH BUFFER_CACHE;

係統已更改。

SQL> SELECT file#,dbablk,tch FROM x$bh
  2  WHERE obj = 54646
  3  AND dbablk in(588,589)
  4  ORDER BY dbablk;

     FILE#     DBABLK        TCH
---------- ---------- ----------
         4        588          0
         4        589          0
         4        589          0

此時熱點度的TCH都是0了,同樣的方式可以去查詢V$BH視圖,V$BH中沒有TCH這個字段,對應數據文件字段還是file#,而塊字段是block#,提供一個狀態字段status和flag字段來源其它視圖,status指明被instance共享、專用、還是一致性讀塊、空閑塊;flag按照和1、16、1536等等進行按位求與運算(通過函數bitand)得到塊內部的信息,如是否為髒塊、是否為臨時塊等等信息。

數據讀取過程有兩種方式:單塊讀(db file sequential)和多塊讀(db file scattered read),所謂單塊讀就是每次IO隻讀取一塊到內存,主要看分布情況,一般我們用索引定位少量數據或者用ROWID定位少量數據時較多,但是也有其它情況,和多塊讀一起說明;多塊讀是一次讀入多個連續塊到內存中(一定是連續的),這個數據的上限是由參數db_file_multiblock_read_count參數指定,默認是16個塊,可以根據實際情況作相應調整,不過很多時候它是一個理想數字,一般達不到,因為當數據緩衝區不夠的時候會替換一些不常用的塊到磁盤中,此時數據塊在內存中的分布零散的,此時當在查詢某個數據範圍時,包含多個塊,但是這些塊在內存中非連續,那麼就會按照斷掉的部分到磁盤上去讀取,此時就會選擇單塊讀還是多塊讀了,此時較為消耗IO性能,最壞的情況是每個塊斷一塊,所以在業務層麵,對於多塊信息在考慮查詢過程中,保證和查詢中的多塊讀的參數差不多是較為理想的選擇(但是這個可能真的不好控製,不過應當有一定的理論計算值),否則在設計層麵上,平均性能差距會產生幾倍的差距。

另外對於常規小表並且經常查詢的或者些經常查詢的不太大的索引,此時我們習慣讓他們放入內存中,此時使用對表的屬性修改為內存表格即可:

ALTER TABLE <table_name> CACHE;

另外可以指定存放位置,默認情況下,ORACLE現在隻會給與一個db_cache_size,它是常規的數據緩衝區信息,其實數據緩衝區還有兩塊分別為:db_keep_cache_size為幾乎不會被替換出內存的區域,和db_recycle_cache_size幾乎使用完就會被替換出內存的區域(付:如果為ORACLE 9i以前,不包括ORACLE 9i使用的參數為:db_block_buffer、db_pool_keep、db_pool_recycle)。

查詢這幾個參信息:

show parameter db_cache_size;

show parameter db_keep_cache_size;

show parameter db_recycle_cache_size;

或者通過視圖:

SELECT * FROM v$buffer_pool_statistics;

若發現後兩者沒有數據則修改這記者的大小信息:

SQL>alter system set db_cache_size = 400M;
SQL>alter system set db_keep_cache_size = 150M;
SQL>alter system set db_recycle_cache_size = 50M;

這裏需要注意的是:若要增加後麵兩者,需要先減少前者的大小,因為數據緩衝區畢竟還是一個整體,另外你設置的大小未必是實際的大小,ORACLE會根據你的設置做相應的細節調整,調整完成後,可以SHOW PARAMETER查看大小變化。

如上述表需要設置到KEEP區域進行存儲,此時使用:

ALTER TABLE <table_name> STORAGE(BUFFER_POOL KEEP) cache;

同理其它區域分別設置:DEFAULT、RECYCLE,如果將一個已經是cache表修改為非cache表,此時將參數修改為nocache即可。

修改為cache表後,可以通過視圖查看:

SELECT name,owner,type
FROM v$db_object_cache where kept = 'YES'
AND NAME ='表名稱大寫';

或者查詢表的屬性信息查看:

SELECT a.cache,a.BUFFER_POOL,a.table_name

 FROM user_tables a
 WHERE a.table_name = ‘表名稱大寫’;

從數據緩衝區可以看出內部運作和讀取方式,根據實際情況中的一些便要設計中有一定用處,這也是一些基礎,在後麵文件管理(其實文件係統才是真正的數據庫,現在說的都是實例內部的信息,他們是完全不同的概念),和索引原理上結合企業也許會更加清楚吧。

關於下一次應該是涉及物理結構的文件係統或者實例另一部分PGA相關說明。。。。

最後更新:2017-04-02 05:21:05

  上一篇:go C# Socket編程
  下一篇:go magento 開發 -- 深入理解Magento第七章 – 自定義Magento係統配置