上一篇 提到,最近有個需求,要修改現有存儲結構,涉及查詢條件和查詢效率的考量,看了幾篇索引和HBase相關的文章,回憶了相關知識,結合項目需求,說說本身的理解和總結。html
整體目錄以下,上篇介紹了前3小節,分析了索引爲何快,總結了它的優勢和分類,以及索引的演化過程,中篇會重點介紹索引分析方法和常見索引優化。sql
部份內容摘錄了幾個博友的文章,最後會給出文章連接,感謝他們的精彩分析。緩存
經過中篇的介紹,你會了解到:安全
想要更好的優化查詢,首先要了解其總體查詢過程,從客戶端發送查詢請求,到接收到查詢結果,MySQL服務器作了不少工做。服務器
MySQL邏輯架構總體分爲三層,分別爲客戶端層、核心服務層、存儲引擎層,共同協做完成。微信
最上層爲客戶端層,好比:鏈接處理、受權認證、安全等功能等。架構
中間層是MySQL的核心服務,包括查詢解析、分析、優化、緩存、內置函數(好比:時間、數學、加密等),另外,全部的跨存儲引擎的功能也在這一層實現:存儲過程、觸發器、視圖等。ssh
最下層爲存儲引擎,負責數據存儲和提取,中間的服務層經過API與存儲引擎通訊,這些API接口屏蔽了不一樣存儲引擎間的差別。函數
重點看下MySQL是如何優化和執行查詢的,不少的查詢優化工做就是遵循一些原則讓MySQL的優化器可以按照預想的方式運行而已。post
先說下整體流程:
1.客戶端/服務端通訊協議
MySQL客戶端和服務器之間的通訊協議是「半雙工」:在任何一個時刻,要麼由服務器向客戶端發送數據,要麼由客戶端向服務器發送數據,不能同時發生,這也就意味着無法進行流量控制。
客戶端用一個單獨的數據包將查詢請求發送給服務器,服務器響應給用戶的數據一般會不少,由多個數據包組成,須要注意的是當服務器響應客戶端請求時,客戶端必須完整的接收整個返回結果,而不能簡單的只取前面幾條結果,而後讓服務器中止發送。
2.查詢緩存
若是查詢緩存是打開的,會檢查這個查詢語句是否命中查詢緩存中的數據,若是命中,在檢查一次用戶權限後直接返回緩存中的結果。
查詢緩存系統會跟蹤查詢中涉及的每一個表,在任何的寫操做時,MySQL必須將對應表的全部緩存都設置爲失效,若是查詢緩存很是大或者碎片不少,這個操做就可能帶來很大的系統消耗。
另外,任何的查詢語句在開始以前都必須通過檢查,即便這條SQL語句永遠不會命中緩存,若是查詢結果能夠被緩存,那麼執行完成後,會將結果存入緩存,也會帶來額外的系統消耗。
因此,打開緩存要慎重,只有當緩存帶來的資源節約大於其自己消耗的資源時,纔會給系統帶來性能提高,能夠將query_cache_type設置爲DEMAND,這時只有加入SQL_CACHE的查詢纔會走緩存,其餘查詢則不會。
3.語法解析和預處理
經過關鍵字將SQL語句進行解析,生成一顆解析樹,預處理則會根據MySQL規則進一步檢查解析樹是否合法。
4.查詢優化
一條查詢能夠有不少種執行方式,優化器的做用就是找到這其中最好的執行計劃,MySQL使用基於成本的優化器,它嘗試預測一個查詢使用某種執行計劃時的成本,並選擇其中成本最小的一個。
5.查詢執行引擎
存儲引擎接口提供了很是豐富的功能,但其底層僅有幾十個接口,這些接口像搭積木同樣完成了一次查詢的大部分操做。
6.返回結果給客戶端
結果集返回客戶端是一個增量且逐步返回的過程,這樣服務端就無須存儲太多結果而消耗過多內存,也可讓客戶端第一時間得到返回結果。
下面來看看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:
2.WHERE
對VT1過程當中生成的臨時表進行過濾,知足WHERE子句的列被插入到VT2表中:
3.GROUP BY
這個子句會把VT2中生成的表按照GROUP BY中的列進行分組,生成VT3表:
4.HAVING
對VT3表中的不一樣的組進行過濾,只用於分組後的數據,知足HAVING條件的子句被加入到VT4表中。
5.SELECT
這個子句對SELECT子句中的元素進行處理,生成VT5表:
6.ORDER BY
從VT5-J2中的表中,根據ORDER BY 子句的條件對結果進行排序,生成VT6表,這是惟一可以使用SELECT中別名的地方。
7.LIMIT
從上一步獲得的VT6虛擬表中選出從指定位置開始的指定行數據。
本小節介紹下經常使用的高級查詢概念。
將多張表按照某個指定的條件進行數據拼接,SQL中將鏈接查詢分紅四類: 內鏈接、外鏈接、天然鏈接、交叉鏈接,其中天然鏈接和交叉鏈接不多用到,就不過多介紹了。
1.內鏈接 inner join
從左表中取出每一條記錄,分別與右表中全部的記錄進行匹配,匹配必須左表和右表中都知足條件,匹配的會保留結果,不然不保留。
2.外鏈接 left/right join
外鏈接分爲兩種:
以某張表爲主,取出裏面的全部記錄,無論能不能匹配上條件,主表最終都會保留,而後與另一張表進行鏈接,若是不能匹配,其餘表的字段都置空NULL。
是在某個查詢結果之上再進行查詢,也就是一條select語句內部包含了另一條select語句。
按子查詢所在位置,能夠劃分爲:
下面舉幾個例子:
查找部門名稱前綴爲「小米」的全部員工:
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選項:
又寫多了,再加一篇吧,中篇未完待續。。。
參考文章:
歡迎掃描下方二維碼,關注個人我的微信公衆號,查看更多文章 ~