理解索引(中):MySQL查詢過程和高級查詢

上一篇 提到,最近有個需求,要修改現有存儲結構,涉及查詢條件和查詢效率的考量,看了幾篇索引和HBase相關的文章,回憶了相關知識,結合項目需求,說說本身的理解和總結。html

整體目錄以下,上篇介紹了前3小節,分析了索引爲何快,總結了它的優勢和分類,以及索引的演化過程,中篇會重點介紹索引分析方法和常見索引優化。sql

  • 爲何須要索引
  • 索引的類別
  • MySQL索引演化
  • MySQL索引優化
  • HBase介紹
  • HBase存儲結構
  • HBase索引介紹
  • 業務需求及設計

部份內容摘錄了幾個博友的文章,最後會給出文章連接,感謝他們的精彩分析。緩存

經過中篇的介紹,你會了解到:安全

  • MySQL查詢過程
  • 高級查詢相關概念
  • explain命令詳細介紹
  • 索引優化建議

MySQL查詢過程

想要更好的優化查詢,首先要了解其總體查詢過程,從客戶端發送查詢請求,到接收到查詢結果,MySQL服務器作了不少工做。服務器

邏輯架構

MySQL邏輯架構總體分爲三層,分別爲客戶端層、核心服務層、存儲引擎層,共同協做完成。微信

MySQL邏輯架構

最上層爲客戶端層,好比:鏈接處理、受權認證、安全等功能等。架構

中間層是MySQL的核心服務,包括查詢解析、分析、優化、緩存、內置函數(好比:時間、數學、加密等),另外,全部的跨存儲引擎的功能也在這一層實現:存儲過程、觸發器、視圖等。ssh

最下層爲存儲引擎,負責數據存儲和提取,中間的服務層經過API與存儲引擎通訊,這些API接口屏蔽了不一樣存儲引擎間的差別。函數

具體執行過程

重點看下MySQL是如何優化和執行查詢的,不少的查詢優化工做就是遵循一些原則讓MySQL的優化器可以按照預想的方式運行而已。post

查詢具體過程

先說下整體流程:

  • 客戶端發送一條查詢SQL給服務器;
  • 服務器先檢查查詢緩存,若是命中了緩存,則當即返回存儲在緩存中的結果;
  • 服務器端進行SQL解析、預處理,再由優化器生成對應的執行計劃;
  • 查詢執行引擎根據優化器生成的執行計劃,調用存儲引擎的API來執行查詢;
  • 將結果返回給客戶端;

1.客戶端/服務端通訊協議

MySQL客戶端和服務器之間的通訊協議是「半雙工」:在任何一個時刻,要麼由服務器向客戶端發送數據,要麼由客戶端向服務器發送數據,不能同時發生,這也就意味着無法進行流量控制。

客戶端用一個單獨的數據包將查詢請求發送給服務器,服務器響應給用戶的數據一般會不少,由多個數據包組成,須要注意的是當服務器響應客戶端請求時,客戶端必須完整的接收整個返回結果,而不能簡單的只取前面幾條結果,而後讓服務器中止發送。

2.查詢緩存

若是查詢緩存是打開的,會檢查這個查詢語句是否命中查詢緩存中的數據,若是命中,在檢查一次用戶權限後直接返回緩存中的結果。

查詢緩存系統會跟蹤查詢中涉及的每一個表,在任何的寫操做時,MySQL必須將對應表的全部緩存都設置爲失效,若是查詢緩存很是大或者碎片不少,這個操做就可能帶來很大的系統消耗。

另外,任何的查詢語句在開始以前都必須通過檢查,即便這條SQL語句永遠不會命中緩存,若是查詢結果能夠被緩存,那麼執行完成後,會將結果存入緩存,也會帶來額外的系統消耗。

因此,打開緩存要慎重,只有當緩存帶來的資源節約大於其自己消耗的資源時,纔會給系統帶來性能提高,能夠將query_cache_type設置爲DEMAND,這時只有加入SQL_CACHE的查詢纔會走緩存,其餘查詢則不會。

3.語法解析和預處理

經過關鍵字將SQL語句進行解析,生成一顆解析樹,預處理則會根據MySQL規則進一步檢查解析樹是否合法。

4.查詢優化

一條查詢能夠有不少種執行方式,優化器的做用就是找到這其中最好的執行計劃,MySQL使用基於成本的優化器,它嘗試預測一個查詢使用某種執行計劃時的成本,並選擇其中成本最小的一個。

5.查詢執行引擎

存儲引擎接口提供了很是豐富的功能,但其底層僅有幾十個接口,這些接口像搭積木同樣完成了一次查詢的大部分操做。

6.返回結果給客戶端

結果集返回客戶端是一個增量且逐步返回的過程,這樣服務端就無須存儲太多結果而消耗過多內存,也可讓客戶端第一時間得到返回結果。

SELECT執行順序

下面來看看SQL查詢語句的執行順序,每一步都會生成一個虛擬臨時表,做爲下一步的輸入。

標準的SQL語法以下:

SELECT DISTINCT
    < select_list >
FROM
    < left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE
    < where_condition >
GROUP BY
    < group_by_list >
HAVING
    < having_condition >
ORDER BY
    < order_by_condition >
LIMIT < limit_number >
複製代碼

但執行順序是這樣的:

FROM 
    <left_table>
ON <join_condition> <join_type> 
JOIN <right_table>
WHERE 
    <where_condition>
GROUP BY 
    <group_by_list>
HAVING 
    <having_condition>
SELECT 
DISTINCT 
    <select_list>
ORDER BY 
    <order_by_condition>
LIMIT 
    <limit_number>
複製代碼

1.FROM

當涉及多個表的時候,左邊表的輸出會做爲右邊表的輸入,以後會生成一個虛擬表VT1:

  • 計算兩個相關聯表的笛卡爾積(CROSS JOIN) ,生成虛擬表VT1-J1;
  • 基於虛擬表VT1-J1進行過濾,過濾出全部知足ON謂詞條件的行,生成虛擬表VT1-J2;
  • 若是使用了外鏈接(LEFT,RIGHT,FULL),主表(保留表)中的不符合ON條件的列也會被加入到VT1-J2中,生成虛擬表VT1-J3;

2.WHERE

對VT1過程當中生成的臨時表進行過濾,知足WHERE子句的列被插入到VT2表中:

  • 與ON的區別:若是有外鏈接,ON針對過濾的是關聯表,主表會返回全部的列,若是沒有外鏈接,效果相同;
  • 對主表的過濾應該放在WHERE;
  • 於關聯表,先條件查詢後鏈接則用ON,先鏈接後條件查詢則用WHERE;

3.GROUP BY

這個子句會把VT2中生成的表按照GROUP BY中的列進行分組,生成VT3表:

  • 其後處理過程的語句,如SELECT,HAVING,所用到的列必須包含在GROUP BY中,對於沒有出現的,得用聚合函數;

4.HAVING

對VT3表中的不一樣的組進行過濾,只用於分組後的數據,知足HAVING條件的子句被加入到VT4表中。

5.SELECT

這個子句對SELECT子句中的元素進行處理,生成VT5表:

  • 計算SELECT子句中的表達式,生成VT5-J1;
  • DISTINCT:尋找重複列,並刪掉,會建立一張內存臨時表VT5-J2,和虛擬表VT5-J1同樣,不一樣的是對DISTINCT的列增長惟一索引,以此來除重複數據;

6.ORDER BY

從VT5-J2中的表中,根據ORDER BY 子句的條件對結果進行排序,生成VT6表,這是惟一可以使用SELECT中別名的地方。

7.LIMIT

從上一步獲得的VT6虛擬表中選出從指定位置開始的指定行數據。

高級查詢相關概念

本小節介紹下經常使用的高級查詢概念。

鏈接查詢

將多張表按照某個指定的條件進行數據拼接,SQL中將鏈接查詢分紅四類: 內鏈接、外鏈接、天然鏈接、交叉鏈接,其中天然鏈接和交叉鏈接不多用到,就不過多介紹了。

1.內鏈接 inner join

從左表中取出每一條記錄,分別與右表中全部的記錄進行匹配,匹配必須左表和右表中都知足條件,匹配的會保留結果,不然不保留。

2.外鏈接 left/right join

外鏈接分爲兩種:

  • left join: 左外鏈接(左鏈接),以左表爲主表
  • right join: 右外鏈接(右鏈接),以右表爲主表

以某張表爲主,取出裏面的全部記錄,無論能不能匹配上條件,主表最終都會保留,而後與另一張表進行鏈接,若是不能匹配,其餘表的字段都置空NULL。

子查詢

是在某個查詢結果之上再進行查詢,也就是一條select語句內部包含了另一條select語句。

按子查詢所在位置,能夠劃分爲:

  • From子查詢:子查詢跟在from以後;
  • Where子查詢: 子查詢出where條件中;
  • exists子查詢: 子查詢出如今exists裏面;

下面舉幾個例子:

查找部門名稱前綴爲「小米」的全部員工:

SELECT name , sex ,  sal
        FROM emp
        WHERE no in ( 
            SELECT no FROM dept 
                WHERE name LIKE '小米%'
        );
複製代碼

查看全部員工的薪水,並按薪水排序:

SELECT name , sal
       FROM (
           SELECT name , sal 
              FROM emp ORDER BY sal
       );
複製代碼
聯合查詢

將屢次查詢, 將結果進行拼接,字段不會增長,每一條select語句獲取的字段數必須嚴格一致。

語法以下:

Select 語句1

Union [union選項]

Select語句2...
複製代碼

Union選項:

  • All: 保留全部;
  • Distinct: 去重,默認選項;

又寫多了,再加一篇吧,中篇未完待續。。。

參考文章:

  1. MySQL優化原理
  2. 步步深刻:SQL解析順序

歡迎掃描下方二維碼,關注個人我的微信公衆號,查看更多文章 ~

情情說
相關文章
相關標籤/搜索