mysql如何explan优化sql_《MySQL数据库》MySQL 优化SQL(explain)
前言
如果要寫出優質的SQL語句,就需要了解MySQL的存儲原理。MySQL是如何分析SQL,如何利用索引查詢。
Explain 關鍵字
explain select * from ic_base;? ? ? ? ? ? ? ? ? --查看SQL的執行情況
id:執行編號,標識Select的執行順序,存在子查詢等負責查詢的時候用來標識執行的優先順序。
select_type:?select查詢語句的類型(simple,primary,subquery,derived,union,union result,dependent union,dependent subquery)。
>?simple : 簡單SQL
>?primary?: 包含union或者子查詢,最外層的部分標記為primary
>?subquery?: 非相關子查詢(子查詢和主表之間有關聯關系)
>?derived?:?派生表——該臨時表是從子查詢派生出來的,位于form中的子查詢
>?union?: 包含union 或者 union all 的查詢
>?union result?: MySQL建立的臨時表需要去掉重復數據
>?dependent union?:?顧名思義,首先需要滿足UNION的條件,及UNION中第二個以及后面的SELECT語句,同時該語句依賴外部的查詢
>?dependent subquery?:?相關子查詢(子查詢和主表之間有關聯關系)
> materialized :當查詢優化器在執行包含子查詢的語句時,選擇將子查詢物化之后與外層查詢進行連接查詢。
table:訪問的表名
partitions:分區信息
type:?訪問類型(system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL),innodb中不存在system.一般來說,得保證查詢至少達到range級別,最好能達到ref。
>?system?:?這是const連接類型的一種特例,表只有一行數據
> const?: 主鍵索引僅有一行滿足條件
> eq_ref?:?被驅動表和驅動表通過驅動表的主鍵關聯。
> ref?: 輔助索引訪問,等值匹配或者常量匹配。
> ref_or_null?: 索引訪問,等值匹配或者常量匹配,存在null值。
> index_merge?:?合并索引,有多個索引可以選擇。
> unique_subquery?:?子查詢使用唯一索引
> index_subquery?:?子查詢使用索引
> range?:?范圍掃描,一個有限制的索引掃描。key列顯示使用了哪個索引。當使用=、<>、>、>=、、BETWEEN 和IN 操作符,用常量比較關鍵字列時。
> index?:?和全表掃描一樣。只是掃描表的時候按照索引次序進行而不是行。主要優點就是避免了排序, 但是開銷仍然非常大。
> ALL :?全表掃描
possible_keys:顯示能夠使用的索引
key:使用的索引
key_len:使用的索引長度(使用的索引字段長度之和,字段沒有設置非空,需要加1,varchar 字段還要加2)
ref:關聯列或者常數
rows:數據行數(來自統計信息)
filtered:過濾百分比,可能滿足條數/總條數
Extra:MySQL的補充額外信息
> no tables used : 沒有額外信息
> Using where : 當我們使用全表掃描來執行對某個表的查詢,并且該語句的WHERE子句中有針對該表的搜索條件
> Using index: 當我們的查詢列表以及搜索條件中只包含屬于某個索引的列,也就是在可以使用索引覆蓋的情況
> Impossible where: 查詢語句的WHERE子句永遠為FALSE時將會提示該額外信息
> Using index condition:?有些搜索條件中雖然出現了索引列,但卻不能使用到索引
> no matching min/max row:?當查詢列表處有MIN或者MAX聚集函數,但是并沒有符合WHERE子句中的搜索條件的記錄
> Using join buffer(block nested loop) : 在連接查詢執行過程中,當被驅動表不能有效的利用索引加快訪問速度,MySQL一般會為其分配一塊名叫join
buffer的內存塊來加快查詢速度
> Using filesort : 很多情況下排序操作無法使用到索引,只能在內存中(記錄較少的時候)或者磁盤中(記錄較多的時候)進行排序,這種在內存中或者磁盤上進行排序的方式統稱為文件排序(英文名:filesort)
> Using temporary : 在許多查詢的執行過程中,MySQL可能會借助臨時表來完成一些功能,比如去重、排序之類的,比如我們在執行許多包含DISTINCT、GROUP BY、UNION等子句的查詢過程中,如果不能有效利用索引來完成查詢,MySQL很有可能尋求通過建立內部的臨時表來執行查詢
> start temporary , end temporary: 查詢優化器會優先嘗試將IN子查詢轉換成semi-join,而semi-join又有好多種執行策略,當執行策略為DuplicateWeedout時,也就是通過建立臨時表來實現為外層查詢中的記錄進行去重操作時,驅動表查詢執行計劃的Extra列將顯示Start temporary提示,被驅動表查詢執行計劃的Extra列將顯示End temporary提示
> FirstMatch(表名) : 在將In子查詢轉為semi-join的去重的方式(找到一條就返回)
查詢優化器
set optimizer_trace="enabled=on";? ? ? ?--打開查詢優化器
---------------需要執行的SQL(可以使用explain)-------------------------
select * from information_schema.OPTIMIZER_TRACE? ? ?--查詢優化器的執行結果
set optimizer_trace="enabled=off";? ? ? ?--關閉查詢優化器
查詢優化器查詢的結果
query: 對應SQL.
trace :優化過程(里面有行估算,走索引,最左前綴等一些計算成本的過程,然后MySQL自動選擇一種最優方式)。
成本計算公式:全表掃描的公式: 主鍵索引頁數*1 + 行數*0.2 = Data_length/16K + Rows*0.2 ;? ? 主鍵索引頁數,行數來自統計信息, 其他數據為MySQL固定常量
由于MySQL的成本計算也是估算(99%是靠譜的),但是當遇到很復雜的SQL,或者統計信息與實際情況差距太大的時候,會導致MySQL的優化過程出現問題。
這個時候我們需要干擾MySQL的執行計劃,強制走我們需要的索引或者更新統計信息。
索引失效
1. 隱式轉換,不走索引
表ic_website的url 創建了一個普通索引,并且該字段是varchar類型,會出現一下情況:
explain select * from ic_website where url = '123';? ? --? 索引有效
explain select * from ic_website where url = 123;? ? --? 索引失效
2. <>,not in 不走普通索引,主鍵索引還是可以走索引。
explain select * from ic_website where url <> '123';
3. 左邊有% 的不走索引
explain select * from ic_website where url like '%123';
實戰
一、ANALYZE TABLE? ic_base;? ?-- 重新收集ic_base 的統計信息,保證MySQL優化器計算準確。 查看統計信息是否被更新:select * from mysql.innodb_table_stats;
select * from mysql.innodb_index_stats;
二、hints
USE INDEX:限制索引的使用范圍,們在數據表里建立了很多索引,當MySQL對索引進行選擇 時,這些索引都在考慮的范圍內。但有時我們希望MySQL只考慮幾個索引,而不是全部的索引, 這就需要用到USE INDEX對查詢語句進行設置。
IGNORE INDEX :限制不使用索引的范圍
FORCE INDEX:我們希望MySQL必須要使用某一個索引(由于 MySQL在查詢時只能使用一個索 引,因此只能強迫MySQL使用一個索引)。這就需要使用FORCE INDEX來完成這個功能。
hints 語法:
SELECT * FROM table1 USE|IGNORE|FORCE INDEX (col1_index,col2_index) WHERE col1=1 ANDcol2=2 AND col3=3;
三、straight_join? ?-- 強制改成左邊為驅動表
select t1.* fromTable1 t1 STRAIGHT_JOIN Table2 t2on t1.CommonID = t2.CommonID where t1.FilterID = 1
總結
SQL優化伴隨開發的全部過程,隨著時間和業務的推移,一些SQL的性能跟不上了,需要重新整理和優化。
筆者遇到過好幾千行的SQL(union,子查詢,嵌套查詢,函數,分組,排序)幾乎用了SQL的全部特性,優化這類SQL第一要熟悉SQL的作用,第二點要將這類SQL拆小,先找到慢的地方,然后再考慮優化。優化SQL是一個需要耐心的活,平時一定要注意SQL寫法,盡量避免一些糟糕的寫法,減少后期的維護。
總結
以上是生活随笔為你收集整理的mysql如何explan优化sql_《MySQL数据库》MySQL 优化SQL(explain)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql字段说明_mysql 字段类型
- 下一篇: 运行mysql数据库的命令_mysql