天天看點

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        589          9 

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

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

sql> alter system flush buffer_cache;

系統已更改。

         4        588          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相關說明。。。。