Oracle SQL語句執行完整過程:

SQL語句執行完整過程:算法

1. 用戶進程提交一個sql 語句: update temp set a=a*2,給服務器進程。sql

2.服務器進程從用戶進程把信息接收到後, 在PGA 中就要此進程分配所需內存,存儲相關的信息,如在會話內存存儲相關的登陸信息等。數據庫

3.服務 器進程把這個sql  語句的字符轉化爲ASCII 等效數字碼, 接着這個ASCII   碼被傳遞給一個HASH 函數, 並返回一個hash 值,而後服務器進程將到shared pool  中的library cache 中去查找是否存在相 同的hash 值,若是存在, 服務器進程將使用這條語句已高速緩存在SHARED POOL 的library cache 中的已分析過的版原本執行。緩存

4.若是不存在, 服務器進程將在CGA 中, 配合UGA  內容對sql,進行語法分析,首先檢查語法的正確性,接着對語句中涉及的表,索引,視圖等對象進行解析,並對照數據字典檢查這些對象的名稱以及相關結構,並根據ORACLE 選用的優化模式以及數據字典中是否存在相應對象的統計數據和是否使用了存儲大綱來生成一個執行計劃或從存儲大綱中選用一個執行計劃,而後再用數據字典覈對此用戶對相應對象的執行權限,最後生成一個編譯代碼。服務器

5.ORACLE  將這條sql 語句的自己實際文本、HASH 值、編譯代碼、與此語名相關聯的任何統計數據 和該語句的執行計劃緩存在SHARED POOL  的library cache 中。服務器進程經過SHARED POOL 鎖存器(shared pool latch) 來申請能夠向哪些共享PL/SQL 區中緩存這此內容,也就是說被SHARED POOL 鎖存 器鎖定的PL/SQL 區中的塊不可被覆蓋,由於這些塊可能被其它進程所使用。網絡

6.在SQL分析階段將用到LIBRARY  CACHE,從數據字典中核對錶、視圖等結構的時候,須要將數據 字典從磁盤讀入LIBRARY  CACHE,所以,在讀入以前也要使用LIBRARY  CACHE 鎖存器(library cache pin,library cache lock) 來申請用於緩存數據字典。到如今爲止, 這個sql 語句已經被編譯成可執行的代碼了,但還不知道要操做哪些數據, 因此服務器進程還要爲這個sql 準備預處理數據。oracle

7.首先服務器進程要判斷所需數據是否在db buffer 存在,若是存在且可用,則直接獲取該數據, 同時根據LRU 算法增長其訪問計數; 若是buffer 不存在所需數據,則要從數據文件上讀取首先服務器進程將在表頭部 請求TM 鎖(保證此事務執行過程其餘用戶不能修改表的結構), 若是成功加TM 鎖,再請求一些行級鎖(TX 鎖), 若是TM、TX 鎖都成功加鎖,那麼纔開始從數據文件讀數據,在讀數據以前, 要先爲讀取的文件準備好buffer 空 間。服務器進程須要掃面LRU list  尋找free db buffer,掃描的過程當中,服務器進程會把發現的全部 已經被修改過的db buffer  註冊到dirty list 中,  這些dirty buffer  會經過dbwr 的觸發條件,隨後會被寫出到數據文件,找到了足 夠的空閒buffer,就能夠把請求的數據行所在 的數據塊放入到db buffer 的空閒區域或者 覆蓋已經被擠出LRU list 的非髒數據塊緩衝區,並排列 在LRU list 的頭部, 也就是在數據塊放入DB BUFFER  以前也是要先申請db buffer 中的鎖存器,成功加鎖後, 才能讀數據到db buffer。函數

8.記日誌如今數據已經被讀入到db buffer 了,如今服務器進程將該語句所影響的並被讀  入db buffer  中的這些行數據的rowid 及要更新 的原值和新值及scn  等信息從PGA  逐條的寫入redo log buffer  中。在寫入redo log buffer 之 前也要事先請求redo log buffer 的鎖存器,成功加鎖後纔開始寫入,當 寫入達到redo log buffer  大小的三分之一或寫入量達到1M 或超過 三秒後或發生檢查點時或者dbwr 以前發生, 都會觸發lgwr  進程把redo log buffer  的數據寫入磁盤上的redo file 文件中(這個時候會產生log file sync 等待事件)  已經被寫入redofile  的redo log buffer 所持有的鎖存器會被釋放,並可被後來的寫入信息覆蓋, redo log buffer是循環使用的。Redo file 也是循環使用的, 當一個redo file 寫滿後,lgwr 進程會自動切換到 下一redo file( 這個時候可能出現log fileswitch(checkpoint complete)等待事件)。若是是歸檔模式,歸檔進  程還要將前一個寫滿的redo file 文件的內容寫到歸檔日誌文件中( 這個時候可能出現log fileswitch(archiving needed)。優化

9.  爲事務創建回滾段在完成本事務全部相關的redo log buffer 以後,服務器進程開始改寫 這個db buffer 的塊頭部事務列表並寫入scn, 而後copy  包含這個塊的頭部事務列表及scn 信息的數據副本放入回滾段中,將這時回滾段「「中的信息稱爲數據塊的前映像,」這個前映「像用於之後的回滾、恢復和一致性讀。(回滾段能夠存儲在專門的回滾表空間中,這個表空間由一個或多個物理文件組成,並專用於回滾表空間,回滾段也可在其它表空間中的數據文件中開闢。操作系統

10. 本事務修改數據塊準備工做都已經作好了, 如今能夠改寫db buffer 塊的數據內容了,並在塊的頭部寫入回滾段的地址。

11. 放入dirty list  若是一個行數據屢次update  而未commit,「則在回滾段中將會有多個前「映像,除了第」「 一個前映像含有scn 信息外,「「 其餘每一個前映像的頭部都有scn 「」 信息和前前映像回滾段地址。一個update 只對應一 個scn, 而後服務器進程將在dirty list 中創建一  條指向此db buffer 塊的指針( 方便dbwr  進程能夠找到dirty list  的db buffer 數據塊並寫入數據文件中) 。接着服務器進程會從數據文件中繼續讀入第二個數據塊,重複前一數據塊的動做,數據塊的讀入、記日誌、創建回滾段、 修改數據塊、放入dirty list 。當dirty queue 的長度達到閥值( 通常是25%), 服務器進程將通知dbwr 把髒數據寫出, 就是釋放db buffer 上的鎖存器, 騰出更多的free db buffer 。前面一直都是在說明oracle 一次讀一個數據塊, 其實oracle 能夠一次讀入多個數據塊(db_file_multiblock_read_count 來設置一次讀入塊的個數)  說明:  在預處理的數據已經緩存在db buffer 或剛剛被從數據文件 讀入到db buffer 中, 就要根據sql 語句的類型來決定接下來如何操做。  1> 若是是select 語句, 則要查看db buffer 塊的頭部是否有事務,若是有事務,則從回滾段中讀取數據;若是沒有事務, 則比較select  的scn  和db buffer  塊頭部的scn,若是前者小於後者,仍然要從回滾段中讀取數據;若是前者大於後者,說明這是一非髒緩存, 能夠直接讀取這個db buffer 塊的中內容。 2> 若是是DML 操做, 則即便在db buffer 中找到一個沒有事務, 並且SCN 比本身小的非髒 緩存數據塊,服務器進程仍然要到表的頭部對這條記錄申請加鎖,加鎖成功才能進行後續動做,若是不成功,則要等待前面的進程解鎖後才能進行動做( 這個時候阻塞是tx 鎖阻塞)。  用戶commit  或rollback 到如今爲止, 數據已經在db buffer 或數據文件中修改完 成,可是否要永久寫到數文件中,要由用 戶來決定commit(保存更改到數據文件) rollback 撤銷數據的更改)。 1. 用戶執行commit 命令  只有當sql  語句所影響的全部行所在的最後一個塊被讀入db buffer  而且重作信息被寫入redo log buffer(僅指日誌緩衝區,而不包括日誌文件)以後, 用戶才能夠發去commit 命令,commit  觸發lgwr 進程,但不 強制當即dbwr 來釋放全部相應db buffer 塊的鎖(也就是no-force-at-commit,即提交不強制寫),也就是說有 可能雖然已經commit 了,但在隨後的一 段時間內dbwr  還在寫這條sql 語句所涉及的數據塊。表頭部的行鎖 並不在commit 以後當即釋放, 而是要等dbwr 進程完成以後才釋放,這就可能會出現一個用戶請求另外一用戶 已經commit 的資源不成功的現象。 A . 從Commit  和dbwr 進程結束之間的時間很短,若是 恰巧在commit 以後,dbwr 未結束以前斷電,由於commit 以後的數據已經屬於數據文件的內容,但這部分文件沒有徹底寫入到數據文件中。因此須要前滾。由 於commit 已經觸 發lgwr,這些全部將來得及寫入數據文件的更改會在實例重啓後, 由smon 進程根據重作日誌文件來前滾, 完成以前commit 未完成的工做(即把更改寫入數據文件)。 B. 若是未commit 就斷電了, 由於數據已經在db buffer 更改了, 沒有commit,說明這部分數據不屬於數據文件, 因爲dbwr  以前觸發lgwr 也就是隻要數據更改,( 確定要先有log)  全部DBWR,在數據文件上的修改都會被先一步記入重作日誌文件,實例重啓後,SMON 進程再根據重作日誌文件來回滾。  其實smon 的前滾回滾是根據檢查點來完成的,當一個所有檢查點發生的時候, 首先讓LGWR  進程將redo log buffer 中的全部緩衝(包含未提交的重作信息)寫入重作日誌文件, 而後讓dbwr  進程將db buffer 已提交的緩衝寫入數據文件(不強制寫未提交的)。而後更新控制文件和 數據文件頭部的SCN,代表當前數據庫是一致的,在相鄰的兩個檢查點之間有不少事務,有提交和未提交的。 像前面的前滾回滾比較完整的說法是以下的說明:   A.發生檢查點以前斷電,而且當時有一個未提交的改變正在進行,實例重啓以後,SMON 進程將從上一個檢查點開始覈對這個檢查點以後記錄在重作日誌文件中已提交的和未提交改變,由於 dbwr  以前會觸發lgwr, 因此dbwr 對數據文件的修改必定會被先記錄在重作日誌文件中。所以, 斷電前被DBWN 寫進數據文件的改變將經過重作日誌文件中的記錄進行還原,叫作回滾, B. 若是斷電時有一個已提交, 但dbwr 動做尚未徹底完成的改變存在,由於已經提交, 提交會觸發lgwr 進程,因此不 管dbwr 動做是否已完成,該語句將要影響的行及其產生的結果必定已經記錄在重作日誌文件中了,則實例重啓後,SMON 進程根據重作日誌文件進行前滾. 實例失敗後用於恢復的時間由兩個檢查點之間的間隔大小來決定,能夠通個四個參數設置檢查點執行的頻率:  Log_checkpoint_interval: 決定兩個檢查點之間寫入重作日誌文件的系統物理塊(redo blocks)的大小, 默認值是0,無限制。 log_checkpoint_timeout:                 兩個檢查點之間的時間長度(秒)默認值1800s。fast_start_io_target: 決定了用於恢復時須要處理的塊的多少, 默認值是0,  無限制。fast_start_mttr_target: 直接決定了用於恢復的時間的長短, 默認值是0,無限制(SMON 進程執行的前滾和回滾與用戶的回滾是不一樣的,SMON 是根據重作日誌文件進行前滾或回滾,而用戶的回滾必定是根據回滾段 的內容進行回滾的。 在這裏要說一下回滾段存儲的數據, 假如是delete 操做,則回滾段將會記錄整個行的數據, 假如是update,則回滾段只記錄被修改了的字段的變化前的數據(前映像),也就是沒有被修改的字段是不會被記錄的, 假如是insert,則回滾段只 記錄插入記錄的rowid 。這樣假如事務提交,那回滾段中簡單標記該事務已經提交;假如是回退, 則若是操做是delete,回退的時候把回滾段中數據從新寫回數據塊, 操做若是是update,則把變化前數據修改回去,操做若是 是insert, 則根據記錄的rowid 把該記錄刪除。 2. 若是用戶rollback。  則服務器進程會根據數據文件塊和DB BUFFER 中塊的頭部的事務列表 和SCN 以及回滾段地址找到回滾段中相應的修改前的副本,而且用這些原值來還原當前數據文件中已修改但未提交的改變。若是有多個「」前映像,「服務器進程會在一個前映」「」像的頭部找到前前映像的回滾段地址,一直找到同一事務下的最先的「」一個前映像 爲止。一旦發出了COMMIT,用戶就不能rollback, 這使得COMMIT  後DBWR 進程尚未所有完成的後續動做獲得了保障。到如今爲例一個事務已經結束了。 說明:  TM 鎖:  符合lock 機制的, 用於保護對象的定義不被修改。TX 鎖: 這個鎖表明一個事務,是行級鎖,用數據塊頭、數據記錄頭的一些字段表示, 也是符合lock 機制, 有resource structure、lock structure、enqueue 算法。

 

 

僅僅是一個SQL語句就包含了這麼複雜的處理過程,若是算上硬件交互(鍵盤鼠標操做),操做系統處理,網絡傳輸等等,僅僅點擊一個查詢按鈕後臺就介入了無比複雜的各方面的處理過程

相關文章
相關標籤/搜索