oracle學習筆記 buffer_cache作用概述



oracle學習筆記  buffer_cache作用概述


從這節課開始講buffercache
對oracle數據庫來講最重要的內存結構是buffercache
buffercache的合理使用它直接關係到數據庫運行的性能
對DBA來講數據庫的性能是非常重要的


和性能即對立又相附的是安全
oracle數據庫的數據安全性一致性有時會出現問題
我們掌握基本的一些概念和手法可以避免
當然有好多知識需要去學習
oracle數據庫的一致性一旦出問題就是災難性的
很多時候把數據搞得不一致了老師也沒有很好的辦法
只能一點點的驗證,很麻煩


不一致簡單講就是數據庫中數據的值和真實值不一樣了
可人爲造成,也可是數據庫運行時由軟件或硬件造成
就是數據出錯了
對一個大型的庫來講想排除一個這樣的錯誤是非常麻煩的,
因爲你可能根本不知道它已經出錯了
或者根本不知道它錯在哪裏
即使找到了地方也有可能根本不知道正確的值是什麼
對於一些不穩定的配置是極易出現這種問題的
如一些"先進"的軟硬件配置
因爲先進設備帶來的最大副作用就是不穩定也就是說經常出錯
儘管一些對軟硬件的修改未必是什麼新的技術,說成是先進很勉強
但作用是肯定有的,原軟件穩定性差了
想保證一個數據庫系統的安全首要的任務是使用安全的軟硬件設施
這樣數據的一致纔有最好的保證


但是我們平時工作中最主要的時間和精力花費在oracle數據庫的優化上
優化是讓數據庫運行的更快更穩定
優化是從一個很高的高度來設置數據庫
但我們首要的任務應該是得到一個安全穩定的基礎


我們在優化過程中非常注意關注的一個地方就是buffercache


這節課主要講一下buffercache的工作機制和工作原理
當然我們後面會給大家講一些操作和sql語句
讓大家更深一步的去理解這些概念和原理


今天我們就從buffercache最基本的講起


一)buffer_cache作用概述


先講一個最基礎的東西
段、區、塊的概念


1)數據庫基本功能和結構


我們需要數據庫是因爲它可以
1、存儲數據
但並不是我們最終使用的目的
對oracle數據庫來講它存儲數據的同時我們可以很方便的
2、檢索和處理數據
處理裏面包括
增加數據、刪除數據、修改數據

舉個很簡單的例子
假設有個公司有十萬個員工
我們把十萬個員工所有的信息全部存儲在數據庫裏面去
將來要檢索要找某個員工信息的時候非常容易
數據庫裏面一條sql語句一下就出來啦


但如果說你不用數據庫你用別的格式的文檔去存儲這個信息的話
你找的時候要翻半天
但數據庫不是
它以存儲數據爲手段
最主要的是要檢索以及處理數據
這是我們處理數據庫的目的


數據庫裏面存儲的數據其實就是表
表是一個有行列的二維結構


比如說一個關於人員的一個表,員工employee表
表裏有員工編號、員工姓名、性別、出生日期,
還有些別的信息如家庭住址、電話號碼等等
這就是一張表
oracle數據庫裏面就是存儲着幾十張幾百張表
一般老師做的數據庫裏面多是四五百張以上
可以這麼認爲oracle數據庫裏面存儲着表
平時可以檢索表數據,同時也可以對錶數據進行處理
當然了我們爲了檢索處理數據
除了表以外在數據庫裏面還建了一堆索引、存儲過程、函數、視圖、序列包括物化視圖等等
都是爲了配合我們對數據庫的數據的檢索以及處理而產生的一些對象
但是對數據庫來講最基礎的我們最關心的最關注的就是表


數據庫裏面存儲的是表
表就是實實在在的這麼一張表


oracle數據庫的體系結構裏有
控制文件、redolog文件、dbf數據文件
數據文件裏面放的很簡單是表


dbf文件有它的結構組織
只要這個dbf文件屬於oracle數據庫就被分成一個一個大小相等的塊
大小可以是通常的8K
可以是4K、2K也可以是16K、32K
一般的都是8K


可以看一下我們使用的數據庫塊的大小


老師在課程中使用了
export NLS_LANG=american_america.zhs16gbk
是因爲它的環境中參數NLS_LANG設置有問題
導致很多字符輸出的亂碼,
而我的環境變量已設置正確不會出現字符輸出亂碼
如果已經設置正確了不用去理會。
前面在軟件安裝準備工作中講過
oracle用戶此環境變量可在此用戶的 .bash_profile文件中設置


關於數據庫塊的環境變量
SQL> show parameter block

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_buffers                     integer     0
db_block_checking                    string      FALSE
db_block_checksum                    string      TRUE
db_block_size                        integer     8192
db_file_multiblock_read_count        integer     16

有這麼一行
db_block_size                        integer     8192
說明當前數據塊的大小是8K


oracle數據庫裏面dbf文件被分割成了無數個8K大小的塊
在dbf拿出一個來時就是一個block


oracle的塊block是oracle的io的最小單位


2)段、區、塊的概念


段可以這樣認爲:一個表就是一個段


建一個表
SQL> create table t2(id int,name varchar2(20));

Table created.

對oracle數據庫來講建立了一個表t2
在oracle數據庫裏它自然給你建一個段,段名t2


我們講分區表會有很多段現在不要想這麼多
現在姑且認爲一個表一個段


然後可以插入數據
SQL> insert into t2 values(1,'xkj');

1 row created.

SQL> insert into t2 values (2,'jiagulun');

1 row created.

SQL> commit;

Commit complete.

剛纔給演示的過程在oracle數據庫裏面的體現


首先來講建了一個表t2
oracle數據庫建了一個段t2
在dbf文件裏面
oracle爲t2分配一個區


一個表就是一個段
你建了一個表同時建了一個段
段一旦建了以後
oracle做的第一件事情給一個段分配一個區
區的英文extent(區域)
區的概念是物理上連續的多個塊


這裏比如8個塊做爲一個區給t2這個段
這個區是8個連續的oracle塊全部屬於t2這個段


建完以後我們開始插入數據
段的前幾個塊被段自己使用了,數據部分從後面開始
insert into開始插入一行行數據
插入數據時oracle會
找一個空塊然後把數據一行行的寫進去
寫滿了這個塊以後
接着寫第二個塊、第三個塊
第八個塊寫滿了的時候
我們給它分配的區已經用滿了
區既然都用完了oracle接着再分配一個區
還是八個塊
這時候這個段又有了新的一個區又有了8個塊可用
接着再插入數據
再用完了再給它分配一個區


建表自然就建了一個段
接着給這個段分配一個區
oracle就可以使用區裏面的一些空塊
用完後再分配新區


區是oracle給段分配空間的最小單位
也就是oracle給段分配空間的時候一次性分配一個區
不是分配一個塊是一次性分配一個區

3)
塊是oracle I/O的最小單位

dbf文件上有好多塊
表t2在這些塊裏面
現在我要訪問t2
要訪問t2裏面的某個塊
塊裏面放的是數據行
原則上來講一個塊裏面放多個行
一般的情況不會出現一個行在多個塊裏面


但在發生了行鏈接、行遷移行爲和保存數據類型爲long或lob的情況下
可能會出現一個行
在一個塊裏面有點在另外一個塊裏也有點


到目前爲止就認爲一個塊裏面有多個行


比如我要訪問某個行
select * from t2 where id=10;
oracle計算髮現要訪問的這個行在某個塊裏面
這個塊裏面有20行,但你只訪問其中一行
這時oracle不會只讀其中一行
oracle會向磁盤發出I/O請求去請求一個塊
這時操作系統會把整個塊讀到內存裏面去
然後cpu會在這個塊裏面找到我們需要的那一行
把這一行讀出來返給用戶
oracle IO的最小單位是塊是oracle塊
就是db_block_size值確定的大小的塊


有人說了oracle太笨了
你只是要讀其中一行數據
假設這一行所在塊8K
這一行只有400個300個字節
爲了讀300個字節把整個塊全部讀到內存裏面去
大家認爲oracle很笨


其實原因又回到我們以前的緩存的概念
和我們講的物理硬盤的工作原理


對硬盤來講一次IO裏面最主要的是尋道時間
一次尋道甚至佔到一次IO的90%的時間
我們要讀這個塊至少要發生一次尋道
然後我們把整個塊讀出來


如發生了尋道花了10ms
讀一行需要花1ms,讀塊中所有20行需要花1.2毫秒
差不多這個時間比例
1.2和1相對10ms來講都很小
所以我把整個塊讀到內存裏面去合適
還有一個概念
oracle讀了這一行以後
接着再讀這一行上面的和下面的行機率是很大的
就是我把整個塊讀到內存去以後
有可能在接下來的10個8個讀裏面oracle都會讀這個塊裏面的內容
所以oracle的io的最小單位是塊而不是行



講到目前爲止講了兩個概念
1、講了段區塊的概念
區是oralce給段分配空間的最小單位
區是物理上連續的幾個oracle塊
2、塊是oracle IO的最小單位
oracle要從dbf裏面取一行十行
這時oracle都是以塊爲單位去發出io請求的
io的最小單位是塊


二)buffercache的兩個意義


1)block和buffer


oracle的內存結構中SGA內存中
有sharedpool、logbuffer
最大的是buffercache


硬盤中有
控制文件 和 dbf 和 logbuffer


sharedpool裏面存儲的主要是sql語句和執行計劃以及我們的數據字典
logbuffer裏面存的是日誌


buffercache和dbf是對應的
dbf的數據會被調到buffercache裏面
也就是buffercache緩存的是dbf的數據
dbf文件都被分成了大小相等的多個block塊大小爲8K
自然buffercache也要被劃成一個一個的塊我們給它起名叫buffer


所以在dbf裏面一個塊就一個block
內存裏面塊叫一個buffer
block和buffer是一一對應的
都是8K


2)buffercache第一個意義


buffercache最主要的意義有兩個


第一個意義緩存dbf文件


我們要訪問t2的某一行
比如t2的第11行
這時oracle經過計算以後發現t2的第11行在某個塊裏面
而oracle IO的最小單位是block
這時oracle 發出一個IO請求
傳達給操作系統,操作系統傳給文件系統,文件系統傳達到磁盤上
最終這個塊被調入到內存裏面去成了一個buffer


dbf裏的塊block和buffercache裏面的buffer對應了
然後oracle就從這個buffer塊裏面把11行取出來
這個時候我們說oracle發生了一次物理的io,從磁盤到內存


接着oracle要讀t2的第12行
oracle要讀一個表的時候首先到buffercache裏面去找
看看錶對應的塊有沒有在內存裏面


oracle要讀一個表就是訪問一個段
這時候oracle有能力計算出來
要訪問的這個表的這個行所對應的這個段
這個行在這個段的那個塊裏面


oracle要讀t2的11行的時候
oracle發現它需要讀這個段的比如說第8個塊
到內存裏找
發現這個段的第8個塊沒有在內存裏
這時候就認爲在磁盤上
就到磁盤上去把這個塊讀到內存裏面去
讀進來以後然後再把11行讀出來
接着oracle讀12行
讀第12行的時候
oracle發現第12行是段的第8個塊
在內存裏面找正好在內存裏面找到了這個段的第8個塊
確實在內存裏
這時oracle就直接在內存裏面把這個塊給讀了
不需要再到磁盤上去讀


這時候我們發現oracle在讀這個塊的時候命中了一次


oracle接着讀13行的時候發現還是這個塊
在內存裏又找到了


發生三次讀其中一次物理讀兩次邏輯讀
結果賺了
這就是以前我們講過的命中率的概念


物理io就是塊block從磁盤到內存叫物理io
邏輯io就是所讀的數據塊直接在內存裏面
物理io叫磁盤讀
邏輯io叫內存讀


buffercache裏面也有命中率的概念
而且buffercache裏的命中率比sharedpool的命中率更重要
因爲給buffercache來講只要是沒有命中一定發生物理讀
只要是物理讀一定有尋道,就一定有磁盤的旋轉
就一定產生相對比較差的性能
這就是講的buffercache的其中一個作用
緩存dbf從而減少物理io


3)buffercache第二個意義


在buffercache裏面除了緩存block以外
第二個意義構造cr塊


cr塊和oracle的隔離級別有關係


隔離級別(isolation level),是併發控制的整體解決方案,是指事務與事務之間的隔離程度,
來解決事務併發效率和異常控制。
鎖是數據庫併發控制的內部機制,是基礎。
對用戶來說,只有當事務隔離級別無法解決一些併發問題和需求時,纔有必要在語句中手動設置鎖。


在多事務環境下,事務隔離對產生cr塊有影響


一個會話
這裏暫且認爲是一個sqlplus登上來了


提交的概念:
比如做了insert語句
這時候insert修改並沒有真真實實的保存起來
只有commit以後
才能實實在在的保存起來


oracle有這麼一個原則
一個會話所修改的數據在沒有commit以前
別的用戶是看不到的


前面的課程中我們已經在t2裏面插入了兩行數據
並且已經提交了
現在另外再起一個會話執行
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun
原會話中的執行結果看到了,因爲它已經提交了


也就是說oracle數據庫裏面
我可以直接讀已經提交的數據


假設另外做一件事情
現有兩個會話
會話1中:
SQL> delete from t2 where id=1;

1 row deleted.
刪了一行,t2表中有兩行刪了一行
但是沒有提交


會話2再來讀這個塊的時候
會話1已經把這一行刪了
這個行在這個塊裏沒有了
會話2要讀這個塊
因爲會話1還沒有提交
就是對塊的修改還沒有提交
會話2不能直接讀這個塊


這樣會話2會在內存裏面在buffercache裏面再單獨的申請一個新塊
將數據填進新塊
第二行因爲沒有修改直接填回來
第一行因爲已經修改了但是還沒有提交
這時這個會話2會把第一行找出來
把第一行修改前數據找回來填到新構造塊裏面去


第一行盡然在原塊裏面被刪了
會話2去哪裏找這一行呢


oracle數據庫裏面
有這麼一堆dbf我們叫回滾數據叫undo
叫undo空間
這些文件只做一件事情
會話1刪了一行數據
這時候被刪的數據就會進到undo裏面去
也就是原來這個塊裏面被修改的修改前的數據被寫到undo裏面去


會話2讀這個塊的時候
發現這個塊裏有一個行被刪了但刪還沒有提交
它就會到undo裏面去找到這一行
把它寫到新構造塊裏面去
這時對會話2來講
就放棄對原塊的讀
直接讀新構造塊


再看實例
會話1已經把t2的一行刪了
在會話2中讀:
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun
我們發現還是兩行

會話2讀原塊的時候t2只剩一行了,爲什麼讀出來兩行呢
是因爲會話2讀這個塊的時候發現這個塊裏面的第二行沒有被改變直接寫過來
第一行被改變了而且還沒有被提交
於是就去undo裏面把已經改變沒有提交的改變前的數據寫到這個塊裏面去
然後讀出來


這個新塊就叫cr塊


oracle數據庫在改變一個塊以前
它會把改變前的數據寫到undo裏面去
undo的作用在刪完一行數據可以後悔
認爲刪錯了可以強制執行一個命令rollback


會話1中
先讀一下當前數據
SQL> select * from t2;

        ID NAME
---------- --------------------
         2 jiagulun


然後回滾


SQL> rollback;

Rollback complete.

rollback,就是把上次提交以後
到目前數據的改變恢復出來


當前在會話1中就是把
delete的操作取消了
原理是在undo裏面把修改前的數據給複製覆蓋回來


再去讀
會話1中:
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun
會話2中:
SQL> select * from t2;

        ID NAME
---------- --------------------
         1 xkj
         2 jiagulun
結果是兩行。


目前爲止undo有幾個作用
第一個
可以對沒有提交的操作回滾
第二個作用
構造cr塊
構造cr塊需要的空間在buffercache裏面


buffercache有兩個作用
一個緩存block,減少物理io,這裏面有命中率的概念
一個構造cr塊


oracle可以辦到:
我做了一些操作我只要沒提交我就可以回滾,就是可以後悔,取消前面的修改
只要未提交,別的會話就看不見修改,看不見怎麼實現呢,就是通過cr塊


這節講了block、buffer包括undo等等這些概念


2016年9月10日
    文字:韻箏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章