開發人員基本都知道,我們的資料存在資料庫中(目前最多的是mysql和oracle,由於作者更擅長mysql,所以這裡預設資料庫為mysql),伺服器通過sql語句將查詢資料的請求傳入到mysql資料庫。資料庫拿到sql語句以後。都是進行了哪些操作呢?這裡向大家介紹下我的個人的理解,歡迎大家評論區批評指正。
流程概述
mysql得到sql語句後,大概流程如下:
1.sql的解析器:負責解析和轉寄sql
2.前置處理器:對解析後的sql樹進行驗證
3.查詢最佳化工具:得到一個執行計畫
4.查詢執行引擎:得到資料結果集
5.將資料放回給調用端。
流程圖如下所示:
分發器及緩衝階段
首先,如果系統的緩衝功能開啟著的話,sql語句進入mysql後,sql進行判斷,是否為select關鍵字。如果是,那麼先去查詢快取中進行查詢,如果在查詢快取中可以命中sql語句,那麼直接返回查詢快取中的查詢語句對應的value值(在緩衝中,把查詢語句做一個hash運算,結果作為key值,查詢的結果集為value)。
如果命中緩衝的話,查詢速度是相當快的。但是查詢快取也有它相應的缺點。
首先,開啟緩衝的話,伺服器會消耗大量的記憶體空間;其次,緩衝有的時候並不適用;最後,有的情況下,開啟緩衝也不會將對應的sql語句寫入緩衝。
緩衝不適用的情況:
緩衝的鎖的力度比較大,而且對於動態sql的支援度不夠。
緩衝在資料進行更新的時候,是進行的表級鎖,更新結束後,會把所有與更新內容相關的緩衝全部刪除。所以,如果表的寫入比較多的話,緩衝是比較浪費效能的。如果寫入特別多,可能緩衝反而會導致mysql變慢。
查詢不到緩衝的情況:
1.查詢條件有不確定資料:如now ,current_time等。
2.緩衝對大小寫敏感,如select * from test 和SELECT* FROM test 就不會解析為同一條sql
查詢帶來的額外開銷:
1.開始前需要先檢查緩衝是否命中。
2.結果輸出的時候,需要額外進行資料的快取作業。
3.寫入資料時,mysql會將對應表的所有緩衝都設定為失效。當緩衝記憶體較大的時候,會導致系統消耗較大。
sql的解析器與預先處理
sql解析器是在命令分發之後,將對應的sql語句,解析為sql解析樹。sql解析樹是Mysql本身內部的文法規則和解析查詢。驗證是否使用錯誤的關鍵字,sql文法順序是否正確等。(文法層面的錯誤)
解析完成後,進行查詢語句前置處理器,根據mysql的規則,檢查解析樹是否合法。(表格是否存在,別名是否有歧義等)
查詢最佳化工具
查詢最佳化工具擷取到執行計畫然後由查詢執行引擎執行相應的操作。查詢最佳化工具,是資料庫l的一個核心模組,分為cbo和rbo兩種。
其中,rbo是基於規則的最佳化器。(rbo在oracle早期版本中使用,現在也保留,不過預設為cbo。mysql沒有rbo最佳化器)
這些規則是寫入程式碼在資料庫的代碼中的。rbo會根據輸入的sql語句可以匹配到的優先順序最高的規則去作為執行計畫。例如:在rbo中有這麼一條規則:有索引的情況下,使用索引。那麼所有的帶有索引的表在執行的時候,都會走索引。rbo最大的問題在於,通過關聯規則來決定執行計畫。並不會考慮sql中涉及的對象的數量和分布。有可能選出來的規則不是最優的執行計畫。
cbo 是基於成本的最佳化器(基於統計資訊),從目標諸多的執行路徑中選擇一個成本最小的執行路徑來作為執行計畫。成本指的是mysql根據相關的統計資訊,算出來sql語句對應的io,cpu等的消耗的一個估計值。計算過程涉及到索引、表、行等資料,過程比較複雜。
1.查詢最佳化工具使用統計資訊為sql選擇執行計畫。
2.mysql沒有資料長條圖,也無法手工刪除統計資訊。(oracle有)
3.在伺服器曾有查詢最佳化工具,卻沒有儲存資料和索引統計資訊。統計資訊由儲存引擎實現,不同的儲存引擎會儲存不同的統計資訊。
4.統計資訊分為索引的統計資訊和表的統計資訊。
查看統計資訊
索引統計資訊
show index from table 或information_schema.statistics表
表統計資訊
show table status like 或 information_schema.tables表
查詢執行引擎+返回資料給用戶端
得到執行計畫後,根據已有的執行計畫,查詢執行引擎,mysql的SQL Layer層,調用Storage Engine Layer層的介面,從mysql的儲存引擎中擷取到相對應的結果集,然後返回給使用者。
執行完成後,將結果返回給用戶端,如果是查詢語句,並且開啟了緩衝,那麼,mysql會同時將結果集放到查詢快取中。然後將查到的結果集返回。如果是增刪改操作,那麼返回執行語句後受影響的行數。