暨上通過預編譯闡述道共享池最後到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相關說明。。。。