Oracle中的commit詳解


本文轉自 :

http://blog.csdn.net/hzhsan/article/details/9719307

它執行的時候,你不會有什么感覺。commit在數據庫編程的時候很常用,當你執行DML操作時,數據庫並不會立刻修改表中數據,這時你需要commit,數據庫中的數據就立刻修改了,如果在沒有commit之前,就算你把整個表中數據都刪了,如果rollback的話,數據依然能夠還原。聽我這么說,你或許感覺commit沒什么用,其實不然。當你同時執行兩條或兩條以上的sql語句時,問題就出現了。舉一個例子,你去銀行轉賬,你轉的時候銀行的數據庫會update你銀行賬戶里面的數據,同時對另一個人得賬戶也進行update操作。這兩個程序都必須全部正確執行,才能commit,否則rollback。如果只是完成一條,要么你郁悶,要么銀行郁悶,第一種情況是,你的賬戶的錢沒少,轉賬人得賬戶上的錢多了,銀行郁悶了。第二種情況你的銀行賬戶的錢少了,他的卻沒多,你就好郁悶了。Oracle好好學吧!sql不難,plsql努努力也能熬過去,等到優化那,哎!DBA不是那么好當的。還有就是commit算是顯式提交,還有隱式提交,並不是,不commit的話,你的全部努力就都白費了。

   這個命令是將數據寫到數據庫中。如果不執行COMMIT這個命令,那么在你這個session之外的其他session查詢的數據是你修改數據之前的數據。而COMMIT之后人家查詢的是你修改的數據。你可以打開兩個sqlplus比較做一下測試。一目了然。 
commit的提交針對的是:DML
Data Manipulation Language(DML) 需要提交,這部分是對數據管理操作,比如Insert(插入)、Update(修改)、Delete(刪除),
Data Definition Language(DDL) 不需要提交,這部分是對數據結構定義,比如 Create(創建)、Alter(修改)、Drop(刪除)
 
   oracle的commit就是提交數據(這里是釋放鎖不是鎖表),在未提交前你前面的操作更新的都是內存,沒有更新到物理文件中。執行commit從用戶角度講就是更新到物理文件了,事實上commit時還沒有寫date file,而是記錄了redo log file,要從內存寫到data物理文件,需要觸發檢查點,由DBWR這個后台進程來寫,這里內容有點多的,如果不深究的話你就理解成commit即為從內存更新到物理文件。鎖有很多種,一般我們關注的都是DML操作產生的,比如insert,delete,update,select...for update都會同時觸發表級鎖和行級鎖 

補充:對的,insert以后commit之前是鎖表的狀態,其他事務無法對該表進行操作。
如果不提交的話,那么這個表就被鎖了 
 COMMIT通常是一個非常快的操作,而不論事務大小如何。你可能認為,一個事務越大(換句話說,它影響的數據越多),COMMIT需要的時間就越長。不是這樣的。不論事務有多大,COMMIT的響應時間一般都很“平”(flat,可以理解為無高低變化)。這是因為COMMIT並沒有太多的工作去做,不過它所做的確實至關重要。

  這一點很重要,之所以要了解並掌握這個事實,原因之一是:這樣你就能心無芥蒂地讓事務有足夠的大小。一種錯誤的信念認為分批提交可以節省稀有的系統資源,而實際上這只是增加了資源的使用。如果只在必要時才提交(即邏輯工作單元結束時),不僅能提高性能,還能減少對共享資源的競爭(日志文件、各種內部閂等)。

  分批提交COMMIT的開銷存在兩個因素:

  顯然會增加與數據庫的往返通信。如果每個記錄都提交,生成的往返通信量就會大得多。

  每次提交時,必須等待redo寫至磁盤。這會導致“等待”。在這種情況下,等待稱為“日志文件同步”(log file sync)。

  為什么COMMIT的響應時間相當“平”,而不論事務大小呢?在數據庫中執行COMMIT之前,困難的工作都已經做了。我們已經修改了數據庫中的數據,所以99.9%的工作都已經完成。例如,已經發生了以下操作:

  已經在SGA中生成了undo塊。

  已經在SGA中生成了已修改數據塊。

  已經在SGA中生成了對於前兩項的緩存redo。

  取決於前三項的大小,以及這些工作花費的時間,前面的每個數據(或某些數據)可能已經刷新輸出到磁盤。

  已經得到了所需的全部鎖。

  執行COMMIT時,余下的工作只是:

  為事務生成一個SCN。如果你還不熟悉SCN,起碼要知道,SCN是Oracle使用的一種簡單的計時機制,用於保證事務的順序,並支持失敗恢復。SCN 還用於保證數據庫中的讀一致性和檢查點。可以把SCN看作一個鍾擺,每次有人COMMIT時,SCN都會增1.

  LGWR將所有余下的緩存重做日志條目寫到磁盤,並把SCN記錄到在線重做日志文件中。這一步就是真正的COMMIT。如果出現了這一步,即已經提交。事務條目會從V$TRANSACTION中“刪除”,這說明我們已經提交。

  V$LOCK中記錄這我們的會話持有的鎖,這些所都將被釋放,而排隊等待這些鎖的每一個人都會被喚醒,可以繼續完成他們的工作。

  如果事務修改的某些塊還在緩沖區緩存中,則會以一種快速的模式訪問並“清理”。塊清除(Block cleanout)是指清除存儲在數據庫塊首部的與鎖相關的信息。實質上講,我們在清除塊上的事務信息,這樣下一個訪問這個塊的人就不用再這么做了。我們采用一種無需生成重做日志信息的方式來完成塊清除,這樣可以省去以后的大量工作(在下面的“塊清除”一節中將更全面地討論這個問題)。

  可以看到,處理COMMIT所要做的工作很少。其中耗時最長的操作要算LGWR執行的活動(一般是這樣),因為這些磁盤寫是物理磁盤I/O。不過,這里LGWR花費的時間並不會太多,之所以能大幅減少這個操作的時間,原因是LGWR一直在以連續的方式刷新輸出重做日志緩沖區的內容。在你工作期間,LGWR並非緩存這你做的所有工作;實際上,隨着你的工作的進行,LGWR會在后台增量式地刷新輸出重做日志緩沖區的內容。這樣做是為了避免COMMIT等待很長時間來一次性刷新輸出所有的redo。

  因此,即使我們有一個長時間運行的事務,但在提交之前,它生成的許多緩存重做日志已經刷新輸出到磁盤了(而不是全部等到提交時才刷新輸出)。這也有不好的一面,COMMIT時,我們必須等待,直到尚未寫出的所有緩存redo都已經安全寫到磁盤上才行。也就是說,對LGWR的調用是一個同步(synchronous)調用。盡管LGWR本身可以使用異步I/O並行地寫至日志文件,但是我們的事務會一直等待LGWR完成所有寫操作,並收到數據都已在磁盤上的確認才會返回。

  前面我提高過,由於某種原因,我們用的是一個Java程序而不是PL/SQL,這個原因就是 PL/SQL提供了提交時優化(commit-time optimization)。我說過,LGWR是一個同步調用,我們要等待它完成所有寫操作。在Oracle 10g Release 1及以前版本中,除PL/SQL以外的所有編程語言都是如此。PL/SQL引擎不同,要認識到直到PL/SQL例程完成之前,客戶並不知道這個PL /SQL例程中是否發生了COMMIT,所以PL/SQL引擎完成的是異步提交。它不會等待LGWR完成;相反,PL/SQL引擎會從COMMIT調用立即返回。不過,等到PL/SQL例程完成,我們從數據庫返回客戶時,PL/SQL例程則要等待LGWR完成所有尚未完成的COMMIT。因此,如果在PL /SQL中提交了100次,然后返回客戶,會發現由於存在這種優化,你只會等待LGWR一次,而不是100次。這是不是說可以在PL/SQL中頻繁地提交呢?這是一個很好或者不錯的主意嗎?不是,絕對不是,在PL/SQ;中頻繁地提交與在其他語言中這樣做同樣糟糕。指導原則是,應該在邏輯工作單元完成時才提交,而不要在此之前草率地提交。

  COMMIT是一個“響應時間很平”的操作,雖然不同的操作將生成不同大小的redo,即使大小相差很大或者說無論生成多少redo,但也並不會影響提交(COMMIT)的時間或者說提交所用的時間都基本相同。

 

 

轉自:
http://zhidao.baidu.com/question/345732898.html
http://zhidao.baidu.com/question/446956119.html
http://zhidao.baidu.com/question/126448794.html
http://soft.chinabyte.com/database/75/12306575.shtml


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM