MySQL中的sql語句執行過程

MySQL的基本結構

大致結構

Server層

有以下組件

連接器

在客戶端登錄Mysql時進行身份認證和權限確認

緩存

在進行select語句時,會優先查詢的區域,同時在發現查詢不到時會從表中查詢並緩存到這個組件。顧名思義。

分析器

準確的說是語義分析器,即分析sql語句是否正確

優化器

優化sql語句到底層最優的方式從而執行sql語句,比如如何選擇索引,如何聯表,但只是理論最優,不一定是實際最優。

執行器

執行語句並從存儲引擎層獲取數據返回,與引擎交互的層。

binlog

熟悉的都知道,日誌模塊,記錄日誌

Server層主要實現了存儲過程、觸發器、視圖、函數等功能。

存儲引擎層

簡單說就是負責數據的讀和寫,可以替換,有很多類型的存儲引擎,默認情況下爲InnoDB,比較常用的還有MyISAM、Memory等多個存儲引擎。

MyISAM

不支持事務和行級鎖,因此不支持併發事務,而且無法保證可用性,容錯性很差。但是也有可取之處,比如全文索引、壓縮、空間函數等,性能很好。

InnoDB

支持行級鎖,支持事務,外鍵等功能,具有安全回滾的能力。
同時也支持MVCC:可以使用樂觀鎖和悲觀鎖來實現。只在讀取已提交和可重複讀兩個隔離級別下工作。(數據庫事務四個隔離級別,讀取未提交,讀取已提交,可重複讀,可串行化)
效率上則未必比MyISAM弱,要看具體的實際場景。

兩者在索引方面的區別

兩者都使用的B+樹(可自行查詢),MyISAM引擎的葉節點data域存放數據的地址。被稱爲非聚簇索引。InnoDB數據文件本身是索引文件,索引文件和數據文件分離,樹的葉節點data域保存了完整的數據記錄,數據文件本身是主索引,而數據表主鍵則是索引的鍵值,被稱爲聚簇索引。

實例分析

大的來分,sql語句不外乎兩種,查詢與修改,因爲增刪改都可以算是修改。

查詢語句

舉個簡單例子如下

select * from student Tate where Tate.sex='M' and Tate.num=1;

執行流程如下:

  1. 檢查權限。若無則報錯,若正確則下一步
  2. 查詢緩存(8.0及更高不再查詢)。如果有則直接返回,若無,繼續下一步。
  3. 進入分析器分析詞法,提取出語句中的操作,先找到select確認爲查詢操作,後找到from後的表名student進行查詢,然後判斷是否存在語法問題,若有則報錯,無則繼續下一步。
  4. 這就到了優化器的層面,確認理論最優的查詢方案,比如這條語句,我們有兩種做法,把性別=M的全部找出來再找num=1的或是把num=1的先找出來再找性別M的(再者也有聯表順序之類的語句也會有不同的執行過程)通過內部的相關算法選擇理論上認爲最優的過程進行執行操作,然後進入下一步
  5. 接下去再次進行權限檢查去調用底層的存儲引擎提供的相關接口,然後返回結果。

修改語句

同樣舉個例子

update student Tate set Tate.money=10000 where Tate.num=1;

和查詢不一樣,這裏面主要涉及數據的修改,爲了數據庫的安全回覆,這裏就要用到上面提到的binlog組件,也就是日誌組件,當然引擎也存在相應的日誌組件。
具體過程如下:

  1. 查詢num=1的所有數據(與查詢語句類似)
  2. 根據查詢語句修改money字段,調用引擎接口保存數據,在引擎的日誌模塊中記錄,並返回執行器信號,記錄此時處於“準備”階段(還未commit)
  3. 執行器收到信號後將操作記錄到binlog日誌組件中,然後再次調用引擎接口,設置引擎的日誌模塊中這條日誌爲commit狀態。

異常處理

因爲兩個日誌的存在會引發很多問題。

爲什麼存在兩個日誌

首先先弄清楚這個問題,其實是可以不存在兩個日誌的,這應該算是個版本更新的問題,5.5之前版本Mysql採用的是MyISAM引擎,而上面提到了,這個是不存在日誌模塊的,而InnoDB是存在的,名字叫redo log。

極端情況

redo log正在準備階段,但是binlog寫完還未調用引擎接口的時候宕機了,造成數據的不一致。

解決方法

重啓之後Mysql會對redolog進行檢查,如果發現是commit狀態,就提交事務。
如果發現是準備階段,那就再去判斷binlog是否已經存在完整的記錄,如果是則修改redolog爲commit,如果不是則進行回滾,重新執行事務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章