MySQL 語句執行過程詳解

MySQL 原理篇

MySQL 索引機制

MySQL 體系結構及存儲引擎

MySQL 語句執行過程詳解

MySQL 執行計劃詳解

MySQL InnoDB 緩衝池

MySQL InnoDB 事務

MySQL InnoDB 鎖

MySQL InnoDB MVCC

MySQL InnoDB 實現高併發原理

MySQL InnoDB 快照讀在RR和RC下有何差異

當客戶端向 MySQL 發送一個請求的時候,MySQL 的執行過程如下圖所示:

MySQL 客戶端/服務端通信

通信機制

MySQL 客戶端與服務端的通信方式是 “ 半雙工 ”。

  • 全雙工:雙向通信,發送同時也可以接收
  • 半雙工:雙向通信,同時只能接收或者是發送,無法同時做操作
  • 單工:只能單一方向傳送

一旦一端開始發送消息,另一端要接收完整個消息才能響應它,所以我們無法也無須將一個消息切成小塊獨立發送,也沒有辦法進行流量控制。

客戶端用一個單獨的數據包將查詢請求發送給服務器,所以當查詢語句很長的時候,需要設置 max_allowed_packet 參數。

但是需要注意的是,如果查詢實在是太大,服務端會拒絕接收更多數據並拋出異常。

與之相反的是,服務器響應給用戶的數據通常會很多,由多個數據包組成。但是當服務器響應客戶端請求時,客戶端必須完整的接收整個返回結果,而不能簡單的只取前面幾條結果,然後讓服務器停止發送。

因而在實際開發中,儘量保持查詢簡單且只返回必需的數據,減小通信間數據包的大小和數量是一個非常好的習慣,這也是查詢中儘量避免使用 SELECT * 以及加上 LIMIT 限制的原因之一。

連接狀態

對於一個 MySQL 的連接,或者說一個線程,時刻都有一個狀態來標識這個連接正在做什麼。

可以通過如下命令來查看連接的狀態:

show full processlist
show processlist

詳細的狀態集描述參考官網:https://dev.mysql.com/doc/refman/5.7/en/general-thread-states.html

這裏簡單介紹幾個常用的連接狀態:

  • Sleep:線程正在等待客戶端發送數據
  • Query:連接線程正在執行查詢
  • Locked:線程正在等待表鎖的釋放
  • Sorting result:線程正在對結果進行排序
  • Sending data:向請求端返回數據

對於出現問題的連接可以通過 kill {id} 的方式進行殺掉。

查詢緩存

工作原理:

  • 緩存 SELECT 操作的結果集和 SQL 語句。
  • 新的 SELECT 語句,先去查詢緩存,判斷是否存在可用的記錄集,需要注意的是在判斷的時候,要求 SQL 語句完全一樣(SQL 兩端允許存在空格)纔會匹配到緩存數據。

緩存參數

MySQL 的緩存參數在配置文件中設置,可以通過如下命令來查看緩存的參數:

show variables like 'query_cache%'

  1. query_cache_type
    1. 0:不啓用查詢緩存,默認值
    2. 1:啓用查詢緩存,只要符合查詢緩存的要求,客戶端的查詢語句和記錄集都可以緩存起來,供其他客戶端使用,SQL 語句中加上 SQL_NO_CACHE 將不緩存
    3. 2:啓用查詢緩存,只要查詢語句中添加了參數:SQL_CACHE,且符合查詢緩存的要求,客戶端的查詢語句和記錄集,則可以緩存起來,供其他客戶端使用
  1. query_cache_size
    1. 總的緩存池的大小,允許設置 query_cache_size 的值最小爲40K,默認1M,推薦設置爲64M/128M
    2. 當總的緩存池大小超過設置的值時,會按照時間順序,讓最老的緩存失效
  1. query_cache_limit
    1. 指定單個查詢能夠使用的緩衝區大小,默認設置爲1M

緩存執行情況

可以通過如下命令來查看緩存情況:

show status like 'Qcache%'

  1. Qcache_free_blocks
    1. Query Cache 中目前還有多少剩餘的 blocks。如果該值顯示較大,則說明 Query Cache 中的內存碎片較多了,可能需要尋找合適的機會進行整理
  1. Qcache_free_memory
    1. Query Cache 中目前剩餘的內存大小。通過這個參數我們可以較爲準確的觀察出當前系統中的Query Cache 內存大小是否足夠,是需要增加還是過多了
  1. Qcache_hits
    1. 緩存命中次數。通過這個參數我們可以查看到 Query Cache 的基本效果
  1. Qcache_inserts
    1. 插入緩存的記錄數,通過 Qcache_hits 和 Qcache_inserts 兩個參數我們就可以算出 Query Cache 的命中率,Query Cache 命中率 = Qcache_hits / ( Qcache_hits + Qcache_inserts )
  1. Qcache_lowmem_prunes
    1. 多少條 Query 因爲內存不足而被清除出 Query Cache。通過 Qcache_lowmem_prunes 和 Qcache_free_memory 相互結合,能夠更清楚的瞭解到我們系統中 Query Cache 的內存大小是否真的足夠,是否經常出現因爲內存不足而有 Query 被清除
  1. Qcache_not_cached
    1. 因爲 query_cache_type 的設置或者不能被 cache 的 Query 的數量
  1. Qcache_queries_in_cache
    1. 當前 Query Cache 中 cache 的 Query 數量
  1. Qcache_total_blocks
    1. 當前 Query Cache 中的 block 數量

不會緩存的情況

  1. 當查詢語句中設置了 SQL_NO_CACHE,則不會被緩存。
  2. 當查詢語句中有一些不確定的數據時,則不會被緩存。如包含函數 NOW() ,CURRENT_DATE() 等類似的函數,或者用戶自定義的函數,存儲函數,用戶變量等都不會被緩存。
  3. 當查詢的結果大於 query_cache_limit 設置的值時,結果不會被緩存。
  4. 對於 InnoDB 引擎來說,當一個語句在事務中修改了某個表,那麼在這個事務提交之前,所有與這個表相關的查詢都無法被緩存。因此長時間執行事務,會大大降低緩存命中率。
  5. 查詢的表是系統表。
  6. 查詢語句不涉及到表。

緩存有哪些坑?

  1. 在查詢之前必須先檢查是否命中緩存,浪費計算資源。
  1. 如果這個查詢可以被緩存,那麼執行完成後,MySQL 發現查詢緩存中沒有這個查詢,則會將結果存入查詢緩存,這會帶來額外的系統消耗。
  1. 針對表進行寫入或更新數據時,將對應表的所有緩存都設置失效。
  1. 如果查詢緩存很大或者碎片很多時,這個操作可能帶來很大的系統消耗。

適用場景

以讀爲主的業務,數據生成 之後就不常改變的業務,比如門戶類、新聞類、報表類、論壇類。

查詢優化處理

查詢優化處理的三個階段

  1. 解析 SQL
    1. 通過 lex 語法分析,yacc 語法分析將 SQL 語句解析成解析樹。
    2. lex、yacc 語法參考:https://www.ibm.com/developerworks/cn/linux/sdk/lex/
  1. 預處理階段
    1. 根據 MySQL 的語法的規則進一步檢查解析樹的合法性,如:檢查數據的表和列是否存在,解析名字和別名的設置。還會進行權限的驗證
  1. 查詢優化器
    1. 優化器的主要作用就是找到最優的執行計劃

查詢優化器如何找到最優執行計劃

這裏介紹幾種優化方式,更多的可以參考《高性能MySQL_第3版(中文)》

  1. 使用等價變化規則
    1. 5 = 5 and a > 5 改寫成 a > 5
    2. a < b and a = 5 改寫成 b > 5 and a = 5
    3. 基於聯合索引,調整條件位置等
  1. 優化 count、min、max 等函數
    1. InnoDB 引擎 min 函數只需找索引最左邊
    2. InnoDB 引擎 max 函數只需找索引最右邊
    3. MyISAM 引擎 count(*),不需要計算,直接返回
  1. 覆蓋索引掃描
  1. 子查詢優化
    1. select * from (select * from user where id = 1) as t;,會被優化成一級查詢
  1. 提前終止查詢
    1. 用了 limit 關鍵字或者使用不存在的條件,獲取到 limit 所需要的數據後,就不再遍歷接下來的數據
  1. IN 的優化
    1. MySQL 對於 IN 的查詢,會先進性排序,再採用二分查找的方式查找數據
    2. 比如表中的數據是 1,2,3,4,5,where 條件是 id IN(2,1,3),在進行 IN 操作的時候,會先對 IN 中的數據排序,變成 1,2,3,然後取出一條數據1先和2比較,1<2,則往2的左邊查找,進而找到1,接下來就是再獲取一條數據重複上面的查找步驟。
    3. 其他關係型數據庫不會採用二分查找的方式,而是和 or 的方式一樣,where id=1 or id=2 or id=3,從表中獲取一條數據和 where 條件中的 or 的數據一個一個比對。

MySQL 的查詢優化器是基於成本計算的原則,它會嘗試各種執行計劃,數據抽樣的方式進行試驗(隨機的讀取一個 4K 的數據塊進行分析)。

執行計劃

這塊內容比較多,後面會單獨提供一篇文章描述

查詢執行引擎

調用插件式的存儲引擎的原子 API 進行執行計劃的執行。

返回客戶端

  1. 有需要做緩存的,執行緩存操作
  2. 增量的返回執行結果,開始生成第一條結果時,MySQL 就開始往請求方逐步返回數據,這樣做的好處是 MySQL 服務器無須保存過多的數據,浪費內存,用戶體驗好,馬上就拿到了數據

參考

http://www.sohu.com/a/233335431_468739

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