Mysql性能调优工具Explain结合语句讲解
Explain簡稱執(zhí)行計劃,可以模擬SQL語句,來分析查詢語句或者表結(jié)構(gòu)是否有性能瓶頸。
Explain的作用有哪些,可以看到哪些?
可以看到表的讀取順序,數(shù)據(jù)讀取操作的操作類型,哪些索引可以使用,哪些索引被實際應(yīng)用,表之間的引用,每張表有多少行被優(yōu)化器查詢。
準(zhǔn)備工作
DROP TABLE IF EXISTS `t1`; CREATE TABLE `t1` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`other_column` varchar(30) NOT NULL DEFAULT '',`other_column2` varchar(30) NOT NULL DEFAULT '',`other_column3` varchar(30) NOT NULL DEFAULT '',PRIMARY KEY (`id`),KEY `idx` (`other_column`),KEY `u_idx` (`other_column2`,`other_column3`),KEY `u_idx2` (`other_column`,`other_column2`,`other_column3`) ) ENGINE=MyISAM AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of t1 -- ---------------------------- INSERT INTO `t1` VALUES ('1', 'A', 'D', 'L'); INSERT INTO `t1` VALUES ('2', 'B', 'E', 'M'); INSERT INTO `t1` VALUES ('3', 'C', '', 'N'); INSERT INTO `t1` VALUES ('4', '', 'F', ''); INSERT INTO `t1` VALUES ('5', 'F', 'G', 'O'); INSERT INTO `t1` VALUES ('6', 'A', 'H', 'P');-- ---------------------------- -- Table structure for t2 -- ---------------------------- DROP TABLE IF EXISTS `t2`; CREATE TABLE `t2` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`other_column` varchar(30) NOT NULL DEFAULT '',PRIMARY KEY (`id`),KEY `idx` (`other_column`) ) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of t2 -- ---------------------------- INSERT INTO `t2` VALUES ('1', 'C'); INSERT INTO `t2` VALUES ('2', 'D'); INSERT INTO `t2` VALUES ('3', 'E'); INSERT INTO `t2` VALUES ('4', ''); INSERT INTO `t2` VALUES ('5', 'G');-- ---------------------------- -- Table structure for t3 -- ---------------------------- DROP TABLE IF EXISTS `t3`; CREATE TABLE `t3` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT,`other_column` varchar(30) NOT NULL DEFAULT '',PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;-- ---------------------------- -- Records of t3 -- ---------------------------- INSERT INTO `t3` VALUES ('1', 'F'); INSERT INTO `t3` VALUES ('2', 'G'); INSERT INTO `t3` VALUES ('3', 'H'); INSERT INTO `t3` VALUES ('4', ''); INSERT INTO `t3` VALUES ('5', 'I');在使用Explain分析SQL語句之后,會出現(xiàn)這些列,分別是id、type、tabl、select_type、possible_keys、key、key_len、ref、rows、Extra。下面就來拿幾張表和語句全面說明一下。
id :select查詢的一個序列號,包含一組數(shù)字,表示查詢中執(zhí)行select子句或者操作表的順序(有三種情況)。
①id相同表示mysql內(nèi)部的查詢優(yōu)化器執(zhí)行命令,也就是加載表的順序的,從上到下,也就是先后加載了t1,t2,t3,當(dāng)然也有可能順序不是這樣。
②id不同
EXPLAIN SELECT t2.* FROM t2 WHERE id = (SELECT id FROM t1 WHERE id = (SELECT t3.id FROM t3 WHERE t3.other_column = '')); +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | 1 | PRIMARY | t2 | const | PRIMARY | PRIMARY | 4 | const | 1 | | | 2 | SUBQUERY | t1 | const | PRIMARY | PRIMARY | 4 | | 1 | Using index | | 3 | SUBQUERY | t3 | ALL | NULL | NULL | NULL | NULL | 5 | Using where | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+如果是子查詢,id的序號會遞增,id值越大優(yōu)先級越高,越先被執(zhí)行。也就是先執(zhí)行子查詢查t3的表語句,再t1。
③id相同存在,不同也存在。
EXPLAIN SELECT t2.* FROM(SELECT t3.id FROM t3 WHERE t3.other_column = '') s1,t2 WHERE s1.id = t2.id; +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+ | 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | | | 1 | PRIMARY | t2 | const | PRIMARY | PRIMARY | 4 | const | 1 | | | 2 | DERIVED | t3 | ALL | NULL | NULL | NULL | NULL | 5 | Using where | +----+-------------+------------+--------+---------------+---------+---------+-------+------+-------------+分析結(jié)果可看出,先走id最大的2,也就是先走括號里面的查t3表的語句。走完查t3后,順序執(zhí)行,有一個<derived2>,derived是衍生的意思,意思是在執(zhí)行完t3查詢后的s1虛表基礎(chǔ)上,<derived2>中的2,就是id為2的。最后執(zhí)行的查t2表。
select_type(數(shù)據(jù)讀取操作的操作類型)
常見常用的6個值分別是:SIMPLE、PRIMARY、SUBQUERY、DERIVED、UNION、UNION RESULT,主要是告訴開發(fā)者查詢的類型,為了區(qū)別是普通查詢、聯(lián)合查詢、子查詢等復(fù)雜的查詢。
SIMPLE:最簡單的查詢,查詢中不包含子查詢或者UNION。
PRIMARY:查詢中若包含任何復(fù)雜的子部分,最外層查詢則被標(biāo)記為PRIMARY,也就是最后加載的那個。(如上面查詢分析語句)
SUBQUERY:在SELECT或者WHERE列表中包含了子查詢
DERIVED:在FROM列表中包含的子查詢被標(biāo)記為DERIVED(衍生)Mysql會遞歸執(zhí)行這些子查詢,把結(jié)果放在臨時表里(如上面查詢分析語句)
UNION:若第二個SELECT出現(xiàn)在UNION之后,則被標(biāo)記為UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標(biāo)記為DERIVED
UNION RESULT:兩種UNION語句的合并。
table(表示查詢涉及的表或衍生表)
type
反應(yīng)的結(jié)果和mysql是否優(yōu)化過,是否是最佳狀態(tài)息息相關(guān)。
常見的大概7種:
從最好到最差的結(jié)果依次如下:
system > const > eq_ref > ref > range > index > ALL
system:表只有一行記錄(等于系統(tǒng)表),這是const類型的特例,平時不會出現(xiàn),這個也可以忽略不計,且只能用于myisam和memory表。如果是Innodb引擎表,type列在這個情況通常都是all或者index。
const:表示通過索引一次就找到了,const用于比較primary key或者unique索引。因為只匹配一行數(shù)據(jù),所以很快如將主題置于WHERE列表中,Mtsql就能將該查詢轉(zhuǎn)換為一個常量。如下
eq_ref :唯一性索引掃描,對于每個索引鍵,表中只有一條記錄與之匹配。常見于主鍵或者唯一索引掃描
explain select * from t1,t2 where t1.id = t2.id; +----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------+ | 1 | SIMPLE | t1 | ALL | PRIMARY | NULL | NULL | NULL | 5 | | | 1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | test_db.t1.id | 1 | | +----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------+ref:非唯一性索引或非主鍵索引掃描,或者是使用了 最左前綴 規(guī)則索引的查詢,返回匹配某個單獨值得所有行。本質(zhì)上也是一種索引訪問,它返回所有匹配某個單獨值得行,然而,它可能會找到多個符合條件的行,所以他應(yīng)該屬于朝趙和掃描的混合體。
create index idx on t1(other_column); explain select * from t1 where other_column ='A'; +----+-------------+-------+------+---------------+------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+-------+------+-------------+ | 1 | SIMPLE | t1 | ref | idx | idx | 92 | const | 1 | Using where | +----+-------------+-------+------+---------------+------+---------+-------+------+-------------+range:只檢索給定范圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引。一般就是在你的WHERE語句中出現(xiàn)了BETWEEN、<、>、IN等的查詢,這種范圍掃描索引比全表掃描更好,因為它只需要開始于索引的某一點,而結(jié)束語另一點不用掃描全部索引。
explain select * from t1 where id between 2 and 5; +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ | 1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 3 | Using where | +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+index: 表示全索引掃描(full index scan), 和 ALL 類型類似, 只不過 ALL 類型是全表掃描, 而 index 類型則僅僅掃描所有的索引, 而不掃描數(shù)據(jù),比ALL稍微好點,如果表數(shù)據(jù)不小,必須優(yōu)化。
index 類型通常出現(xiàn)在: 所要查詢的數(shù)據(jù)直接在索引樹中就可以獲取到, 而不需要掃描數(shù)據(jù). 當(dāng)是這種情況時, Extra 字段 會顯示 Using index.
ALL: 表示全表掃描, 這個類型的查詢是性能最差的查詢之一. 通常來說, 我們的查詢不應(yīng)該出現(xiàn) ALL 類型的查詢, 因為這樣的查詢在數(shù)據(jù)量大的情況下, 對數(shù)據(jù)庫的性能是巨大的災(zāi)難. 如一個查詢是 ALL 類型查詢, 那么一般來說可以對相應(yīng)的字段添加索引來避免.
下面是一個全表掃描的例子, 可以看到, 在全表掃描時, possible_keys 和 key 字段都是 NULL, 表示沒有使用到索引, 并且 rows 十分巨大, 因此整個查詢效率是十分低下的.
possible_keys 和 key
顯示可能應(yīng)用在這張表中的索引,一個或者多個。查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢實際使用。也就是說possible_keys是推測可能用到哪些索引,而key是實際用到的。這里例子很多,不舉例
key_len
表示索引中使用的字節(jié)數(shù),可通過該列計算查詢中使用的索引的長度。在不損失精確性的情況下,長度越短越好。key_len顯示的值為索引字段的最大可能長度,并非實際使用長度。即key_len是根據(jù)表定義計算而得,不是通過表內(nèi)檢索出的
ref
顯示索引的哪一段被使用了,如果可能的話,是一個常數(shù)。哪些列或常量被用于查找索引列上的值。
rows
根據(jù)表統(tǒng)計信息及搜索選用情況,大致估算出找到所需的記錄所需要讀取的行數(shù),當(dāng)然越小越好
extra(列返回的描述的意義,這里只說常見的)
Using filesort:看到這個的時候,查詢就需要優(yōu)化了。說明Mysql會對數(shù)據(jù)使用一個外部的索引排序,而不是按照表內(nèi)的索引順序進(jìn)行讀取。Mysql中無法利用索引完成的排序操作稱之為文件排序。Mysql需要進(jìn)行額外的步驟來發(fā)現(xiàn)如何對返回的行排序。它根據(jù)連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行。
explain select other_column from t1 where other_column = 'A' order by other_column3; +----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+ | 1 | SIMPLE | t1 | ref | idx | idx | 92 | const | 1 | Using where; Using filesort | +----+-------------+-------+------+---------------+------+---------+-------+------+-----------------------------+優(yōu)化案例:
create index u_idx2 on t1(other_column,other_column2,other_column3); EXPLAIN SELECT other_column FROM t1 WHERE other_column = 'A'ORDER BY other_column2,other_column3; +----+-------------+-------+------+---------------+--------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+--------+---------+-------+------+-------------+ | 1 | SIMPLE | t1 | ref | idx,u_idx2 | u_idx2 | 92 | const | 1 | Using where | +----+-------------+-------+------+---------------+--------+---------+-------+------+-------------+Using index: 列數(shù)據(jù)是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發(fā)生在對表的全部的請求列都是同一個索引的部分的時候。表示相應(yīng)的select操作中使用了覆蓋索引(Coverindex ing),避免訪問了表的數(shù)據(jù)航,效果理想!如果同時出現(xiàn)using where,表示索引被用來執(zhí)行索引鍵值的查找;如果沒有同時出現(xiàn)using where,表示索引用來讀取數(shù)據(jù)而非執(zhí)行查找動作。
覆蓋索引的含義: 就是select的數(shù)據(jù)列只用從索引中就能夠取得,不必讀取數(shù)據(jù)行,Mysql可以利用索引返回select列表中的字段,而不必根據(jù)索引再次讀取數(shù)據(jù)文件,換句話說查詢列要被所建的索引覆蓋。注意的是,如果要使用覆蓋索引,一定要注意select列表中只讀取出需要的列,而不是select *,因為如果將所有字段一起做索引會導(dǎo)致索引文件過大,降低查詢性能。
EXPLAIN SELECT other_column FROM t1 WHERE other_column in ('A','B','C') group by other_column,other_column2; +----+-------------+-------+-------+---------------+--------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+--------+---------+------+------+--------------------------+ | 1 | SIMPLE | t1 | range | idx,u_idx2 | u_idx2 | 92 | NULL | 3 | Using where; Using index | +----+-------------+-------+-------+---------------+--------+---------+------+------+--------------------------+ EXPLAIN SELECT other_column,other_column2,other_column3 FROM t1; +----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+ | 1 | SIMPLE | t1 | index | NULL | u_idx2 | 276 | NULL | 6 | Using index | +----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+Using temporary:看到這個的時候,查詢需要優(yōu)化了。這里,Mysql需要創(chuàng)建一個臨時表來存儲結(jié)果,這通常發(fā)生在對不同的列集進(jìn)行ORDER BY上和GROUP BY上,拖慢與sql查詢。
EXPLAIN SELECT other_column FROM t1 WHERE other_column in ('A','B','C') group by other_column3; +----+-------------+-------+-------+---------------+--------+---------+------+------+-----------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+--------+---------+------+------+-----------------------------------------------------------+ | 1 | SIMPLE | t1 | range | idx,u_idx2 | u_idx2 | 92 | NULL | 3 | Using where; Using index; Using temporary; Using filesort | +----+-------------+-------+-------+---------------+--------+---------+------+------+-----------------------------------------------------------+優(yōu)化案例:
EXPLAIN SELECT other_column FROM t1 WHERE other_column in ('A','B','C') group by other_column,other_column2; +----+-------------+-------+-------+---------------+--------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+--------+---------+------+------+--------------------------+ | 1 | SIMPLE | t1 | range | idx,u_idx2 | u_idx2 | 92 | NULL | 3 | Using where; Using index | +----+-------------+-------+-------+---------------+--------+---------+------+------+--------------------------+Impossible WHERE:查詢語句總是false,不能查詢出任何數(shù)據(jù),相當(dāng)于要求一個人既是男性又是女性...
explain select * from t1 where other_column = 'A' and other_column= 'B'; +----+-------------+-------+------+---------------+------+---------+------+------+------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+------------------+ | 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE | +----+-------------+-------+------+---------------+------+---------+------+------+------------------+延伸案例(執(zhí)行順序分析)
explain select d1.other_column,(select id from t3) d2 from (select id,other_column from t1 where other_column='') d1 union (select other_column,id from t2); +------+--------------+------------+--------+---------------+---------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+--------------+------------+--------+---------------+---------+---------+------+------+-------------+ | 1 | PRIMARY | <derived3> | system | NULL | NULL | NULL | NULL | 1 | | | 3 | DERIVED | t1 | ref | idx,u_idx2 | idx | 92 | | 1 | Using where | | 2 | SUBQUERY | t3 | index | NULL | PRIMARY | 4 | NULL | 5 | Using index | | 4 | UNION | t2 | ALL | NULL | NULL | NULL | NULL | 5 | | | NULL | UNION RESULT | <union1,4> | ALL | NULL | NULL | NULL | NULL | NULL | | +------+--------------+------------+--------+---------------+---------+---------+------+------+-------------+第一行(執(zhí)行順序4):id列為1,表示union里的第一個select,select_type列的primary表示該查詢?yōu)橥鈱硬樵?#xff0c;table列被標(biāo)記為<derived3>,表示查詢結(jié)果來自一個衍生表,其中derived3中的3表示該查詢衍生自第三個select查詢,即id為3的select。select d1.other_column....
第二行(執(zhí)行順序2):id列為3,是整個查詢中的第三個select的一部分。因查詢包含在from中,所以derived。select id,other_column from t1 where other_column=''
第三行(執(zhí)行順序3):selct列表中的子查詢select_type為subquery,為整個查詢中的第二個select。select id from t3
第四行(執(zhí)行順序1):select_type為union,說明第四個select是union里的第二個select,最先執(zhí)行。select other_column,id from t2
第五行(執(zhí)行順序5):代表從union的臨時表中讀取行的階段,table列的<union1,4>表示用第一個和第四個select的結(jié)果進(jìn)行union操作。兩個結(jié)果union操作
總結(jié)
以上是生活随笔為你收集整理的Mysql性能调优工具Explain结合语句讲解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 黑魔法和知识点
- 下一篇: Lync Server 2013 标准版