ORACLE 多版本读一致性
生活随笔
收集整理的這篇文章主要介紹了
ORACLE 多版本读一致性
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
?先來看看這段代碼:
? while s in (select * from table1) loop
??? insert into table1 values(s.field1,s.field2,s.field3,s.field4,s.field5);
? end loop;
? 如果是SQL server的開發(fā)人員,看到這段代碼,肯定會搖頭:這段代碼有問題,這樣遞歸插入,會一直到表爆掉為止;而ORACLE開發(fā)人員,則不會有覺得這段代碼有什么不對。
? 這是為什么呢?原因就是兩個數(shù)據(jù)庫系統(tǒng)的處理機制不一樣,假設表table1的內(nèi)容如下:
? field1? field2? field3? field4? field5
? 1?????? 2?????? 3?????? 4?????? 5
? 那么SQL server會這樣處理:找到table1的第一條記錄,把這條記錄插入到table1中,這時select * from table1這個查詢的內(nèi)容就變成了
? field1? field2? field3? field4? field5
? 1?????? 2?????? 3?????? 4?????? 5
? 1?????? 2?????? 3?????? 4?????? 5
? 于是循環(huán)就移動指針,把第二條記錄復制下來插入到table1中,于是select * from table1這個查詢又增加了一條記錄,于是繼續(xù)復制...,就這樣一直繼續(xù)下去,直至表被撐滿。
? 而在ORACLE中,系統(tǒng)指向第一條記錄時,會判斷這條記錄的版本,由于這個版本在查詢select * from table1被提交前就存在,所以它會被復制插入,然后指針移向下一記錄,也就是剛剛加入的這條,判斷它的版本,發(fā)現(xiàn)它是在查詢提交后生成的,這時ORACLE就會去找這條記錄在查詢被提交時的版本,得到的結(jié)果是當時沒有這條記錄,ORACLE就不認為它是查詢結(jié)果中的記錄,于是跳過,再去找下一條記錄。
? 從上面的處理過程可以看出,SQL server遇到這段代碼,會不停循環(huán)下去--如果表的記錄數(shù)不是限制的話,而ORACLE會把表的記錄復制一次插入就推出。
? ORACLE對所有的數(shù)據(jù)都記錄了它任何時間的狀態(tài),這樣做當然會使數(shù)據(jù)占用更大的空間,但也使得查詢得出的數(shù)據(jù)全部都是同一刻狀態(tài)的數(shù)據(jù)。
? 舉個例子,如果對于一個銀行的數(shù)據(jù)庫系統(tǒng),保存有儲戶的帳號和儲蓄金額,假設在經(jīng)理查詢本行所有帳戶的總儲蓄額(假設數(shù)據(jù)量較大,需要花費的查詢時間較長)時,有用戶做了轉(zhuǎn)帳處理,就可能出現(xiàn)以下情況:
? 用戶??? 金額
? A?????? 1400
? B?????? 2200
? C?????? 600
? 經(jīng)理在使用sum統(tǒng)計總金額且沒有使用鎖定,如果已經(jīng)統(tǒng)計完A和B的金額相加之后,統(tǒng)計到C之前,用戶A將自己帳戶上的金額轉(zhuǎn)了1000到C的帳戶上,那么對于某些數(shù)據(jù)庫系統(tǒng)就可能會出現(xiàn)總金額比實際要多出1000的情況,因為它們在統(tǒng)計到用戶C的儲蓄金額時,會將用戶A轉(zhuǎn)帳后C的金額當作有效值參與到查詢中,這種結(jié)果顯然是不正確的。
? 而ORACLE在處理到用戶C的記錄時會去找查詢提交時間所對應的版本的記錄,也就是A轉(zhuǎn)帳到C之前的記錄,顯然這才是經(jīng)理要得到的結(jié)果。
? 由此看來,ORACLE的多版本,使得在不需要鎖定的情況下,查詢到的數(shù)據(jù)是同一時間的數(shù)據(jù)。
? 這是不是意味著針對ORACLE數(shù)據(jù)庫開發(fā)的查詢就完全不需要鎖來阻塞其他用戶了呢?不是的
? 以餐館的訂桌系統(tǒng)為例,假設用戶通過查詢來查看各個時間桌子是否被訂了,然后再從沒有被訂的桌子中預定訂某個時間某個桌子的使用權(quán)。
? 如果這個系統(tǒng)是多用戶的,那么就可能出現(xiàn)這種情況:甲乙兩個用戶同時查看當天下午五點的訂桌情況,然后同時訂下了1號桌。在沒有對其它用戶進行排它阻塞的情況下,兩個用戶同時看到1號桌沒有被訂,于是都下了訂單,于是一張桌子同時被兩人訂了,這顯然出了問題。
? 正確解決這個問題,顯然還是要使用用戶阻塞的,也就是在查詢時使用for update,這樣在甲用戶查詢時,乙用戶的查詢就會被掛起,直到甲用戶釋放鎖定之后才會執(zhí)行,就不會出現(xiàn)上面這種情況了。
? ORACLE的多版本解決了數(shù)據(jù)的一致性問題,可以在不加鎖的情況下獲得同一時間的數(shù)據(jù),然而這不意味著不需要在讀取表的時候加鎖了,類似上面的這種問題,往往很容易被忽略,而且這種bug很不容易找出來,何時用鎖,何時不用,應當仔細。
? while s in (select * from table1) loop
??? insert into table1 values(s.field1,s.field2,s.field3,s.field4,s.field5);
? end loop;
? 如果是SQL server的開發(fā)人員,看到這段代碼,肯定會搖頭:這段代碼有問題,這樣遞歸插入,會一直到表爆掉為止;而ORACLE開發(fā)人員,則不會有覺得這段代碼有什么不對。
? 這是為什么呢?原因就是兩個數(shù)據(jù)庫系統(tǒng)的處理機制不一樣,假設表table1的內(nèi)容如下:
? field1? field2? field3? field4? field5
? 1?????? 2?????? 3?????? 4?????? 5
? 那么SQL server會這樣處理:找到table1的第一條記錄,把這條記錄插入到table1中,這時select * from table1這個查詢的內(nèi)容就變成了
? field1? field2? field3? field4? field5
? 1?????? 2?????? 3?????? 4?????? 5
? 1?????? 2?????? 3?????? 4?????? 5
? 于是循環(huán)就移動指針,把第二條記錄復制下來插入到table1中,于是select * from table1這個查詢又增加了一條記錄,于是繼續(xù)復制...,就這樣一直繼續(xù)下去,直至表被撐滿。
? 而在ORACLE中,系統(tǒng)指向第一條記錄時,會判斷這條記錄的版本,由于這個版本在查詢select * from table1被提交前就存在,所以它會被復制插入,然后指針移向下一記錄,也就是剛剛加入的這條,判斷它的版本,發(fā)現(xiàn)它是在查詢提交后生成的,這時ORACLE就會去找這條記錄在查詢被提交時的版本,得到的結(jié)果是當時沒有這條記錄,ORACLE就不認為它是查詢結(jié)果中的記錄,于是跳過,再去找下一條記錄。
? 從上面的處理過程可以看出,SQL server遇到這段代碼,會不停循環(huán)下去--如果表的記錄數(shù)不是限制的話,而ORACLE會把表的記錄復制一次插入就推出。
? ORACLE對所有的數(shù)據(jù)都記錄了它任何時間的狀態(tài),這樣做當然會使數(shù)據(jù)占用更大的空間,但也使得查詢得出的數(shù)據(jù)全部都是同一刻狀態(tài)的數(shù)據(jù)。
? 舉個例子,如果對于一個銀行的數(shù)據(jù)庫系統(tǒng),保存有儲戶的帳號和儲蓄金額,假設在經(jīng)理查詢本行所有帳戶的總儲蓄額(假設數(shù)據(jù)量較大,需要花費的查詢時間較長)時,有用戶做了轉(zhuǎn)帳處理,就可能出現(xiàn)以下情況:
? 用戶??? 金額
? A?????? 1400
? B?????? 2200
? C?????? 600
? 經(jīng)理在使用sum統(tǒng)計總金額且沒有使用鎖定,如果已經(jīng)統(tǒng)計完A和B的金額相加之后,統(tǒng)計到C之前,用戶A將自己帳戶上的金額轉(zhuǎn)了1000到C的帳戶上,那么對于某些數(shù)據(jù)庫系統(tǒng)就可能會出現(xiàn)總金額比實際要多出1000的情況,因為它們在統(tǒng)計到用戶C的儲蓄金額時,會將用戶A轉(zhuǎn)帳后C的金額當作有效值參與到查詢中,這種結(jié)果顯然是不正確的。
? 而ORACLE在處理到用戶C的記錄時會去找查詢提交時間所對應的版本的記錄,也就是A轉(zhuǎn)帳到C之前的記錄,顯然這才是經(jīng)理要得到的結(jié)果。
? 由此看來,ORACLE的多版本,使得在不需要鎖定的情況下,查詢到的數(shù)據(jù)是同一時間的數(shù)據(jù)。
? 這是不是意味著針對ORACLE數(shù)據(jù)庫開發(fā)的查詢就完全不需要鎖來阻塞其他用戶了呢?不是的
? 以餐館的訂桌系統(tǒng)為例,假設用戶通過查詢來查看各個時間桌子是否被訂了,然后再從沒有被訂的桌子中預定訂某個時間某個桌子的使用權(quán)。
? 如果這個系統(tǒng)是多用戶的,那么就可能出現(xiàn)這種情況:甲乙兩個用戶同時查看當天下午五點的訂桌情況,然后同時訂下了1號桌。在沒有對其它用戶進行排它阻塞的情況下,兩個用戶同時看到1號桌沒有被訂,于是都下了訂單,于是一張桌子同時被兩人訂了,這顯然出了問題。
? 正確解決這個問題,顯然還是要使用用戶阻塞的,也就是在查詢時使用for update,這樣在甲用戶查詢時,乙用戶的查詢就會被掛起,直到甲用戶釋放鎖定之后才會執(zhí)行,就不會出現(xiàn)上面這種情況了。
? ORACLE的多版本解決了數(shù)據(jù)的一致性問題,可以在不加鎖的情況下獲得同一時間的數(shù)據(jù),然而這不意味著不需要在讀取表的時候加鎖了,類似上面的這種問題,往往很容易被忽略,而且這種bug很不容易找出來,何時用鎖,何時不用,應當仔細。
總結(jié)
以上是生活随笔為你收集整理的ORACLE 多版本读一致性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Semaphore及其用法
- 下一篇: 执行-技术人的管理之路--总结