下面是mysql查詢的路徑
下面簡單的理解一下mysql服務器的查詢過程
查詢緩存
在解析一個查詢語句之前,如果查詢緩存是打開的,那么mysql會優先檢查這個查詢是否命中緩存中的數據。如果命中查詢緩存,則在檢查用戶權限后直接返回查詢結果。否則進入下一階段的處理。
解析器
mysql通過關鍵字將sql語句進行解析,并生成解析樹。解析器使用mysql語法規則驗證和解析查詢。例如,它將驗證是否使用錯誤的關鍵字,或者使用關鍵字的順序是否正確等,還有引號能否前后匹配。
預處理器
預處理器則根據mysql規則進一步檢查解析樹是否合法,例如,這里將檢查數據表和數據列是否存在,還會解析名字和別名,看是否有歧義等。下一步預處理還會驗證權限。
查詢優化器
一條查詢可以有很多種執行方式,最后都返回相同的結果,優化器的作用就是找到這其中最好的執行計劃。
mysql使用基于成本的優化器,他將嘗試預測一個查詢使用某種執行計劃時的成本,并選擇其中成本最小的一個。可以通過查詢當前會話的last_query_cost的值來得知mysql計算當前的當前查詢的成本。
mysql> select sql_no_cache count(*) from renren.applicants;
+----------+
| count(*) |
+----------+
| 499362 |
+----------+
1 row in set (0.97 sec)
mysql> show status like 'last_query_cost';
+-----------------+---------------+
| Variable_name | Value |
+-----------------+---------------+
| Last_query_cost | 125297.999000 |
+-----------------+---------------+
1 row in set (0.02 sec)
這個結果表示mysql的優化器認為大概需要做125297個數據頁的隨機查詢才能完成上面的查詢,這是根據一系列的統計信息計算的來的。 sql_no_cache代表不讀取緩存。
下面是一些mysql能夠處理的優化類型:
重新定義關聯表的順序
數據表的關聯并不是總按照查詢指定的順序進行。
將外連接轉換成內連接
并不是所有的outer join 語句都必須以外連接的方式執行。例如where條件、庫表結構都可能會讓外連接等價于一個內連接。mysql能夠識別這點并重寫查詢,讓其可以調整關聯順序。
使用等價變換規則
mysql可以使用等價變化來簡化并規范表達式。它可以合并和減少一些比較,還可以移除恒成立和不成立的判斷。例如,(5=5 and a>5) 被該寫成 a>5,還有(a<b and b=c) and a=5 會該寫成 b>5 and b=c and a=5。
覆蓋索引掃描
當索引中的列包含所有查詢中需要的列時,mysql就可以使用索引返回需要的數據,而無須查詢對應的數據行。
子查詢優化
mysql在某些情況下可以將子查詢轉換成一種效率更高的形式,從而減少多個子查詢多次對數據的訪問。
(未完)
等值傳播
如果兩個列的值通過等式關聯,mysql能夠把其中一列的where條件傳遞到另一列上,例如:
select film.film_id from film inner join film_actor using(film_id)
where film.film_id > 500;
因這里使用using等值關聯,mysql知道where子句不僅適用于film,而且對于film_actor同樣適用。
列表in()的比較
很多數據庫中in()完全等同于多個or條件的子句,但在mysql中,將in()列表中的數據先進行排序,然后通過二分查找方式確定列表中的值是否滿足條件,in列表中有大量取值時,mysql來說處理速度更快。(并不是指mysql 中in列表的值越多查詢越快,是與其他數據庫對比來說相同的in數據量,mysql速度會更快)
提前終止查詢
在發現已經滿足查詢需求的時候,mysql總是能夠立即終止查詢。最典型的是使用limit子句。此外發現一個不成立條件,如..where film_id = -1
,這類查詢在優化階段就已終止。當存儲引擎需要檢索“不同取值”或者判斷存在性的時候,mysql會用此類優化。類似這種“不同值/不存在”的優化一般可用于distinct、not exist() 或者 left join類型的查詢。
優化count()、min()、max()
在B-tree索引中,找某列最小值,只需查詢B-tree索引最左端記錄,最大值查詢B-tree最右端記錄,優化器會將這個表達式作為一個常熟對待。在沒有任何where條件的count(*)查詢,在myisam引擎中可以直接讀取已存儲好的行數信息。