Mysql基本架構及查詢流程

mysql體系結構簡單概述:

  1. Connectors:接入方,支持協議不少
  2. Management Serveices & Utilities系統管理和控制工具例如:備份恢復,mysql複製集羣等
  3. Connection Pool鏈接池:管理緩衝用戶鏈接、用戶名、密碼、權限校驗、線程處理等須要緩存的需求
  4. SQL InterfaceSQL接口:接受用戶的SQL命令,而且返回用戶須要查詢的結果。好比select from就是調用SQL Interface
  5. Parser: 解析器,SQL命令傳遞到解析器的時候會被解析器驗證和解析。解析器是由LexYACC實現的。
  6. Optimizer: 查詢優化器,SQL語句在查詢以前會使用查詢優化器對查詢進行優化
  7. CacheBuffer(高速緩存區): 查詢緩存,若是查詢緩存有命中的查詢結果,查詢語句就能夠直接去查詢緩存中取數據。
  8. pluggable storage Engines插件式存儲引擎。存儲引擎是MySql中具體的與文件打交道的子系統。也是Mysql最具備特點的一個地方。 Mysql的存儲引擎是插件式的。
  9. file system  :文件系統,數據、日誌(redoundo)、索引、錯誤日誌、查詢記錄、慢查詢等

常見的存儲引擎:

 Mysql插拔式的存儲引擎:html

  1. 插拔式的插件方式。
  2. 存儲引擎是指定在表之上的,即一個庫中的每個表均可以指定專用的存儲引擎。
  3. 無論表採用什麼樣的存儲引擎,都會在數據區,產生對應的一個frm文件(表結構定義描述文件)。

CSV:https://dev.mysql.com/doc/refman/5.7/en/csv-storage-engine.htmlmysql

  數據存儲以CSV文件,會生成3個文件 table_name.CSM(元數據狀態管理,數據行) table_name.CSV(數據文件) table_name.frm。特色:linux

  不能定義沒有索引、列定義必須爲NOT NULL。sql

  不能設置自增列,不適用大表或者數據的在線處理。緩存

  CSV數據的存儲用,隔開,可直接編輯CSV文件進行數據的編排,數據安全性低。安全

注:編輯以後,要生效使用 flush table XXX 命令。服務器

應用場景:數據的快速導出導入,表格直接轉換成CSV。函數

Archive:https://dev.mysql.com/doc/refman/5.7/en/archive-storage-engine.html工具

  會生成 table_name.ARZ   table_name.frm,數據存儲爲ARZ文件格式。特色:測試

  只支持 insert 和 select 兩種操做,只容許自增ID列創建索引,行級鎖,不支持事務,數據佔用磁盤少。

應用場景:日誌系統,大量的設備數據採集。

Memory(heap):https://dev.mysql.com/doc/refman/5.7/en/memory-storage-engine.html

  數據都是存儲在內存中,IO效率要比其餘引擎高不少,服務重啓數據丟失,內存數據表默認只有16M。特色:

  支持hash索引,B tree索引,默認hash(查找複雜度0(1)),字段長度都是固定長度varchar(32)=char(32),不支持大數據存儲類型字段如 blog,text,表級鎖

應用場景:等值查找熱度較高數據,查詢結果內存中的計算,大多數都是採用這種存儲引擎,做爲臨時表存儲需計算的數據。

Myisam:https://dev.mysql.com/doc/refman/5.7/en/myisam-storage-engine.html

  Mysql5.5版本以前的默認存儲引擎,較多的系統表也仍是使用這個存儲引擎,系統臨時表也會用到Myisam存儲引擎。特色:

  select count(*) from table 無需進行數據的掃描,數據(MYD)和索引(MYI)分開存儲,表級鎖,不支持事務。

Innodb:https://dev.mysql.com/doc/refman/5.7/en/innodb-introduction.html

  在建立好表結構而且指定搜索引擎爲 Myisam以後,會在數據目錄生成3個文件,分別是table_name.frm(表結構文件),table_name.idb(數據與索引保存文件)。Mysql5.5及之後版本的默認存儲引擎

  Key Advantages:Its DML operations follow the ACID model [事務ACID]。

  Row-level locking[行級鎖]InnoDB tables arrange your data on disk to optimize queriesbased on primary keys[彙集索引(主鍵索引)方式進行數據存儲]。

  To maintain data integrity, InnoDB supports FOREIGN KEY constraints[支持外鍵關係保證數據完整性]。

  接下來看一下這些經常使用的搜索引擎的簡單對比圖,也能看出爲何InnoDB最後悔脫穎而出:

MySQL運行機理:

  由下圖能夠看出Mysql的執行流程大體分爲 5 個階段:

  1. mysql 客戶端/服務端通訊階段。
  2. 查詢緩存階段。
  3. 查詢優化處理階段。
  4. 查詢執行引擎階段。
  5. 返回客戶端階段。

  咱們能夠根據執行的流程來看一下在優化的過程當中須要注意點什麼。

1.mysql 客戶端/服務端通訊階段:

Mysql客戶端與服務端的通訊方式是「半雙工」的通訊方式,通訊方式主要分爲如下三種:

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

半雙工通訊:

  在任何一個時刻,要麼是有服務器向客戶端發送數據,要麼是客戶端向服務端發送數據,這兩個動做不能同時發生。因此咱們沒法也無需將一個消息切成小塊進行傳輸

特色和限制:

  客戶端一旦開始發送消息,另外一端要接收完整個消息才能響應。客戶端一旦開始接收數據無法停下來發送指令。

mysql 客戶端/服務端通訊--查詢狀態

  有一整套狀態集去管理狀態。對於一個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}的方式進行鏈接的殺掉

2.查詢緩存階段:

  工做原理:緩存SELECT操做的結果集和SQL語句;新的SELECT語句,先去查詢緩存,判斷是否存在可用的記錄集。

  判斷標準:與緩存的SQL語句,是否徹底同樣,區分大小寫 (簡單認爲存儲了一個key-value結構,key爲sql,value爲sql查詢結果集)。

  能夠經過如下命令來查看緩存的設置狀況:

在my.cnf配置文件中能夠配置:

query_cache_type:

  • 值:0 -– 不啓用查詢緩存,默認值;
  • 值:1 -– 啓用查詢緩存,只要符合查詢緩存的要求,客戶端的查詢語句和記錄集均可以緩存起來,供其餘客戶端使用,加上 SQL_NO_CACHE將不緩存 ,如select SQL_NO_CACHE *from.......
  • 值:2 -– 啓用查詢緩存,只要查詢語句中添加了參數:SQL_CACHE,且符合查詢緩存的要求,客戶端的查詢語句和記錄集,則能夠緩存起來,供其餘客戶端使用

query_cache_size:容許設置query_cache_size的值最小爲40K,默認1M,推薦設置 爲:64M/128M;

query_cache_limit:限制查詢緩存區最大能緩存的查詢記錄集,默認設置爲1M

  能夠經過 show status like 'Qcache%' 命令可查看緩存狀況:

 

  須要注意的是,一旦表數據發生一點變化,與這個表所相關的緩存所有失效,不會緩存的狀況:

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

爲何mysql默認關閉了緩存開啓??

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

適用場景 :以讀爲主的業務,數據生成以後就不常改變的業務。好比門戶類、新聞類、報表類、論壇類等

3.查詢優化處理階段:

  查詢優化處理的三個階段:

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

  查詢優化器如何找到最優計劃 ,經過explain  +查詢sql查看執行計劃+\G。

  查詢優化器如何找到最優執行計劃,有以下規則:

  1. 使用等價變化規則:5 = 5 and a > 5 改寫成 a > 5,a < b and a = 5 改寫成 b > 5 and a = 5
  2. 基於聯合索引,調整條件位置等
  3. 優化count 、min、max等函數:min函數只需找索引最左邊,max函數只需找索引最右邊,myisam引擎count(*)
  4. 覆蓋索引掃描:若是是創建了一個 name 字段的索引,InnoDB因爲葉子節點保存了ID索引的key值,這種狀況下 使用 select id,name from。。。這個也會用到覆蓋索引
  5. 子查詢優化  
  6. 提早終止查詢:用了limit關鍵字或者使用不存在的條件,選擇不一樣的索引來執行,在採用limit的狀況下,查詢優化器在成本計算的過程當中也能夠選擇離散型不高的列索引。
  7. IN的優化:用 or的狀況是一條一條去比對,in:用二分法,where in(1,2,3,4,5),先排序條件後再比對中間位置 3,經過二分查找法進行查找,當條件多的狀況下  ,相對來講的話in的優化會好一點。先進性排序,再採用二分查找的方式

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

  mysql查詢優化 -執行計劃:使用命令查看一句查詢SQL,看看查詢計劃中都涉及什麼有用的信息

id:select查詢的序列號,標識執行的順序

  • id相同,執行順序由上至下,聯表查詢使用union  id爲空。
  • id不一樣,若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
  • id相同又不一樣即兩種狀況同時存在,id若是相同,能夠認爲是一組,從上往下順序執行;在全部組中,id值越大,優先級越高,越先執行

select_type:查詢的類型,主要是用於區分普通查詢、聯合查詢、子查詢等

  • SIMPLE:簡單的select查詢,查詢中不包含子查詢或者union
  • PRIMARY:查詢中包含子部分,最外層查詢則被標記爲primary
  • SUBQUERY/MATERIALIZED:SUBQUERY表示在select 或 where列表中包含了子查詢
  • MATERIALIZED表示where 後面in條件的子查詢
  • UNION:若第二個select出如今union以後,則被標記爲union;
  • UNION RESULT:從union表獲取結果的select

table :查詢涉及到的表

  • 直接顯示錶名或者表的別名
  • <unionM,N> 由ID爲M,N 查詢union產生的結果
  • <subqueryN> 由ID爲N查詢生產的結果

type:訪問類型,sql查詢優化中一個很重要的指標,結果值從好到壞依次是:system > const > eq_ref > ref > range > index > ALL

  • system:表只有一行記錄(等於系統表),const類型的特例,基本不會出現,能夠忽略不計
  • const:表示經過索引一次就找到了,const用於比較primary key 或者 unique索引
  • eq_ref:惟一索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配。常見於主鍵 或 惟一索引掃描
  • ref:非惟一性索引掃描,返回匹配某個單獨值的全部行,本質是也是一種索引訪問
  • range:只檢索給定範圍的行,使用一個索引來選擇行(至少要這個級別)
  • index:Full Index Scan,索引全表掃描,把索引從頭至尾掃一遍
  • ALL:Full Table Scan,遍歷全表以找到匹配的行

執行計劃:

possible_keys:查詢過程當中有可能用到的索引

key:實際使用的索引,若是爲NULL,則沒有使用索引 rows,根據表統計信息或者索引選用狀況,大體估算出找到所需的記錄所須要讀取的行數。

filtered:它指返回結果的行佔須要讀到的行(rows列的值)的百分比。表示返回結果的行數佔需讀取行數的百分比,filtered的值越大越好。

Extra :十分重要的額外信息

  • Using filesort :mysql對數據使用一個外部的文件內容進行了排序,而不是按照表內的索引進行排序讀取 order by xxx desc這樣子的,若是是索引字段的排序則不是這樣的,就不須要使用外部文件了
  • Using temporary:使用臨時表保存中間結果,也就是說mysql在對查詢結果排序時使用了臨時表,常見於order by 或 group by
  • Using index:表示相應的select操做中使用了覆蓋索引(Covering Index),避免了訪問表的數據行,效率高
  • Using where :使用了where過濾條件
  • select tables optimized away:基於索引優化MIN/MAX操做或者MyISAM存儲引擎優化COUNT(*)操做,沒必要等到執行階段在進行計算,查詢執行。計劃生成的階段便可完成優化

4.mysql查詢執行引擎階段:

  調用插件式的存儲引擎的原子API的功能進行執行計劃的執行,執行計劃的好壞也是依賴於搜索引擎的。

5.返回客戶端階段:

一、有須要作緩存的,執行緩存操做。

二、增量的返回結果:開始生成第一條結果時,mysql就開始往請求方逐步返回數據。

  好處: mysql服務器無須保存過多的數據,浪費內存。用戶體驗好,立刻就拿到了數據。

如何定位慢SQL:

  1. 業務驅動:根據業務反饋來肯定哪些sql可能出現問題。
  2. 測試驅動:經過測試肯定哪些sql出現問題。
  3. 慢查詢日誌:經過日誌記錄的方式查找執行效率慢的sql。
  4. 其餘第三方工具。

慢日誌查詢配置:

show variables like 'slow_query_log' //--查看是否開啓慢日誌保存
set global slow_query_log = on //-- 打開慢日誌
set global slow_query_log_file = '/var/lib/mysql/gupaoedu-slow.log' //--慢日誌保存位置
set global log_queries_not_using_indexes = on //-- 沒有命中索引的是否要記錄慢日誌
set global long_query_time = 0.1 (秒) //-- 執行時間超過多少爲慢日誌

  能夠直接打開編輯 vi slow.log文件來查看,以下圖的信息:

  • Time :日誌記錄的時間。
  • User@Host:執行的用戶及主機。
  • Query_time:查詢耗費時間 Lock_time 鎖表時間 Rows_sent 發送給請求方的記錄,條數 Rows_examined 語句掃描的記錄條數。
  • SET timestamp 語句執行的時間點。
  • select .... 執行的具體語句。

慢日誌分析工具:

  mysqldumpslow -t(查詢多少行) 10 -s at(平均查詢時間) /var/lib/mysql/gupaoedu-slow.log

   經過返回的記錄能看到前10條執行效率比較低下的sql信息,開發者能夠經過這些信息去作相應的優化。

相關文章
相關標籤/搜索