開發人員基本都知道,咱們的數據存在數據庫中(目前最多的是mysql和oracle,因爲做者更擅長mysql,因此這裏默認數據庫爲mysql),服務器經過sql語句將查詢數據的請求傳入到mysql數據庫。數據庫拿到sql語句之後。都是進行了哪些操做呢?這裏向你們介紹下個人我的的理解,歡迎你們評論區批評指正。mysql
mysql獲得sql語句後,大概流程以下:sql
1.sql的解析器:負責解析和轉發sql數據庫
2.預處理器:對解析後的sql樹進行驗證緩存
3.查詢優化器:獲得一個執行計劃服務器
4.查詢執行引擎:獲得數據結果集oracle
5.將數據放回給調用端。性能
流程圖以下所示:優化
首先,若是系統的緩存功能開啓着的話,sql語句進入mysql後,sql進行判斷,是否爲select關鍵字。若是是,那麼先去查詢緩存中進行查詢,若是在查詢緩存中能夠命中sql語句,那麼直接返回查詢緩存中的查詢語句對應的value值(在緩存中,把查詢語句作一個hash運算,結果做爲key值,查詢的結果集爲value)。編碼
若是命中緩存的話,查詢速度是至關快的。可是查詢緩存也有它相應的缺點。spa
首先,開啓緩存的話,服務器會消耗大量的內存空間;其次,緩存有的時候並不適用;最後,有的狀況下,開啓緩存也不會將對應的sql語句寫入緩存。
緩存的鎖的力度比較大,並且對於動態sql的支持度不夠。
緩存在數據進行更新的時候,是進行的表級鎖,更新結束後,會把全部與更新內容相關的緩存所有刪除。因此,若是表的寫入比較多的話,緩存是比較浪費性能的。若是寫入特別多,可能緩存反而會致使mysql變慢。
1.查詢條件有不肯定數據:如now ,current_time等。
2.緩存對大小寫敏感,如select * from test 和SELECT* FROM test 就不會解析爲同一條sql
1.開始前須要先檢查緩存是否命中。
2.結果輸出的時候,須要額外進行數據的緩存操做。
3.寫入數據時,mysql會將對應表的全部緩存都設置爲失效。當緩存內存較大的時候,會致使系統消耗較大。
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會同時將結果集放到查詢緩存中。而後將查到的結果集返回。若是是增刪改操做,那麼返回執行語句後受影響的行數。