日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MySQL怎么打开explain_MySQL干货之-利用EXPLAIN优化查询

發布時間:2025/3/20 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL怎么打开explain_MySQL干货之-利用EXPLAIN优化查询 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? 在工作中,經常會碰到一些慢查詢,Explain可以幫我們更詳細的了解MySQL查詢的執行計劃,用法也很簡單Explain 后面跟上SELECT語句即可。執行完之后,會顯示一行有多個列的記錄,可能很多人和我一樣,對EXPLAIN里面字段的含義,并沒有深入的去了解過,處于一知半解的狀態,只知道一些最常見的。

? 下面我根據MySQL官方文檔,查閱了很多資料,再結合我自己的理解,對EXPLAIN的字段和值做了詳細的描述,在總結過程中,也發現了自己的很多知識漏洞,很多時候,總是會想當然的認為,這個就是對的,并沒有嚴密的邏輯驗證,大腦喜歡偷懶,正所謂好記性不如爛筆頭,寫的過程也是對自己知識點掌握程度的批判和考驗。

關于EXPLAIN

? EXPLAIN返回一行記錄,通過Explain可以獲取到很多信息,如:不同表的查詢順序,查詢用了哪些表,能使用哪些索引以及真正用到了哪些索引,用了哪種連接類型,是否有臨時表和文件排序等。這些因素對查詢的效率有直接的相關,想要使查詢更高效,需要對這些條件做一個好的優化。

? EXPLAIN有12個字段,每個字段對查詢優化的權重比不一樣,也就是說并不是所有字段都很重要。type,key,Extra字段相對其它字段來說,對查詢效率的影響更大,優化查詢的時候,先把注意力放到這些字段會比其它字段來得更加直接有效,下面開始具體內容。

EXPLAIN語法

以user_info表為例:

explain select * from `user_info` where uid = 5

結果:

id

select_type

table

partitions

type

possible_keys

key

key_len

ref

rows

filtered

Extra

1

SIMPLE

user_info

NULL

const

PRIMARY

PRIMARY

8

const

1

100.00

NULL

EXPLAIN字段說明

注: 標注星號的字段為重點

id:

SELECT語句的標識符,代表SELECT查詢在整個查詢中的序號。這個值也可能為NULL,如果這一行是UNION的結果。

select_type:

SELECT查詢的類型,該類型的值有11種類型。例如,示例中的值為SIMPLE,表示該查詢是一個簡單的查詢(即:沒有子查詢和UNION)。

table:

大多數情況下表示輸出行所引用的表名,它也可能是下列值之一:

partitions:

只對分區表有意義。意思是查詢所匹配到的分區,如果該表為非分區表,則它的值為NULL。

*type:

查詢的join類型,注意單表查詢也被當做join的特例,并不一定要兩張表。連接類型詳情下面會詳細介紹。

possible_key:

possible_key列是指,在查詢中能夠被MySQL用到的索引,但在實際情況中,不一定會被全部用到,這取決于MySQL優化器的選擇,假設possible_key有A,B,C,3個索引,優化器經過分析認為A索引不需要用,那么實際執行的時候只會用到B,C索引。實際應用中,該列經常幫我們對SQL查詢進行優化,如果它的值為NULL,說明沒有能被用到的索引,這種情況下,需要調整SQL語句和優化表的索引。

*key:

查詢中實際用到的索引,要注意,該列的值可能包含possible_key列中沒有出現的索引,當查詢滿足覆蓋索引的條件時,possible_keys列為NULL,索引僅在key列顯示,MySQL只需要掃描索引樹,不用到實際的數據行檢索即可得到結果,查詢會更高效,Extra列顯示USING INDEX,則證明使用了覆蓋索引。 也可以通過FORCE INDEX,USE INDEX或IGNORE INDEX來強制使用或忽略possible_key列中的索引。

覆蓋索引概念:

如果索引包含所有滿足查詢需要的數據的索引成為覆蓋索引(Covering Index)。

假設有一個user表,假設索引A包含了col1,col2,col3三個字段,criteria為標準條件。

Query 1:

select * from user where criteria

Query 1使用了索引查詢,獲取到數據行的主鍵,但是仍然需要根據主鍵值掃描實際的數據行。

Query 2:

select `col1`,`col2` where criteria

Query 2中,索引A已經包含了它需的字段,也就是說Query 2不用再去實際的數據行獲取數據了,只要掃描完索引樹就行了,這樣就省了一個步驟,索引樹往往比實際的數據表小,所以效率很高,這就是覆蓋索引。

key_len:

實際用到的索引字段長度,越短越好。

ref:

ref列顯示哪個列或者常數和索引比較篩選出結果。

rows:

rows列表示MySQL認為執行查詢必須檢查的行數,對Innodb表來說,這是一個預估值,可能并不是確切的值。

filtered:

? filtered的意思是,首先MySQL利用索引,例如,用range范圍掃描出符合的行,如果掃描符合條件的估計值是100行,rows顯示估計的值就是100,這一步是存儲引擎根據索引篩選后的值,然后在Server層根據其余的WHERE條件過濾。

? 被過濾器過之后,符合條件的還剩下20行,也就是剩下20%,20%就是filtered中的值。很顯然,直接在存儲引擎層篩選出20行比先篩選出100行再過濾要更好,通常情況下,filtered的值越大可能意味著索引越好。

? 另一方面看,你也可以完全忽略filtered,因為這個值在大多數情況下只是一個不準確的估計,應該把注意力放到優化其它更有用的字段上,尤其是type,key,Extra。例如:盡量避免filesort排序,使用索引排序。或者有一個更好的type值,對性能的提升是非常巨大的,這種情況,即使filtered的值低也沒關系。假設一個查詢A, type=all,filtered=0.1%。那么首要先關注type字段,可通過添加索引來優化,可以先不管filtered。

? 所以對這個值不需要太認真,即使100%也不意味著索引一定好,反過來也不一定說明索引差,type比它更能說明索引的好壞。

*Extra:

這個列包含Mysql解決查詢的詳細信息,詳情見下方。

EXPLAIN字段值說明:

select_type:

select_type 值

描述

SIMPLE

簡單的SELECT查詢(沒有UNION和子查詢)

PRIMARY

一個需要union操作或者含有子查詢的select,位于最外層的單位查詢的select_type即為primary。且只有一個

UNION

UNION連接的select查詢,除了第一個表外,第二個及以后的表select_type都是union

DEPENDENT UNION

與union一樣,出現在union 或union all語句中,但是這個查詢要受到外部查詢的影響

UNION RESULT

UNION之后的結果集

SUBQUERY

除了from字句中包含的子查詢外,其他地方出現的子查詢都可能是subquery

DEPENDENT SUBQUERY

與dependent union類似,表示這個subquery的查詢要受到外部表查詢的影響

DERIVED

FROM字句中出現的子查詢。語法:SELECT ... FROM (subquery) [AS] tbl_name ...

MATERIALIZED

被物化的子查詢

UNCACHEABLE SUBQUERY

對于外層的主表,子查詢不可被物化,每次都需要計算(耗時操作)

UNCACHEABLE UNION

UNION操作中,內層的不可被物化的子查詢(類似于UNCACHEABLE SUBQUERY)

通過 **物化 ** 優化子查詢的原理:

? 優化器使用物化的方式能讓子查詢更高效的執行,類似緩存技術,把第一次查詢的結果存起來,避免多次的耗時操作,同時也有它自身的限制,不是所有子查詢都能被物化的。物化技術把子查詢產生的結果放在一個臨時表中,如果數據量小的話,通常是在內存中完成,數據大的時候就降級到磁盤進行,速度也會慢很多。首先,MySQL得到子查詢的結果,然后把結果放到臨時表中,在隨后的任何時間,當需要這個結果時,MySQ就再次引用這個臨時表,不需要再執行計算了。優化器可能會使用哈希索引(復雜度為O(1),很快)來快速且低成本的查找表,這個索引是唯一的,避免了重復,能使表更小。

SELECT * FROM t1

WHERE t1.a IN (SELECT t2.b FROM t2 WHERE where_condition);

type(連接類型):

system

當表只有一行數據的時候,這是const連接類型的特例。

const

表中最多只有一行匹配,在查詢開始時被讀取。因為只有一行,該行中列的值可以被優化器的其余部分視為常量。const表非常快,因為他們僅被讀取一次。將PRIMARY KEY 或 UNIQUE INDEX索引和常量值比較時,會使用const。例如:

SELECT * FROM tbl_name WHERE primary_key=1;

SELECT * FROM tbl_name

WHERE primary_key_part1=1 AND primary_key_part2=2;

eq_ref

假設A JOIN B,B表讀取A表的各個行組合的一行時,通過B表的PRIMARY KEY或UNIQUE NOT NULL索引列連接時,優化器會使用eq_ref類型,這是除了system和const之外最快的JOIN類型。

舉例說明:

表tableA,有(id,text)字段,id為PRIMARY KEY,A表數據為:

id

text

1

HELLO

2

THANK

表tableB有(id,text)字段,id為PRIMARY KEY,B表數據為:

id

text

1

WORLD

2

YOU

現在通過JOIN將兩個表關聯起來

SELECT A.text,B.text

FROM tableA AS A,tableB as B

WHERE A.id=B.id

這個連表查詢是非常快的,因為在A表中掃描的每一行,在B表中也僅一行滿足條件。

ref

? A JOIN C時,A表中的每一行不是唯一的,對單表查詢也一樣,有多個滿足條件的行,查詢的KEY是單個索引或復合索引的最左前綴(不是唯一索引和主鍵),也就是說C表的id是一個非唯一索引。這種情況下,優化器會使用ref優化,如果只有少部分行(rows)滿足條件,這個連接類型(join type)是很好的。ref用于索引的比較操作,注意:僅對于=,<=> 操作有效,對于>,

舉例說明:

現在有tableC,id為索引,不唯一。數據為:

id (非唯一索引)

text

1

HANGZHOU

1

SHANGHAI

現在通過LEFT JOIN將A和C關聯起來:

SELECT A.text,C.text

FROM `tableA` AS A

LEFT JOIN `tableC` AS C ON A.id=C.id

這個JOIN不像之前的那么快,因為在表A中掃描的每一行,在表C中可能有很多行滿足條件,C的id不是唯一索引。

fulltext

使用了全文索引,Innodb不支持全文索引。

ref_or_null

如果一個查詢的WHERE子句中包含colA IS NULL的條件,但是colA已經被聲明為NOT NULL,此時優化器會使用ref_or_null類型。

SELECT * FROM ref_table

WHERE key_column=expr OR key_column IS NULL;

index_merge

? 在MYSQL5.0之前是沒有索引合并功能的,假設A表有3個單獨的索引col1 ,col2,col3,然后執行如下SQL:

SELECT * FROM A WHERE col1=1 AND col2=2 AND col3=3

實際查詢中只有一個索引能被用到,這種情況,只能通過建立復合索引(col1,col2,col3)才能在索引中用到所有字段。

? 5.0之后有了索引合并,當檢索數據行時出現多個范圍掃描條件時,在滿足索引合并前提條件時(單個索引覆蓋WHERE條件的字段),MySQL優化器可能會使用索引合并(不一定),首先分別對多個索引進行掃描,然后合并來自單個表的掃描結果,它不能合并多個表的掃描結果,合并的方式有3種:

unions:索引取并集

intersections:索引取交集

Sort-Union:先對取出的數據按主鍵排序,再取并集

索引合并條件:

WHERE子句中的范圍條件,WHERE中出現字段必須被索引覆蓋,如果colA沒添加索引,則只會對colB和colC進行索引合并,Extra字段顯示Using intersect(colB,colC);,type為index_merge,則說明用到了索引合并。

WHERE colA = const1 AND colB = const2 AND colC = const3

Innodb表中的主鍵的任何范圍條件,>,等。

SELECT * FROM innodb_table

WHERE primary_key < 10 AND key_col1 = 20;

? 滿足了條件,MYSQL會選擇索引行數最少的字段對索引結果進行合并,最終使用哪個索引字段來合并也不一定,也可能不使用合并,這取決于優化器,如果優化器認為沒必要使用索引合并優化,就會使用其它優化,也許會選擇type 為range或更高效的ref的優化。

? 當優化器決定使用索引合并優化,如果WHERE條件用AND連接,優化器會使用INTERSECTIONS合并算法,對多個索引掃描的結果取交集。如果用OR連接,優化器會選擇UNIONS或SORT-UNIONS合并算法,對多個索引掃描的結果取合集,SORT-UNIONS和UNIONS的主要區別是,前者在掃描完數據時,需要先對數據按主鍵排序,再取它們的合集。

? 在WHERE子句中使用AND時,使用復合索引比索引合并更高效,因為復合索引只用一個索引篩選,沒有匹配合并的過程,這個過程節省了很多時間。

? 在使用OR時,復合索引是不起作用的,這種情況下,使用UNIONS索引合并效果更好。如果不想使用某種索引合并,也可以選擇關閉。可通過optimzer_switch系統變量查看各個索引合并的開啟狀況。如下:

SELECT @@optimizer_switch

索引合并算法的默認都是開啟的,可以通過關閉某個合并算法。例如:

SET optimizer_switch = 'index_merge_intersection=off'

unique_subquery

這種類型是eq_ref類型在子查詢中的替代類型。例如

SELECT * FROM A WHERE

value IN (SELECT id FROM B WHERE some_expr)

B表中的id在A表中有唯一對應的記錄。

range

? 在WHERE子句中,執行>,,=,BETWEEN,IN() 等操作時,MySQL可能會(不一定)使用range類型,Explain中key列的值就是實際用到的索引,key_len是它們中最長的索引的長度。如果優化器認為使用索引篩選沒有全表掃描來得及,例如:條件篩選后的行占全表的50%以上,即使有索引可用,優化器也會選擇全表掃描,即type=ALL。

? 為什么呢?解釋這個問題之前,需要先了解幾個概念。對Innodb表來說,每個表都有一個聚簇索引,InnoDB的聚簇索引實際上在同一個結構中保存了B-Tree索引和數據行信息。因為無法把數據行存放在兩個不同的地方,所以一個表只能有一個聚簇索引。二級索引存儲的是記錄的主鍵,而不是數據存儲的地址,索引數據和存儲數據是分離的,唯一索引、普通索引、前綴索引等都是二級索引。實際上,InnoDB在查詢任何數據時,最后都是通過主鍵來查詢的。首先我們根據索引條件在索引樹上掃描出對應的主鍵值。然后根據這個值去聚簇索引總超找到對應的行(如果是覆蓋索引則省略這一步)。

? 在某些情況下,索引條件掃描出的數據行非常大,可能占了全表的50%,此時再根據主鍵找到對應的數據塊是不劃算。主鍵的BTree查找屬于文件的隨機搜索,但是如果隨機搜索文件數據的目的是為了查找一半的數據,這并不是最優化的,只要對數據文件進行大量的順序讀寫要更快,這種情況下,索引會被忽略。

index

? index類型和ALL類型幾乎相同。有兩種情況:

若SELECT中列全部被索引覆蓋,所需要的數據可以直接在索引中讀取,MySQL只需對索引樹進行掃描,這通常比掃描實際數據行要快,因為索引樹通常比數據表更小,這種情況下,Extran的值會顯示USING INDEX。

使用索引中讀取的主鍵值,按索引順序對全表進行掃描,此時Extra中沒有USING INDEX。

ALL

對表的每一行進行掃描,這是最糟糕的情況。一般,你可以通過添加索引來避免這種情況發生。

Extra列值的含義:

? Extra列包含了MySQL處理查詢的一些額外信息,下面的列出了Extra中可能出現的值,如果你想讓查詢盡可能的快,應該注意下Extra字段中是否出現了using filesort 和using temporary。下面只列除了在實際應用中經常會出現,相對比較重要的一部分,若描述的不夠詳細,可查看MySQL官方文檔。

const row not found

SELECT * FROM A

如果A表為空,則會出現改值。

DISTINCT

mysql在尋找不同的值,當它找到第一個匹配的行之后,就停止搜索更多的行了。例子:

no matching row in const table

用唯一索引或者主鍵查詢時,沒有匹配到的數據。

Not exists

MySQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行,就不再搜索了,。例如:

SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id

WHERE t2.id IS NULL;

Using filesort

? 這個值表示,MySQL必須對檢索到的結果進行額外的排序。排序是按照連接類型遍歷所有行并存儲排序鍵和指向行的指針,以匹配滿足where子句條件的所有行,然后對鍵進行排序,并按排序順序檢索行。根據不同情況,MySQL會選擇不同的排序算法,在數據比較小的時候,MySQL會利用排序緩沖區作為優先級隊列將結果在內存中排序,否則只能通過合并文件的方式合并,那會慢很多,排序緩沖區的大小取決于sort_buffer_size變量的大小。

? 總之,當看到filesort的時候就應該引起重視,通過優化索引來避免額外的文件排序,這對性能影響是很大的。

Using index

單個索引覆蓋了SELECT的所有列(即:覆蓋索引),不需要對實際的數據行進行掃描。

Using index condition

? Index Condition Pushdown (ICP)是MySQL 5.6 版本中的新特性,是一種在存儲引擎層使用索引過濾數據的一種優化方式。當關閉ICP時,index 僅僅是data access 的一種訪問方式,存儲引擎通過索引回表獲取的數據會傳遞到MySQL Server 層進行where條件過濾。

? 當打開ICP時,如果部分where條件能使用索引中的字段,MySQL Server 會把這部分下推到引擎層,可以利用index過濾的where條件在存儲引擎層進行數據過濾,而非將所有通過index access的結果傳遞到MySQL server層進行where過濾.

優化效果:ICP能減少引擎層訪問基表的次數和MySQL Server 訪問存儲引擎的次數,減少io次數,提高查詢語句性能。

Using index for group-by

和USING INDEX很相似,區別是,當查詢語句中含有DISTINCT和GROUP BY操作時,僅需訪問索引樹,不需要訪問實際的表時,使用該優化。

``Using sort_union(...),Using union(...),Using intersect(...)`

當查詢產生索引合并時會顯示該值,type為index_merge。

Using temporary

為了處理查詢,MySQL必須建立一個臨時表才能產生結果。典型的情況是,在使用GROUP BY和ORDER BY子句時,兩者使用了不同的列會導致產生臨時表。

Using where

using where 是指使用WHERE或ON子句,MySQL Server層收到存儲引擎返回的結果時,需要對結果再次過濾,不需要返回所有結果,注意LIMIT不算限制條款。如果沒有用到索引using where只是說明,使用了顧慮條件過濾。

參考

總結

以上是生活随笔為你收集整理的MySQL怎么打开explain_MySQL干货之-利用EXPLAIN优化查询的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。