Oracle一致性讀(consistents gets)
很多資料庫的併發控制方式是通過MVCC(多版本併發控制)實現的。這種方式使得資料庫可以通過讀取資料塊的快照,而不會發生讀操作阻塞寫操作的情況。Oracle通過undo回滾段實現一致性讀取。當一條sql在讀取資料塊的時候,會記錄讀取時刻的SCN1,並且將這個SCN1與讀取資料塊頭部ITL槽中的SCN2做比較,如果SCN1<SCN2,那麼說明,改資料塊在SCN1的時候沒有變動,但是經過一段時間後(硬,軟解析等過程)在SCN2時刻真正發生讀取的時候,發現在SCN2-SCN1這段時間內,資料塊變動了,那麼此時由於Oracle是RC的事務隔離級別,那麼需要構建SCN1時刻的快照塊完成讀取,這個過程就是一致性讀,即consistents gets。構建快照塊的時候,需要資料塊頭部ITL槽中的資訊,指引到相應的undo塊,如果ITL槽中有多個SCN的話,那麼取最大的那個;如果undo塊的SCN仍然大於SCN1,那麼繼續從該塊的ITL中遞迴查詢下一個undo塊,直到找到小於SCN1的undo,如果找不到的話,那就是經典的ORA-01555的錯誤了。
先來看一下一致性讀的一個例子:
drop table ming.t190514 purge;
create table ming.t190514(a int,b varchar2(20));
insert into ming.t190514 select 1,'ming' from dual;
commit;
session A發起事務但是不要提交:
update ming.t190514 set b='SHUO' where a=1;
SQL> select * from ming.t190514;
A B
---------- --------------------
1 SHUO
session B:
select dbms_rowid.rowid_relative_fno(rowid) fileno,dbms_rowid.rowid_block_number(rowid) blockno from ming.t190514;
FILENO BLOCKNO
---------- ----------
16 312790
SQL> select * from ming.t190514;
A B
---------- --------------------
1 ming
SQL> alter system dump datafile 16 block 312790;
session A update之後,session B再去查詢這張表,這個時候就需要通過一致性讀完成select了。
檢視dump出來的trace檔案:
Block header dump: 0x0404c5d6
Object id on Block? Y
seg/obj: 0x121cb csc: 0x0000000005e141e6 itc: 2 flg: E typ: 1 - DATA
brn: 0 bdba: 0x404c5d0 ver: 0x01 opc: 0
inc: 0 exflg: 0
Itl Xid Uba Flag Lck Scn/Fsc
0x01 0x0007.00f.00002d00 0x018212f3.04bf.18 C--- 0 scn 0x0000000005e141a5
0x02 0x0003.019.000039c7 0x0181df46.04e0.0b ---- 1 fsc 0x0000.00000000
bdba: 0x0404c5d6
data_block_dump,data header at 0x11e06e064
===============
tsiz: 0x1f98
hsiz: 0x14
pbl: 0x11e06e064
76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f8d
avsp=0x1f79
tosp=0x1f79
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x1f8d
block_row_dump:
tab 0, row 0, @0x1f8d
tl: 11 fb: --H-FL-- lb: 0x2 cc: 2
col 0: [ 2] c1 02
col 1: [ 4] 53 48 55 4f
end_of_block_dump
通過seg/obj驗證找到的這部分內容確實是t190514這張表。
SQL> select to_number('121cb','xxxxxxxxx') from dual;
TO_NUMBER('121CB','XXXXXXXXX')
------------------------------
74187
Elapsed: 00:00:00.00
15:01:54 SQL> select object_name from dba_objects where object_id=74187;
OBJECT_NAME
--------------------------------------------------------------------------------
T190514
lb: 0x2的falg是---。說明還有活動事務。檢視col 1的值:
SQL> select utl_raw.cast_to_varchar2(replace('53,48,55,4f',',')) value from dual;
VALUE
--------------------------------------------------------------------------------
SHUO
session A確實已經更改了資料。
查詢活動事務:
SQL> select xid,xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn,ubarec,status from v$transaction;
XID XIDUSN XIDSLOT XIDSQN UBAFIL UBABLK
---------------- ---------- ---------- ---------- ---------- ----------
UBASQN UBAREC STATUS
---------- ---------- ----------------
03001900C7390000 3 25 14791 10 122694
1248 11 ACTIVE
dump出undo塊:
alter system dump datafile 10 block 122694;
檢視dump出來的undo塊的trace:
*-----------------------------
* Rec #0xb slt: 0x19 objn: 74187(0x000121cb) objd: 74187 tblspc: 7(0x00000007)
* Layer: 11 (Row) opc: 1 rci 0x00
Undo type: Regular undo Begin trans Last buffer split: No
Temp Object: No
Tablespace Undo: No
rdba: 0x00000000Ext idx: 0
flg2: 0
*-----------------------------
uba: 0x0181df46.04e0.08 ctl max scn: 0x0000000005e0b434 prv tx scn: 0x0000000005e0b43e
txn start scn: scn: 0x0000000005e141dd logon user: 83
prev brb: 25288513 prev bcl: 0
KDO undo record:
KTB Redo
op: 0x03 ver: 0x01
compat bit: 4 (post-11) padding: 1
op: Z
KDO Op code: URP row dependencies Disabled
xtype: XA flags: 0x00000000 bdba: 0x0404c5d6 hdba: 0x0404c5d2
itli: 2 ispac: 0 maxfr: 4858
tabn: 0 slot: 0(0x0) flag: 0x2c lock: 0 ckix: 0
ncol: 2 nnew: 1 size: 0
col 1: [ 4] 6d 69 6e 67
Block dump from disk:
buffer tsn: 2 rdba: 0x0181df46 (6/122694)
scn: 0x5e141dd seq: 0x01 flg: 0x04 tail: 0x41dd0201
frmt: 0x02 chkval: 0x66fd type: 0x02=KTU UNDO BLOCK
Hex dump of block: st=0, typ_found=1
檢視col 1的值
SQL> select utl_raw.cast_to_varchar2(replace('6d,69,6e,67',',')) value from dual;
VALUE
--------------------------------------------------------------------------------
ming
還是更新之前的舊值。
update語句在執行的時候,需要先進行一致性讀,過濾where條件,然後再做當前讀,在這兩個過程的時間間隔中如果資料塊出現了變動,那麼會出現意料之外的效果。
drop table t190514 purge;
create table ming.t190514(a int,b varchar2(20));
insert into ming.t190514 select 1,'ming' from dual;
insert into ming.t190514 select 2,'ming' from dual;
commit;
session A :
SQL> select * from ming.t190514;
A B
---------- --------------------
1 ming
2 ming
SQL> select count(*) from test2,t1;
COUNT(*)
----------
18000000
Elapsed: 00:00:14.37
update ming.t190514 set b='shuo';
commit;
現在t190514表的b值都是shuo。此時我想用a=1的值更新a=2的值,更新前後其實是不會改變資料的。這更加類似於試一次無效更新。但是我在where條件中加入了一個比較耗時的條件,也就是下面語句中的笛卡爾積。
14:27:17 SQL> update ming.t190514 set b=(select b from ming.t190514 where a=1) where a=2 and ( select count(*) from test2,t1)>17000000;
1 row updated.
Elapsed: 00:00:14.56
sql中的( select count(*) from test2,t1)>17000000這段要執行10幾秒的時間,如果沒有這個條件的話,那麼下面再session B中的語句會hang住,很顯然是由於行級排它鎖導致的。有了這段就可以執行了,在返回結果前快速到session B :
SQL> set timing on time on
14:27:19 SQL> update ming.t190514 set b='x';
2 rows updated.
Elapsed: 00:00:00.00
14:27:19 SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
回到之前的session A :
14:28:00 SQL> commit;
Commit complete.
Elapsed: 00:00:00.00
此時查詢表的資料,發現是下面的情況了:
14:28:05 SQL> select * from ming.t190514;
A B
---------- --------------------
1 x
2 shuo
Elapsed: 00:00:00.00
session A的update語句執行時間點為T1,它會先執行where條件中17000000那部分的條件,這點從執行計劃中可以看出。在T2時刻,session B快速更新了表的b為X。在T3時刻,執行完where條件後,需要開始一致性讀來讀取b的值,此時問題來了,是讀取T1時刻update語句開始執行的時間點的值呢,還是讀取T3時間點的b的值呢?如果把update看做一個整體的話,那麼確實應該是讀取T1的值,但其實它是讀取了T3時刻的值,也就是說該語句用一致性讀的舊值更新了當前讀的新值。之前的打算是不改變資料的無效更新,結果發現被其他事務干擾了。update實際更新了b的值。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31480688/viewspace-2644676/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle一致性讀(Consistent Read)的原理Oracle
- db block gets 與 consistent read getsBloC
- getc();fgetc();getchar();gets();fgets();
- C語言關於指標,gets()和gets_s()函式的理解C語言指標函式
- [20190416]檢視shared latch gets的變化.txt
- 讀寫一致性的一些思考
- 如何實現資料庫讀一致性資料庫
- oracle邏輯讀過程Oracle
- oracle的只讀事務Oracle
- [20210208][20200426]檢視shared latch gets的變化.txt
- [20181206]關於一致性讀取3.txt
- MySQL e二級索引上的一致性讀MySql索引
- Oracle的資料併發與一致性詳解(上)Oracle
- MySQL探祕(六):InnoDB一致性非鎖定讀MySql
- 如何解讀Oracle的LOAD PROFILEOracle
- Oracle建立只讀使用者Oracle
- 緩衝區溢位漏洞那些事:C -gets函式函式
- 在Oracle中,什麼是物理讀和邏輯讀?Oracle
- [20180907]訪問v$檢視與一致性讀取.txt
- Oracle SCN機制詳細解讀Oracle
- 【ORACLE21C】Oracle21c 只讀目錄說明Oracle
- MySQL半一致性讀原理解析-從原始碼角度解析MySql原始碼
- Oracle與Hadoop對比:強一致性和高效能不可兼得!OracleHadoop
- sqlserver讀取oracle資料庫資料SQLServerOracle資料庫
- 面試必問:讀寫一致性,你需要思考的問題面試
- [20210304]關於11g一致性讀取的測試.txt
- One-on-One Oracle閱讀筆記2(轉)Oracle筆記
- 2.2.3 關於配置Oracle-Home只讀模式Oracle模式
- 管理(006):啟用只讀Oracle Home目錄Oracle
- 解讀MySQL雙主複製的主備資料一致性GPMySql
- 深度剖析 | 關於資料鎖定和讀取一致性問題
- MySQL事務(二)事務隔離的實現原理:一致性讀MySql
- 資料庫大牛李海翔詳解全域性讀一致性技術資料庫
- Oracle優化案例-hang analyze閱讀方法(三十六)Oracle優化
- C/C++輸入函式 scanf() gets() getline() cin.getline() cin.get() getchar()C++函式
- 資料一致性(一) - 介面呼叫一致性
- Oracle 11g 新特性:只讀表(Read-only)Oracle
- 一致性Hash