1. 程式人生 > >Oracle學習筆記 深入剖析事務槽及Oracle多種提交方式

Oracle學習筆記 深入剖析事務槽及Oracle多種提交方式

Oracle 學習筆記

深入剖析事務槽及Oracle多種提交方式

這節課把事務槽和oracle事務的提交方式講一下
講完以後再去回顧上節課講的oracle的undo裡面的事務的整個操作過程的時候大家就更清晰了

一)事務槽數量引數

每一個oracle資料塊裡面在資料塊的頭部都有事務槽

事務槽的數量可以去查一下

比如資料庫中有一個表t2,可以查一下這個表的事務槽的數量

SQL> select INI_TRANS,MAX_TRANS from dba_tables where table_name='T2';

 INI_TRANS  MAX_TRANS
---------- ----------
         1
255 1 255

這個表t2事務槽的數量
預設是INI_TRANS的值1,表剛建立的時候預設值是1
最大是MAX_TRANS的值255

oracle中INI_TRANS和MAX_TRANS這兩個引數屬於單個表
在系統引數和隱含引數中都沒有這兩個引數
oracle從10g開始最大的那個MAX_TRANS的值不能改了
不管改成多少最終值總是255

預設的數量INI_TRANS可以改

因為這個屬性屬於單個表,
可以在建表的時候指定值,也可以在建表後使用修改語句修改表的這個屬性

INI_TRANS指這個表分配新資料塊時,資料塊有事務一開始資料塊就擁有的事務槽的數量
可以在建表時的語句中指定值,預設值是1,
這樣這個表分配的資料塊初始時就有INI_TRANS值的事務槽
也可以在建表後使用alter table命令修改
如:ALTER TABLE T10 INITRANS 4;
修改後這個表
原來已有資料塊的初始事務槽數量仍保持原值
修改後新建的資料塊的初始事務槽數量就是修改後的值

這是關於事務槽的數量
一般我們不去改,預設是1最大是255

二)事務槽爭用

一個數據塊裡面放了很多行
底下有很多的資料行
上面開始預設一開始有1個事務槽

當要修改資料塊的時候
修改包括增加、刪除和更新
不管哪個操作要對這個塊進行操作的時候
首先要在這個塊獲取到一個事務槽
將事務資訊將xid寫上
同時還要寫uba地址就是回滾塊的地址

資料塊中事務槽的xid指向事務表,uba指向回滾塊

然後對資料塊進行操作進行修改
修改了以後把修改前的資料寫到回滾塊裡面去

當一個事務A事務對這個資料塊進行操作的時候
獲取到一個事務槽

一個事務可以在資料塊中修改多行
但只需要一個事務槽就可以

有可能另外一個事務B事務也要對這個資料塊進行修改
這時候它需要獲取第二個事務槽

事務槽是以事務為單位的

A事務在資料塊裡面獲得事務槽以後修改了幾行,一直沒有提交
沒有提交這個事務槽就不能被覆蓋

只有這個事務被提交以後這個事務槽才能被覆蓋
這個點很關鍵

B事務上來後也要分一個事務槽

C事務也要修改這個資料塊的話也要分配一個事務槽

一個數據塊我們知道有一個pct free 10%

資料塊上面是塊頭的事務槽
底下是資料行
中間留10%的空間

留10%是為了將來
1、我更新底下的資料的時候資料可能往上佔空間
2、當有多個事務同時修改塊的時候需要增加事務槽的數量,塊頭的資料要往下壓

增加資料行往上壓,增加事務槽往下壓
10%的空間是預留給這個用的

有可能出現這個情況
多個事務同時修改這個資料塊
產生了非常多的事務槽
這個時候我們發現這裡面只能擱四個事務槽,再往下就沒空間了
第5個事務再要修改這個資料塊的時候
它就會要等待前面的四個事務槽去提交

這叫事務槽的爭用ITL爭用
事務槽英文叫ITL(Interested Transaction List)
ITL是Oracle資料塊內部的一個組成部分,位於資料塊頭

如果事務槽的爭用這種情況發生可以把pct free增加一些

比如有一個批量的插入操作
表t分配一個區,這個區有八個塊
有三個事務同時往t裡面做insert做插入操作

而一個數據塊預設有1個事務槽

如果說這三個事務同時往一個塊裡插入的話
這時oracle需要額外的增加兩個事務槽
在原有有一個事務槽的基礎上在一個數據塊增加兩個事務槽
就會額外的佔用空間

針對這種情況
往一個表中多個事務並行插入資料的時候

第一個事務使用一個塊
第二個事務我優先使用第二個塊
第三個事務優先使用第三個塊

oracle為了避免事務槽的爭用
儘量的對insert操作分佈到多個塊裡去,減少事務槽的爭用問題

但是對於delete和update往往就無能為力了
一個事務更新的這行就在這個塊裡面
另外一個事務更新的這行也在這個塊裡面
第三個事務也在這個塊裡面
就沒辦法了

更新和刪除
往往是針對某些具體的行進行更新和刪除
這個時候這個行就在這個塊裡面
這個事務沒有辦法就必須增加事務槽

容易發生事務槽爭用的主要集中在update和delete上

三)dump事務槽

1)準備和收集資訊

我們建一個表
然後把事務槽給dump出來來看一下

建一個表

SQL> create table t10(id number(5),name char(2000));

Table created.

SQL> desc t10;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER(5)
 NAME                                               CHAR(2000)

然後insert資料

SQL> insert into t10 values(1,'aa');
insert into t10 values(2,'bb');
insert into t10 values(3,'bb');
insert into t10 values(4,'cc');
insert into t10 values(5,'dd');
commit;
1 row created.

SQL>
1 row created.

SQL>
1 row created.

SQL>
1 row created.

SQL>
1 row created.

SQL>

Commit complete.

提交了

執行select * from t10;
結果有資料
name列比較長總體結果顯示的有些亂
這裡不用看這個語句的結果,就不列出來了

然後執行

SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid),id from t10;

DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)         ID
------------------------------------ ------------------------------------ ----------
                                   1                                60786          1
                                   1                                60786          2
                                   1                                60786          3
                                   1                                60787          4
                                   1                                60787          5

有5行資料

ID為1、2、3、4、5,對應原表t10中的ID列
id為1的為第一行

DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)為所在檔案號
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)為所在塊號

第1行ID為1的行在1號檔案的60786塊

這五行佔了兩個塊
檔案號都一樣,塊是60786和60787兩個塊

然後更新一下t10表
更新是一個事務

SQL> update t10 set name='abcd' where id=1;

1 row updated.

更新以後去查一下

SQL> select ubafil,ubablk,xidusn,xidslot,xidsqn,start_scnb from v$transaction;

    UBAFIL     UBABLK     XIDUSN    XIDSLOT     XIDSQN START_SCNB
---------- ---------- ---------- ---------- ---------- ----------
         2        750          8         24        422          0

建一個表插入資料提交
然後對這個表又做了更新
更新了一行就更新了一個數據塊

UBAFIL和UBABLK
代表著回滾塊資訊
XIDUSN 和XIDSLOT 和XIDSQN
是 回滾段的編號、事務表的編號、還有被覆蓋多少次

前面的UBAFIL UBABLK XIDUSN XIDSLOT XIDSQN
這5個資訊從事務表來的

一個事務在事務表中有xid還有指向uba
它裡面查的xid包含
XIDUSN段號、XIDSLOT事務表裡的槽位號、XIDSQN被覆蓋次數
就是xid分解出來的
UBAFIL、UBABLK這兩個資訊就是指向的uba,uba的地址

2)dump回滾段頭塊

這時候回滾段的編號知道了
這裡XIDUSN的值是8號回滾段

編號知道了就可以把段的名字找出來

SQL> select * from v$rollname;

       USN NAME
---------- --------------------
         0 SYSTEM
         1 _SYSSMU1$
         2 _SYSSMU2$
         3 _SYSSMU3$
         4 _SYSSMU4$
         5 _SYSSMU5$
         6 _SYSSMU6$
         7 _SYSSMU7$
         8 _SYSSMU8$
         9 _SYSSMU9$
        10 _SYSSMU10$

11 rows selected.

結果中8號段名字為_SYSSMU8$

知道這個段以後

alter system dump undo header ‘_SYSSMU8$’;
可以把段頭給dump出來

SQL> alter system dump undo header '_SYSSMU8$';

System altered.

然後找一下當前會話的編號

SQL> select spid from v$process where addr in (select paddr from v$session where
        sid=(select sid from v$mystat where rownum=1));  2

SPID
------------
6066

執行dump命令的會話的編號為6066

可以去找那個檔案了
找到檔案6066trace檔案可以vi看了

3)dump回滾塊

當然還可以dump塊

    UBAFIL     UBABLK 
---------- ---------- 
         2        750

2號檔案的750塊

使用命令
alter system dump datafile 2 block 750;
就可以把這個回滾塊dump出來

回滾段的段頭塊可以dump出來
回滾段的回滾塊可以dump出來

4)dump資料塊

還可以dump id等於1的資料行所對應的資料塊

我們查一下id等於1的行所在資料塊是誰

SQL> select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid),id from t10;

DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)         ID
------------------------------------ ------------------------------------ ----------
                                   1                                60786          1
                                   1                                60786          2
                                   1                                60786          3
                                   1                                60787          4
                                   1                                60787          5

結果中id等於1的資料行所在的資料塊為1號檔案的60786資料塊

alter system dump datafile 1 block 60786;
就可以把這個資料塊dump出來了

先退出會話再重新建立會話以得到不同的程序編號

SQL> alter system dump datafile 1 block 60786;

System altered.

這個dump出來的就是資料塊的資料,就是資料塊的具體的資訊

然後具體的查一下執行dump的程序是哪個程序編號

SQL> select spid from v$process where addr in (select paddr from v$session where
        sid=(select sid from v$mystat where rownum=1));  2

SPID
------------
7519

由於改變了會話,程序編號和上面的不一樣了,現在為7519

去系統目錄找一下得到的trace檔案

[[email protected] udump]$ pwd
/u01/app/oracle/admin/jiagulun/udump
[[email protected] udump]$ ls
jiagulun_ora_10692.trc  jiagulun_ora_13841.trc  jiagulun_ora_24967.trc
jiagulun_ora_11994.trc  jiagulun_ora_17335.trc  jiagulun_ora_27148.trc
jiagulun_ora_12910.trc  jiagulun_ora_18203.trc  jiagulun_ora_27861.trc
jiagulun_ora_13393.trc  jiagulun_ora_19827.trc  jiagulun_ora_29885.trc
jiagulun_ora_13449.trc  jiagulun_ora_20062.trc  jiagulun_ora_30323.trc
jiagulun_ora_13450.trc  jiagulun_ora_2020.trc   jiagulun_ora_32457.trc
jiagulun_ora_13475.trc  jiagulun_ora_20217.trc  jiagulun_ora_3940.trc
jiagulun_ora_13525.trc  jiagulun_ora_20471.trc  jiagulun_ora_3944.trc
jiagulun_ora_13529.trc  jiagulun_ora_20922.trc  jiagulun_ora_4044.trc
jiagulun_ora_13547.trc  jiagulun_ora_21317.trc  jiagulun_ora_6066.trc
jiagulun_ora_13550.trc  jiagulun_ora_21344.trc  jiagulun_ora_6443.trc
jiagulun_ora_13551.trc  jiagulun_ora_21549.trc  jiagulun_ora_6616.trc
jiagulun_ora_13567.trc  jiagulun_ora_21871.trc  jiagulun_ora_6643.trc
jiagulun_ora_13592.trc  jiagulun_ora_21898.trc  jiagulun_ora_6644.trc
jiagulun_ora_13617.trc  jiagulun_ora_21901.trc  jiagulun_ora_7317.trc
jiagulun_ora_13633.trc  jiagulun_ora_21929.trc  jiagulun_ora_7519.trc
jiagulun_ora_13660.trc  jiagulun_ora_21978.trc

jiagulun_ora_7519.trc檔案就是dump出來的檔案

資料塊內容很多

資訊中有事務槽部分

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0001.017.00000147  0x0080000a.0101.33  C---    0  scn 0x0000.000c6571
0x02   0x0008.018.000001a6  0x008002ee.0114.0e  ----    1  fsc 0x0000.00000000

其中

0x02   0x0008.018.000001a6  0x008002ee.0114.0e  ----    1  fsc 0x0000.00000000

為我們使用的新的事務槽

0x0008.018.000001a6為事務id
0x008002ee.0114.0e為uba
Flag為是否已提交標誌
Lck為鎖標記
等等

5)dump總結

本節講了三種塊的dump方式,包括undo段段頭塊,回滾塊,普通資料塊

總結如下:

1、事務開始後,要得到這個事務的xid和uba資訊
select ubafil,ubablk,xidusn,xidslot,xidsqn,start_scnb from v$transaction;
這些資訊中包含該事務使用的回滾段和回滾塊的資訊
dump出段頭塊和回滾塊要依此開始

2、dump出回滾段頭塊
根據事務資訊找到事務使用回滾段的編號,依此找到回滾段的名字
select * from v$rollname;

以回滾段名dump
alter system dump undo header ‘_SYSSMU1$’;

也可以以回滾段名找到回滾段頭塊的地址包括檔名和塊號
select header_block,header_file from dba_segments where segment_name=’_SYSSMU1$’;
使用dump出資料塊的方式得到段頭塊
alter system dump datafile 2 block 9;

dump undo header方式得到段頭塊資訊檔案,解讀了檔案中所有的資訊
dump datafile方式段頭塊中的有些資訊沒有解讀,直接以二進位制方式提供出來了

3、dump出回滾塊
事務資訊中的ubafil、ubablk代表了事務使用的回滾塊的檔案號和塊號
依次可dump出回滾塊
alter system dump datafile 2 block 750;

4、dump出普通資料塊

先得到普通表中每條記錄對應的資料塊
select dbms_rowid.rowid_relative_fno(rowid),dbms_rowid.rowid_block_number(rowid),id from t10;
依此dump出普通資料塊,這種方式可以精確到一條記錄所在的資料塊

alter system dump datafile 1 block 60786;

也可以先得到資料段的第一個塊的地址
select header_file , header_block from dba_segments where segment_name=’T10’;
或者根據
select * from dba_extents where segment_name=’T10’;
得到段的所有區塊的統計資訊
然後dump出這個段的其中的一個數據塊

5、檢視dump出來的資料塊內的資訊
得到執行dump命令的程序的id
select spid from vprocesswhereaddrin(selectpaddrfromvsession where
sid=(select sid from v$mystat where rownum=1));
預設dump出的檔案在/u01/app/oracle/admin/jiagulun/udump目錄下
檔名中包含上面得到的serverprocessID
找到檔案然後vi看

vi jiagulun_ora_21978.trc

四)詳解ITL

一個事務槽例子

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x000a.012.0000027a  0x00800702.012d.07  C---    0  scn 0x0000.001f45ce
0x02   0x0008.008.000002e9  0x0080238e.02c7.22  C---    0  scn 0x0000.001f45c7
0x03   0x0009.026.00000313  0x00800044.0166.0c  ----    7  fsc 0x0031.00000000

這是展示的一個事務槽
是講課老師做過的做出來的一個事務槽

剛才演示了一系列操作
就是如何找到資料塊,如何找到undo段頭,如何找到undo塊
把這三個找到
然後如何dump出來然後vi去研究

我們看事務槽,事務槽裡面有哪些資訊

第一列為事務槽編號Itl編號

還有事務id(transaction identifier)即Xid
事務id指向具體的事務,並指向回滾段段頭塊裡面的事務表裡面的記錄
格式:xidusn.xidslot.xidsqn
分為三部分
包括:這個事務使用的回滾段號.在回滾段頭事務表中的記錄位置.這個位置已被覆蓋的次數

uba指向具體的回滾塊中的記錄
格式:uba(undo block address).UBASQN.UBAREC
地址也分三段
第一段:回滾資料塊的地址,就是在回滾段內的塊號
第二段:undo塊被重用的次數,第三段:在undo塊的第幾條記錄

Flag為事務標誌位,記錄了這個事務的狀態,如事務是活動的還是已提交等

Lck為這個事務擁有的鎖的數量,也可理解為影響的記錄數

Scn/Fsc提交方式為普通提交時標記為scn,為快速提交則先標記為fsc,
然後後面都再跟上scn值就是提交時的一個時間點

undo段頭事務表裡面也類似有這些資訊
一個事務即在事務表裡有資訊在事務槽裡面也有資訊

五)資料塊中存放事務資訊的意義

一個事務開始以後
首先在回滾段,回滾段頭的事務表裡面找到一個事務槽
同時分配一個回滾塊
事務表指向回滾塊
事務表中這條資訊有xid、是否已提交標誌

然後修改一個數據塊
資料塊分配一個事務槽
事務槽指向undo段頭事務表中的一條事務記錄

資料塊事務槽的uba指向的是對應的undo塊
事務槽還有是否已提交標記

然後在資料塊中修改資料行
資料行行的頭部指向資料塊的事務槽

修改了三個資料行
這三個資料行的頭部都指向資料塊頭部的這個事務對應的事務槽

我要修改一個數據塊首先在事務槽分配事務

如這個事務的事務槽是1號事務槽
這個事務修改了三行
在這個事務每個被修改的行的頭部都寫上1
就是都指向1號事務槽

一個事務正在修改這個資料塊
事務的資訊在事務槽裡面寫了

這個事務修改了3行
這三行都指向事務槽
槽裡面有事務提交標誌

另外一個事務再來修改這個塊的時候
它又獲取另外一個事務槽,如獲取了2號事務槽

二號事務也可能要修改一號事務修改的一個數據行
當他修改資料行的時候,發現這個資料行的頭部寫的1
它就知道目前有一個事務,1號事務槽的事務正在修改這個行

對這個行,1號事務有兩種情況
第一種情況已提交,第二個情況未提交

如果已提交的話
對應事務的事務槽會寫了已提交標誌
它就可以覆蓋這個行了

如果他發現事務槽中的已提交標誌沒有寫的話
它就認為對應的這個行還沒有提交
沒有提交的話兩個事務不能同時修改一個行

在一個數據塊裡面
有事務資訊及有一個關於一個事務是否已提交的標誌是有意義的

假設在這個資料塊裡面沒有這個資訊
也就是說對oracle資料庫來講,關於某個事務只有回滾段段頭有
這時我要讀這個資料塊的時候,要修改這個資料塊的時候
要修改一行的時候
這個行到底有沒有被事務修改只能查undo段頭裡的事務表
查它才能知道這個行被誰修改了、事務有沒有提交
所有的修改都會查回滾段段頭
這樣的話會出現段頭的爭用,不現實

這就是為什麼我要把事務資訊
即寫在回滾段段頭裡面,也要寫在每個資料塊的事務槽裡面
就是因為
我將來訪問資料塊某個行的時候
我要看這個行有沒有被修改
有沒有被事務修改、被哪個事務修改、修改它的事務有沒有提交
這個資訊在本身這個資料塊裡就有
直接查就完了,不需要再去查回滾段段頭塊了

事務資訊在兩個地方都有是有意義的

六)快速提交

1)產生原因

這個地方有個問題涉及到oracle的一個提交方式

假設一個事務修改了1000個塊
修改了一千個塊以後要提交
提交以後這個事務必須把事務的提交標誌置成已提交

一個事務修改了1000個塊
意味著關於這個事務的資訊在1001個地方有
因為每個資料塊裡面有事務資訊,還有undo段頭有事務資訊
在1001個地方有這個關於事務的資訊

我提交了,在1001個地方把事務提交的狀態都給它寫上
會出現commit提交的速度會很慢,因為要訪問1001個塊

況且還有另外一種情況

修改了一千的塊,這個事務持續的時間很長
在這個過程裡面
這1000個塊裡面其中有800個塊已經寫到磁碟了
因為dbwr寫的時候就什麼也不管,它不管你有沒有提交
寫到磁碟,記憶體中原有塊就是乾淨塊了
乾淨塊就可能被覆蓋

也就是說我提交的時候
我發現修改了1000個塊
只有200個塊或者只有300個塊在記憶體裡面
還有另外700個塊在磁碟上
為了提交這個事務
還有把那700個塊讀到磁碟
如果是這樣的話提交速度會很慢

我們把事務資訊寫到資料塊裡面和undo段裡面,寫兩份是有好處的

將來oracle更新資料行的時候
找這個資料行對應的事務資訊的時候從塊找就可以很方便

但是帶來另外一個問題
oracle提交的時候要過多地在很多地方修改事務資訊
這時候帶來提交慢

所以說為了解決這個問題
oracle推出一個技術叫快速提交

2)原理

oracle提交的時候
如果發現這個事務這次所修改的資料塊過多
它會只是更新undo表空間裡面的事務資訊
只把undo段頭裡的事務資訊更新了
資料塊裡的那些事務槽,它不更新或者更新少量

這樣提交速度會很快
也就是說回滾段段頭裡的事務一定最能準確的代表著這個事務是否已提交
但是普通資料塊裡面的事務槽的資訊,那裡面是否已提交不怎麼準確

如果資料塊資料槽這裡面寫了已提交那肯定已提交了
如果寫了未提交就不見得未提交

3)舉例

回滾段裡有事務資訊
資料塊裡有事務資訊

資料塊裡有三個行被修改了
資料塊上面有事務槽

事務資訊在所修改資料塊裡有
在回滾段裡也有

oracle要修改資料塊裡一個行
另外一個事務也要修改這個行
它也佔用一個事務槽

但被修改行的事務資訊指向第一個事務槽
就意味著
第二個事務要修改這個行
這個行又指向第一個事務的事務槽

第二個事務就讀一下第一個事務槽
看一下第一個事務對應的事務槽
看一下第一個事務是否已經提交

如果已提交的話
第二個事務就可以直接修改這個資料行
因為已提交肯定是準確的

如果他發現這個事務未提交
它就懷疑了
懷疑這個第一個事務槽所對應的事務不一定未提交
有可能已提交了當時這個提交的時候沒有清理
要去查undo段頭的事務表
查事務表裡面的事務槽

在資料塊的事務槽有個xid
通過xid找到事務表

資料塊事務槽指向undo段頭事務表這時有意義了

一查undo段頭的事務表這個事務已經提交了

第二個事務會相信undo段頭的事務表而不相信資料塊中的事務槽

這時它不但更新要修改的行
這行更新以後這個資料行指向第二個事務在資料塊中的事務槽
而且
它一塊兒把第一個事務對應資料塊中事務槽的事務狀態置成已提交

第二個事務做很多事情
幫第一個事務掃掃尾
在一次訪問裡面無所謂

七)事務資訊的指向總結

undo段頭事務表 資料塊事務槽 和 回滾塊 的關係

1、我們講了undo段頭事務表指向這個事務最新undo塊,並且對應的所有undo塊是串起來

2、資料塊頭部事務槽直接指向這個事務對這個資料塊最新修改對應的最新回滾塊

3、資料塊的事務槽也指向undo段頭事務表,和提交方式有關係

這三個點很重要,都有意義

八)行級鎖和事務資訊的清理關係

我們看oracle的提交分幾步

最徹底的提交
undo段頭事務表肯定被修改
資料塊中對應的事務槽也被修改
事務槽對應的資料塊資料行裡面的標記也被修改

如果說提交而提交地最徹底的話
undo段頭事務表被修改
事務槽裡面的事務狀態被修改了
同時資料行前面的事務槽標誌也被修改

如果資料行這個標誌是空的,這個行沒有被修改
這個資料行被修改了,
它就寫一個事務槽的標記指向資料塊的事務槽
相當於我在這個資料行加了一個鎖

一個事務修改這個資料塊
獲得一個事務槽1號事務槽
修改這個資料行
就在這個資料行的前部加一個數字1指向事務槽1
相當於在這個資料行加了一個鎖

第二個事務要修改這個資料行的時候
一看上面有一個鎖
它就根據鎖找到資料塊中鎖對應的事務槽
看它是否已提交
如果事務沒有提交的話,它不能修改這個行

在這個資料行的前面加了一個事務槽的編號就相當於加了個鎖
這就是oracle裡面非常有名的叫行級鎖
在行的級別上加了一個鎖
這個開銷不大,直接加個數字就行了
這就是oracle的行級鎖

oracle和sqlserver不一樣
sqlserver是修改資料塊的時候在塊上加一個鎖叫塊級鎖
不能兩個事務同時修改一個塊
但是oracle可以,因為oracle是行級鎖
兩個事務可以同時修改一個數據塊,只要行不衝突就行
oracle的併發性好一些

所以說sqlserver是塊級鎖,oracle是行級鎖
行級鎖併發性好一些,而且又沒有多大的開銷很靈巧

所以說對oracle來講最徹底的提交方式
undo段頭事務表、資料塊中的事務槽還有資料行的鎖標記
如果這三個都清了,那是最徹底的提交方式

但是oracle如果修改的資料塊過多
它會只清undo段頭和少量的資料塊

一般的情況它第一次提交的時候只會清undo段頭事務表和事務槽
有時候資料行的鎖定標記經常不清
訪問的時候再清一次
這就看這次事務修改多少塊了
這就是我們講的oracle的一個工作機制

九)行鎖、事務槽、事務表中事務的提交狀態關聯作用

1)行鎖未清、事務槽標記已提交

oracle的select查詢有時候也會產生redo,很奇怪

我們知道只有增刪改產生redo
我們來看查詢產生redo的原理

oracle事務有undo段頭、資料塊事務槽、資料行、回滾塊
資料行指向事務槽
事務槽指向undo段頭事務表
資料塊事務槽直接指向回滾塊

舉個例子看oracle的查詢

oracle的select要訪問一個數據塊
訪問這個資料塊的一行
訪問這個行的時候發現這個行的前面有鎖定標記,就是行有鎖
說明有可能某個事務正在修改這個塊

這個select不能直接查詢
要根據資料行這個鎖定標記找到對應的事務槽
它發現事務槽裡面有資訊
事務槽裡的事務是否已提交的資訊
有可能這個事務已提交但是沒有清鎖
這時select就直接讀這個行
但是這個select會把這個鎖標記給它去了
就是把原來的那個資料行指向事務槽的鏈打斷

select做了一件事情
查這個行的同時把這個行的鎖也清了
因為它發現這個行所對應的事務已提交了
只是鎖倒是沒有清,它幫他清了

select讀行,但是結果修改了行
所以有時select也會產生日誌

2)鎖未清、事務槽標記未提交、事務表標記已提交

select還有一種情況
讀行時行有行鎖

它就找這個事務對應事務槽
它發現事務槽沒有提交
沒有提交就有可能是這個事務有可能已提交了

select就讀事務表
事務表絕對準確
在事務表發現這個事務已提交了
它就把資料塊中的事務槽也給清了

這時又產生日誌了

3)都未提交,構造cr塊

它發現數據行有鎖
資料塊中事務槽說事務沒提交
查undo段頭事務表也未提交
這個資料行這時候確實正在被某個事務修改著

修改著時select不能查沒有提交的事務
它根據鎖找到事務槽
再從事務槽找到undo塊
把這個undo塊和另外兩個沒有提交的行構成一個新的塊

從鎖標記找事務槽再找回滾塊
兩個沒有修改的行,加上這個修改的行
三個行拼起來組成一個cr塊
然後直接讀這個cr塊
這就是一致性讀

這個讀沒有出現髒讀
它讀的時候沒有讀未提交的事務

它讀的是上一個已提交事務

這就是select的一個讀的過程

4)事務表中這個事務沒了

另外一種情況以後還會碰到

我們知道一個數據塊
在磁盤裡面很久沒有讀出來了

這個資料塊的一個行有鎖標記
通過鎖標記找到事務槽對應的事務
這個事務寫著沒有提交

假設這個塊是昨天修改
結果塊被寫到磁碟了,結果再也沒有訪問過

然後我又根據事務槽裡的xid去事務表裡面去找

xid有三塊組成
一塊是段號一塊是槽號再有被覆蓋了多少次

假設段號是8號,在段第15個槽,被第13次覆蓋
結果找的時候發現
這個8號段的15號這個槽位已經被第15次覆蓋了

我要找8號段的15號槽位的第13次覆蓋所對應的事務是否已提交
但是當我找到的時候發現它已經是被第15次覆蓋了

因為這個塊已經很長時間沒有被讀出來了
事務槽已經被很多次覆蓋了
這個時候
oracle不會報錯
oracle就會非常果斷地認為那個事務已提交了

如果沒有提交的話
事務表中的事務槽不可能被覆蓋
既然它都被第15次被覆蓋了
這裡第13次所對應的事務早已經提交了

然後oracle會按照原事務已提交做一系列的工作。

這節課講了
事務槽的知識
同時把行級鎖也講了
同時事務的操作流程這塊又給大家講了

2017年8月26日
文字:韻箏