mysql的語句執行過程 Mysql語句執行過程

2021-10-18 23:44:22 字數 4617 閱讀 9887

昨天老大問了我個問題,說一條sql在低層的時候是怎麼執行的,發生了什麼.

首先使用者通過各種鏈結連線到我們的sql伺服器

但是這些鏈結需要等待伺服器的空閒程序來處理

所以當伺服器接到一條sql後會做很多分解動作

1.首先在快取裡查詢快取中是否有需要的資料表,如果有並且可以用那麼就不執行後面的動作了,直接返回給使用者.

2.若沒有,伺服器肯定就要檢查我們sql語法是否正確,是不是符合我們sql伺服器的規則,不符合就給使用者報錯哦.符合就繼續往下.

3.對sql中要用的表,字段,結構進行檢查,判斷是否與資料庫裡的一樣,若表與字段不符就報錯.

4.若語法語義都對,那麼就對我們的表載入到記憶體,對其表頭也就是欄位名哪一行進行加鎖,防止我們查詢的過程中其他使用者對其結構的改變

5.檢查了語法語義以後,就對當前使用者的許可權檢查,若沒有許可權就不能獲取到資料

6.上面哪些操作都做了以後,就會對sql語句進行優化,確定執行計畫,如果使用了最佳計畫,就會將其儲存在快取記憶體中,下次同樣的語句就不需要做上面的操作

對於select語句:

1)首先伺服器程序要判斷所需資料是否在db buffer存在,如果存在且可用,則直接獲取該資料而不是從資料庫檔案中去查詢資料,同時根據lru 演算法增加其訪問計數;

2)若資料不在緩衝區中,則伺服器程序將從資料庫檔案中查詢相關資料,並把這些資料放入到資料緩衝區中(buffer cache)。

其中,若資料存在於db buffer,其可用性檢查方式為:檢視db buffer塊的頭部是否有事務,如果有事務,則從回滾段中讀取資料;如果沒有事務,則比較select的scn和db buffer塊頭部的scn,如果前者小於後者,仍然要從回滾段中讀取資料;如果前者大於後者,說明這是一非髒快取,可以直接讀取這個db buffer塊的中內容。

對於dml語句(insert、delete、update):

1)檢查所需的資料庫是否已經被讀取到緩衝區快取中。如果已經存在緩衝區快取,則直接執行步驟3;

2)若所需的資料庫並不在緩衝區快取中,則伺服器將資料塊從資料檔案讀取到緩衝區快取中;

3)對想要修改的表取得的資料行鎖定(row exclusive lock),之後對所需要修改的資料行取得獨佔鎖;

4)將資料的redo記錄複製到redo log buffer;

5)產生資料修改的undo資料;

6)修改db buffer;

7)dbwr將修改寫入資料檔案;

其中,第2步,伺服器將資料從資料檔案讀取到db buffer經經歷以下步驟:

1)首先伺服器程序將在表頭部請求tm鎖(保證此事務執行過程其他使用者不能修改表的結構),如果成功加tm鎖,再請求一些行級鎖(tx鎖),如果tm、tx鎖都成功加鎖,那麼才開始從資料檔案讀資料。

2)在讀資料之前,要先為讀取的檔案準備好buffer空間。伺服器程序需要掃瞄lru list尋找free db buffer,掃瞄的過程中,伺服器程序會把發現的所有已經被修改過的db buffer註冊到dirty list中。如果free db buffer及非髒資料塊緩衝區不足時,會觸發dbwr將dirty buffer中指向的緩衝塊寫入資料檔案,並且清洗掉這些緩衝區來騰出空間緩衝新讀入的資料。

3)找到了足夠的空閒buffer,伺服器程序將從資料檔案中讀入這些行所在的每乙個資料塊(db block)(db block是oracle的最小操作單元,即使你想要的資料只是db block中很多行中的一行或幾行,oracle也會把這個db block中的所有行都讀入oracle db buffer中)放入db buffer的空閒的區域或者覆蓋已被擠出lru list的非髒資料塊緩衝區,並且排列在lru列表的頭部,也就是在資料塊放入db buffer之前也是要先申請db buffer中的鎖存器,成功加鎖後,才能讀資料到db buffer。

若資料塊已經存在於db buffer cache(有時也稱db buffer或db cache),即使在db buffer中找到乙個沒有事務,而且scn比自己小的非髒快取資料塊,伺服器程序仍然要到表的頭部對這條記錄申**鎖,加鎖成功才能進行後續動作,如果不成功,則要等待前面的程序解鎖後才能進行動作(這個時候阻塞是tx鎖阻塞)。

在記redo日誌時,其具體步驟如下:

1)資料被讀入到db buffer後,伺服器程序將該語句所影響的並被讀入db buffer中的這些行資料的rowid及要更新的原值和新值及scn等資訊從pga逐條的寫入redo log buffer中。在寫入redo log buffer之前也要事先請求redo log buffer的鎖存器,成功加鎖後才開始寫入。

2)當寫入達到redo log buffer大小的三分之一或寫入量達到1m或超過三秒後或發生檢查點時或者dbwr之前發生,都會觸發lgwr程序把redo log buffer的資料寫入磁碟上的redo file檔案中(這個時候會產生log file sync等待事件)。

3)已經被寫入redo file的redo log buffer所持有的鎖存器會被釋放,並可被後來的寫入資訊覆蓋,redo log buffer是迴圈使用的。redo file也是迴圈使用的,當乙個redo file寫滿後,lgwr程序會自動切換到下一redo file(這個時候可能出現log file switch(check point complete)等待事件)。如果是歸檔模式,歸檔程序還要將前乙個寫滿的redo file檔案的內容寫到歸檔日誌檔案中(這個時候可能出現log file switch(archiving needed)。

在為事務建立undo資訊時,其具體步驟如下:

1)在完成本事務所有相關的redo log buffer之後,伺服器程序開始改寫這個db buffer的塊頭部事務列表並寫入scn(一開始scn是寫在redo log buffer中的,並未寫在db buffer)。

2)然後copy包含這個塊的頭部事務列表及scn資訊的資料副本放入回滾段中,將這時回滾段中的資訊稱為資料塊的「前映像」,這個「前映像」用於以後的回滾、恢復和一致性讀。(回滾段可以儲存在專門的回滾表空間中,這個表空間由乙個或多個物理檔案組成,並專用於回滾表空間,回滾段也可在其它表空間中的資料檔案中開闢)。

在修改資訊寫入資料檔案時,其具體步驟如下:

1)改寫db buffer塊的資料內容,並在塊的頭部寫入回滾段的位址。

2)將db buffer指標放入dirty list。如果乙個行資料多次update而未commit,則在回滾段中將會有多個「前映像」,除了第乙個「前映像」含有scn資訊外,其他每個"前映像"的頭部都有scn資訊和"前前映像"回滾段位址。乙個update只對應乙個scn,然後伺服器程序將在dirty list中建立一條指向此db buffer塊的指標(方便dbwr程序可以找到dirty list的db buffer資料塊並寫入資料檔案中)。接著伺服器程序會從資料檔案中繼續讀入第二個資料塊,重複前一資料塊的動作,資料塊的讀入、記日誌、建立回滾段、修改資料塊、放入dirty list。

3)當dirty queue的長度達到閥值(一般是25%),伺服器程序將通知dbwr把髒資料寫出,就是釋放db buffer上的鎖存器,騰出更多的free db buffer。前面一直都是在說明oracle一次讀乙個資料塊,其實oracle可以一次讀入多個資料塊(db_file_multiblock_read_count來設定一次讀入塊的個數)

當執行commit時,具體步驟如下:

1)commit觸發lgwr程序,但不強制dbwr立即釋放所有相應db buffer塊的鎖。也就是說有可能雖然已經commit了,但在隨後的一段時間內dbwr還在寫這條sql語句所涉及的資料塊。表頭部的行鎖並不在commit之後立即釋放,而是要等dbwr程序完成之後才釋放,這就可能會出現乙個使用者請求另一使用者已經commit的資源不成功的現象。

2)從commit和dbwr程序結束之間的時間很短,如果恰巧在commit之後,dbwr未結束之前斷電,因為commit之後的資料已經屬於資料檔案的內容,但這部分檔案沒有完全寫入到資料檔案中。所以需要前滾。由於commit已經觸發lgwr,這些所有未來得及寫入資料檔案的更改會在例項重啟後,由smon程序根據重做日誌檔案來前滾,完成之前commit未完成的工作(即把更改寫入資料檔案)。

3)如果未commit就斷電了,因為資料已經在db buffer更改了,沒有commit,說明這部分資料不屬於資料檔案。由於dbwr之前觸發lgwr也就是只要資料更改,(肯定要先有log)所有dbwr在資料檔案上的修改都會被先一步記入重做日誌檔案,例項重啟後,smon程序再根據重做日誌檔案來回滾。

其實smon的前滾回滾是根據檢查點來完成的,當乙個全部檢查點發生的時候,首先讓lgwr程序將redologbuffer中的所有緩衝(包含未提交的重做資訊)寫入重做日誌檔案,然後讓dbwr程序將dbbuffer已提交的緩衝寫入資料檔案(不強制寫未提交的)。然後更新控制檔案和資料檔案頭部的scn,表明當前資料庫是一致的,在相鄰的兩個檢查點之間有很多事務,有提交和未提交的。

當執行rollback時,具體步驟如下:

伺服器程序會根據資料檔案塊和db buffer中塊的頭部的事務列表和scn以及回滾段位址找到回滾段中相應的修改前的副本,並且用這些原值來還原當前資料檔案中已修改但未提交的改變。如果有多個」前映像「,伺服器程序會在乙個「前映像」的頭部找到「前前映像」的回滾段位址,一直找到同一事務下的最早的乙個「前映像」為止。一旦發出了commit,使用者就不能rollback,這使得commit後dbwr程序還沒有全部完成的後續動作得到了保障。

當語句執行完成之後,查詢到的資料還是在伺服器程序中,還沒有被傳送到客戶端的使用者程序。所以,在伺服器端的程序中,有乙個專門負責資料提取的一段**。他的作用就是把查詢到的資料結果返回給使用者端程序,從而完成整個查詢動作。

本文也是學習別人的東西詳情請看

MySQL語句執行過程

查詢語句 許可權校驗 快取查詢 分析器 優化器 執行器 許可權校驗 執行器 引擎。更新語句 分析器 許可權校驗 執行器 引擎 redolog prepare binlog redolog commit。mysql主要分為2部分 server層和儲存引擎層。查詢快取 執行查詢語句的時候,會先查詢快取 ...

MySQL語句執行過程

目錄平常我們看到的只是一條語句執行出來的結果,並不知道中間發生了什麼,今天就來 一下,mysql語句的執行過程。每次使用mysql會先連線到資料庫上面,聯結器負責跟客戶端進行連線 mysql u root p然後根據密碼,判斷我登陸進去會有什麼許可權,並分配許可權給我 通過show processl...

mysql 語句執行的過程

實際上mysql執行的每一步都比較複雜,具體的過程如下 1 mysql客戶端和伺服器通訊 mysql客戶端和伺服器之間的通訊協議是 半雙工 的,這意味著,在任何乙個時刻,要麼由伺服器向客戶端傳送資料,要麼由客戶端向伺服器傳送資料,這兩個動作不能同時發生。這種協議讓mysql通訊簡單快速,但也限制了m...