MySQL學習 - 查詢的執行過程

想要得到更好的表現,你須要:  合理的表結構 + 出色的索引 + [ 不錯的查詢語句]


1. 慢查詢是怎麼回事


1.1 我怎麼才能知道個人查詢很慢

  • 開啓慢查詢日誌,好比你認爲查詢超過1秒就是慢,MySQL會記錄下超過1秒的查詢記錄
  • 看看是否是由於MySQL任務太多致使你查詢很慢
  • 使用EXPLAIN , 仔細研究每一條語句,看看是否是執行了不應執行的內容


1.2 你是否是向數據庫請求了多餘的數據

不少時候你其實在向數據庫請求了超多資源,可能你並無意識到,這些多餘的數據會被拋棄,並給MySQL服務器端增長額外的壓力。 一些場景:html

  • 你取了全部數據,可是你的程序卻只用到前面10行:   
    • 若是你真的只須要10行,學會使用 LIMIT 10
  • 取了所有的列,可是實際用不到。這可能會使你喪失使用覆蓋索引的機會
    • 什麼是覆蓋索引?   假設你的索引是A+B,對應B-Tree內節點,有A+B的狀況下能夠查找到完整數據儲存位置。 可是若是你 select A,B from users, 你直接讀B-Tree就完事了,你甚至都不用去找完整數據,更快。可是你仍是選擇了 select * ,咱們就須要回去找完整數據,去找你根本用不到的剩餘列
    • 除了覆蓋索引,你還可能給服務器帶來許多沒必要要的IO壓力
  • 重複查詢的數據
    • 好比查找頭像這種請求,徹底能夠經過緩存,不必定每次都要從新請求


1.3 MySQL有沒有掃描多餘的行

-- 使用索引
EXPLAIN SELECT * FROM users WHERE id = 1\G
********************** 1.row **********************
             type: ref    
             key : id     
             rows: 10     

-- 刪除索引
EXPLAIN SELECT * FROM users WHERE id = 1\G
********************** 1.row ***********************
             type:  ALL        
             rows:  5073       
             extra: Using Where
複製代碼

咱們能夠經過"EXPLAIN" 命令看看這條命令是怎麼執行的,有沒有索引掃描內容真的差異太大mysql

  • 若是你有索引,而且經過索引檢索,咱們使用 key=id 的 ref 方式,這種狀況下,MySQL大概須要掃描10行,能獲得你想要的數據
  • 可是若是你沒有索引了,咱們如今只能經過先全表掃描 + USING WHERE 的方式來篩選了,這種狀況下預計得掃描5073行才能獲得你想要的數據
    • 真的掃描了太多本不須要的東西

在表面上,咱們都直接在 SQL 語句加上WHERE就完事兒,並不過多的去關心性能問題,可是即便你們都是WHERE, 在"索引" 的輔助下也會存在很大的優劣之分sql

由好到差:數據庫

  • WHERE 篩選項 即 索引, 這個在存儲引擎層就能完成  ->  圖一所示案例
  • 索引能覆蓋掃描項目(使用覆蓋索引), 標誌是EXPLAIN顯示Extra=Using Index 操做手法爲MySQL服務器拿着索引前往B-Tree讀數據就結束,不用數據庫讀數
  • 沒有使用索引,直接使用WHERE,數據庫引擎須要先從表中讀出數據,返回給MySQL服務器,而後MySQL用WHERE過濾,這樣一來數據庫引擎必定掃描了不少數據 -> 圖二所示

總結一下,不管是方法1.存儲引擎能直接訪問須要的行,仍是2.直接前往B-Tree讀數,都好過全表掃描,返回全部數據而後由MySQL作過濾。 爲了達到這樣的效果,儘量把要用到的WHERE篩選項放到索引中去緩存



2. 查詢的過程是怎樣的

“MYSQL 查询过程”的图片搜索结果

爲了更好的作出優化,以及後面會提到的"緩存命中",咱們必須也要先知道查詢過程是怎樣的。 關於詳細的步驟,咱們會在下面的環節描述一下各個部件是怎麼工做的bash

  1. 客戶端發送一條請求給服務器
  2. 服務器先檢查緩存,若是命中緩存則直接返回結果,不然進入下一階段
  3. MySQL服務器進行SQL解析,預處理,再由優化器生成執行計劃
  4. MySQL服務器根據執行計劃調用存儲引擎API接口
  5. 將結果緩存 並 返還給客戶端


2.1 客戶端 & MySQL 服務器之間的交互

MySQL客戶端與MySQL服務器之間的交互是半雙工的,也就是說同一時刻內只有其中一方向另外一方發送請求,這個請求能夠是客戶端向服務器發送SQL語句,也能夠是服務器向客戶端返回所請求的數據,一旦客戶端發送了請求之後,它所能作的就只有等待服務器返回所請求的數據服務器

  • 等待服務器查詢並返回的結果比較漫長,因此一個比較好的辦法是把查詢返回的數據進行緩存,下次須要用的時候直接從緩存讀取便可,能夠減輕服務器的壓力
  • 當咱們使用不少個連接發送請求的時候,表面上看咱們是從MySQL服務器獲取數據,其實都是緩存獲取數據,這樣能夠很大程度提高效率


2.2 如何使用緩存

在解析一個SQL語句以前服務器會先看看是否有命中緩存中的數據,也就是看看是否已經有緩存上了。檢查的標準是經過對查詢語句的哈希實現的,若是哈希出的結果是同樣的就算命中,而且這個哈希是對大小寫敏感的,也就是說哪怕是大小寫不一致都不能算命中性能


2.3 SQL解析 & 預處理

MySQL服務器經過關鍵字將客戶端發來的SQL語句進行解析,解析器經過MYSQL語法對這條語句進行驗證,例如它將驗證是否使用了錯誤的關鍵字,關鍵字順序是否正確等。優化

預處理器則會去檢查它所請求的數據表以及列是否存在,並驗證權限。spa


2.4 查詢優化器的優化原則

走到了這一步說明你的語句沒有問題,能執行,問題就是怎麼執行。 因此查詢優化器,會先找出不少個可能的作法,並嘗試找出最優解 優化原則? 找出成本最低的

mysql > SELECT SQL_NO_CACHE COUNT(*) FROM users
+----------+
| count(*) |
+----------+
|     5462 |
+----------+

mysql > SHOW STATUS LIKE 'Last_query_cost'
+-----------------+-------------+
| Variable_name   | Value       |
+-----------------+-------------+
| Last_query_cost | 1040.59     |
+-----------------+-------------+複製代碼
  • 你可使用以上的方式查看一下,上一條執行語句的 」執行成本「 是多少
  • "執行成本" 說明MySQL服務器認爲須要加載1040個數據頁,並在其中作隨機查找才能夠
    • 這個 "執行成本" 是這麼考量出來的
      • 索引節點,涉及多少個頁面
      • 索引以及數據行的長度,索引的分佈狀況
      • 可是優化器並不考慮有"緩存" 這種東西,它假設每取一次數 == 一次磁盤IO
    • "執行成本"  必定是準確的嗎?
      • 必定不是,考量不少時候就沒法考慮到所有狀況,而且他也不知道什麼在內存裏什麼在磁盤上,在內存裏的都不用作磁盤IO
      • 可是大部分時候計算出來的執行成本會比人思考的更準確



2.5 MySQL優化器 - 從新定義關聯順序

2.5.1 先簡單介紹一下聯表的執行過程 (若是你知道就能夠跳過了)

“mysql join 泳道图”的图片搜索结果

-- 上圖反應的就是下面個SQL語句的聯表過程
SELECT tbl1.col1 , tbl2.col2 
FROM tbl1 JOIN tbl2 USING(col3)
WHERE tbl1.col1 IN(5,6)複製代碼

表之間的關聯遵循一種"嵌套" 的規則,用最簡單的話說就是先取表[tbl1]的第一行,去表[tbl2]中作匹配,對於咱們,咱們天然是但願執行的步驟越少越好:

  • 咱們先從[tbl1]中挑出 col1在(5,6)範圍內的全部記錄
  • 對於每一條這樣的記錄,去遍歷 tbl2, 找出匹配,成爲符合的輸出
  • 因此,若是第一個表,它知足條件的記錄,越少,是否是咱們在tbl2中遍歷,也就越少?所以一個大原則誕生了,咱們必定但願,第一張表符合條件的越少越好。 這個原則會成爲聯表優化最重要的原則

2.5.2 聯表優化實戰分析

SELECT tbl1.col1, tbl2.col2, tbl3.col3
FROM tbl1
INNER JOIN tbl2 USING(tbl1.col1)
INNER JOIN tbl3 USING(tbl3.col3);複製代碼

  • tbl1 一共 1000行,tbl3 一共200行, 三張表都有索引
  • 雖然第一個出如今SQL語句裏的tbl1, 在通過聯表優化之後第一個出現的是tbl3,緣由:
    • 若是咱們拿着第一張表的索引前往第二張表匹配,根據索引查詢都很快
    • 因此問題變成了若是第一張表會越短,咱們匹配的次數就越少
    • tbl3 比 tbl1 短,所以被自動優化成第一個出現的表
相關文章
相關標籤/搜索