oracle-2中commit 詳解

博文轉自:http://blog.csdn.net/hzhsan/article/details/9719307html

它執行的時候,你不會有什麼感受。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並無太多的工做去作,不過它所作的確實相當重要。

  這一點很重要,之因此要了解並掌握這個事實,緣由之一是:這樣你就能心無芥蒂地讓事務有足夠的大小。一種錯誤的信念認爲分批提交能夠節省稀有的系統資源,而實際上這只是增長了資源的使用。若是隻在必要時才提交(即邏輯工做單元結束時),不只能提升性能,還能減小對共享資源的競爭(日誌文件、各類內部閂等)。sql

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

  顯然會增長與數據庫的往返通訊。若是每一個記錄都提交,生成的往返通訊量就會大得多。編程

  每次提交時,必須等待redo寫至磁盤。這會致使「等待」。在這種狀況下,等待稱爲「日誌文件同步」(log file sync)。緩存

  爲何COMMIT的響應時間至關「平」,而不論事務大小呢?在數據庫中執行COMMIT以前,困難的工做都已經作了。咱們已經修改了數據庫中的數據,因此99.9%的工做都已經完成。例如,已經發生了如下操做:安全

  已經在SGA中生成了undo塊。session

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

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

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

  已經獲得了所需的所有鎖。

  執行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
相關文章
相關標籤/搜索