MySQL中一條SQL語句的執行過程

2021-09-01 18:24:57 字數 2922 閱讀 7848

查詢語句的執行順序:

1.客戶端通過tcp連線傳送連線請求到mysql聯結器,聯結器會對該請求進行許可權驗證及連線資源分配(max_connections,8小時超時)

2.建立連線後客戶端傳送一條語句,mysql收到該語句後,通過命令分發器判斷其是否是一條select語句,如果是,在開啟查詢快取的情況下,先在查詢快取中查詢該sql是否完全匹配,如果完全匹配,驗證當前使用者是否具備查詢許可權,如果許可權驗證通過,直接返回結果集給客戶端,該查詢也就完成了。如果不匹配繼續向下執行。(注意:此步並不做詞法及語法分析,也就是用不到分析器,這塊原來我也很疑惑,如果不做分析mysql怎麼知道我要查什麼?解釋如下: 其實說白了大概就是拿著你的sql和原始快取的sql比對)

3.如果在查詢快取中未匹配成功,則將語句交給分析器作語法分析,mysql需要知道到底要查哪些東西,如果語法不對,就會返回語法錯誤中斷查詢。

4.分析器的工作完成後,將語句傳遞給預處理器,檢查資料表和資料列是否存在,解析別名看是否存在歧義等

5.語句解析完成後,mysql就知道要查什麼了,之後會將語句傳遞給優化器進行優化(通過索引選擇最快的查詢方式),並生成執行計畫。

6.之後交給執行器去具體執行該語句,在執行之前,會先檢查該使用者是否具有查詢許可權,如果有,繼續執行該語句。執行器開始執行後,會逐漸將資料儲存到結果集中,同時會逐步將資料快取到查詢快取中,最終將結果集返回給客戶端。(快取到查詢快取受到幾個引數的影響 1.query_cache_type 是否開啟查詢快取,預設為off  2.query_cache_size:查詢快取使用的總記憶體空間,預設值為1m   3.query_cache_limit 對於大於該值的結果集不會被快取,預設值1m,在8.0版本後該引數被移除了)(如果該sql執行過程中超過了慢查詢閥值,該sql會被記錄到慢查詢日誌中) 

一條更新語句的執行順序:

1.客戶端通過tcp連線傳送連線請求到mysql聯結器,聯結器會對該請求進行許可權驗證及連線資源分配(max_connections,8小時超時)

2.建立連線後客戶端傳送一條語句,mysql收到該語句後,通過命令分發器判斷其是否是一條更新語句,如果是,則直接傳送給分析器做語法分析。

3.分析器階段,mysql需要知道到底要查哪些東西,如果語法不對,就會返回語法錯誤中斷查詢

4.分析器的工作完成後,將語句傳遞給預處理器,檢查資料表和資料列是否存在,解析別名看是否存在歧義等

5.語句解析完成後,mysql就知道要查什麼了,之後會將語句傳遞給優化器進行優化(通過索引選擇最快的查詢方式),並生成執行計畫。

6.執行器根據生成的執行計畫去open table,此時會先去檢視該錶上是否有元資料(mdl)排他鎖(如果有元資料共享鎖則無影響),如果有元資料排他鎖,則事物被阻塞,進入等待狀態(時間由lock_wait_timeout決定,預設是一年。。。。),等元資料鎖被釋放,繼續執行。如果無元資料鎖或者是有元資料共享鎖,則該事務在表上加元資料共享鎖(因為元資料共享讀鎖之間是不衝突的,如果表上有元資料共享鎖,我們執行alter table這樣的ddl語句時,會進入等待狀態,因為ddl語句需要在表上加元資料排他鎖)

7.進入引擎層(預設innodb),去innodb_buffer_pool裡面的data dictionary得到表得相關資訊

8.根據表資訊去innodb_buffer_pool裡面的lock info檢視是否有相關的鎖資訊,如果有則等待(因為要加排它鎖),如果沒有則加排它鎖,更新lock info。

9.取讀取相關資料頁到innodb_buffer_pool中(如果資料頁本身就在快取中,則不用從硬碟讀取)

10.將頁中的原始資料(快照)儲存到undo log buffer中(undo log buffer會以相關引數定義的規則進行刷盤操作寫入到undo tablespace中)

11.在innodb_buffer_pool中將相關頁面更新,該頁變成髒頁(髒頁會以相關引數定義的規則進行刷盤操作寫入所屬表空間中)

12.頁面修改完成後,會把修改後的物理頁面儲存到redo log buffer中,(redo log buffer會以相關引數定義的規則進行刷盤操作寫入到redo tablespace中)

13.如果開啟binlog,則更新資料的邏輯語句也會記錄在binlog_cache中(binlog會以相關引數定義的規則進行刷盤操作寫入到binlog file 中)

14.如果該錶上有二級索引並且本次操作會影響到二級索引,則會把相關的二級索引修改寫入到innodb_buffer_pool中的change buffer裡(change buffer 會以相關引數定義的規則進行刷盤操作寫入所屬表空間中)

15.前期的準備工作到此已經做完了,之後便是事務的commit或者rollback操作。一般情況下執行的是commit操作

16.執行commit操作後(mysql預設開啟自動提交,如果手動開始事務begin,則需要顯示提交commit),由於要保證redolog與binlog的一致性,redolog採用2階段提交方式。

17.將undo log buffer及redo log buffer刷盤(innodb_flush_log_at_trx_commit=1),並將該事務的redolog標記為prepare狀態。

18.將binlog_cache資料刷盤(sync_binlog=1)

19.如果開啟了主從結構,此時會將binlog_cache中的資訊通過io執行緒傳送給從機,如果開啟了半同步複製則需要等待從機落盤(relay log)並反饋。如果是非同步複製則無需等待(預設是非同步複製)

20.待binlog落盤完成,再將redolog中該事務資訊標記為commit,釋放相關鎖資源。此時乙個更新事務的操作已經完成,返回給客戶端成功更新提示。

21.標記undolog中該事務修改頁的原始快照資訊為delete,當無其他事務引用該原始資料時(mvcc),再將其刪除

22.如果此時觸發了髒頁刷盤操作,會先將髒頁寫入到double write buffer中(防止寫入過程中出現斷頁,因為mysql頁面預設為16k,linux作業系統最大為4k,如果寫了8k時系統掛了,這個資料頁將不完整,標記為損壞)然後再寫到期所在表空間的相應位置。

mysql中,一條查詢sql的執行過程

作為乙個程式設計師,最不能避免的就是與sql打交道,那麼,在我們平時寫的那麼多sql它們是怎麼執行,並給我們返回資料的?比如最簡單的乙個查詢 select from user where id 10 sql簡單,但問題是你知道它是如何執行的嗎?先從整體看一下mysql資料庫的執行構造 1 serve...

MySql 一條查詢SQL語句的執行

這個的快取不是指redis,或者mybatis的快取我們常見的快取,其實mysql自帶了快取模組,但是我們幾乎從來沒有用過他,甚至在mysql8.0直接就給去掉了,所以一定有他的侷限性,大家可以查閱一下,但是確實是存在的。如果開啟的話,所以乙個查詢sql先會查詢快取 我們沒有使用快取的話,就會跳過快...

一條SQL語句研究

現有 select from t where a in 5,3,2,1,8,9,30.假設 a 是主鍵,in裡面的引數是唯一的。現要求輸出的結果集按照 in 提供的引數順序排序。而不是按照a本身的排序規則排序?另 如果不要求使用臨時表或表變數,那麼又有什麼辦法實現。臨時表方案參卡 create ta...