MySQL_explain關鍵字分析查詢語句
通過對查詢語句的分析,可以瞭解查詢語句的執行情況。MySQL中,可以使用EXPLAIN語句和DESCRIBE語句來分析查詢語句。
EXPLAIN語句的基本語法如下:(DESCRIBE語法一致,DESCRIBE可簡寫為DESC)
EXPLAIN Select 語句;
eg:explain SELECT * FROM `user` where name = 'name6'; 結果如下:
explain結果值及其含義:
引數值 |
含義 |
id |
表示SELECT語句的編號; |
select_type |
表示SELECT語句的型別。 該引數有幾個常用的取值: SIMPLE :表示簡單查詢,其中不包括連線查詢和子查詢; PRIMARY:表示主查詢,或者是最外層的查詢語句; UNION :表示連線查詢的第二個或後面的查詢語句; |
table |
表示查詢的表; |
type |
表示表的連線型別。該引數有幾個常用的取值: const :表示表中有多條記錄,但只從表中查詢一條記錄; eq_ref :表示多表連線時,後面的表使用了UNIQUE或者PRIMARY KEY; ref :表示多表查詢時,後面的表使用了普通索引; unique_ subquery:表示子查詢中使用了UNIQUE或者PRIMARY KEY; index_ subquery:表示子查詢中使用了普通索引; range :表示查詢語句中給出了查詢範圍; index :表示對錶中的索引進行了完整的掃描; all :表示此次查詢進行了全表掃描; ----------- 該條SQL需要優化; |
possible_keys |
表示查詢中可能使用的索引; 如果備選的數量大於3那說明已經太多了,因為太多會導致選擇索引而損耗效能, 所以建表時欄位最好精簡,同時也要建立聯合索引,避免無效的單列索引; |
key |
表示查詢使用到的索引; |
key_len |
表示索引欄位的一長度; |
ref |
表示使用哪個列或常數與索引一起來查詢記錄; |
rows |
表示查詢的行數; 試圖分析所有存在於累計結果集中的行數,雖然只是一個估值,卻也足以反映 出SQL執行所需要掃描的行數,因此這個值越小越好; |
Extra |
表示查詢過程的附件資訊。 |
通過explain可以得到如下結論:
①使用索引比未使用索引,掃描的行數更少查詢速度更快;
②在查詢語句中使用LIKE關鍵字進行查詢時,如果匹配字串的第一個字元為“%”時,索引不會被使用。如果“%”不是在第一個位置,索引就會被使用。
③使用多列索引時,只有查詢條件中使用了該索引中的第一個索引欄位時,索引才會被使用。
注:create index index_age_sex on user(age,sex); age為第一個索引;
④查詢語句只有OR關鍵字時,如果OR前後的兩個條件列都是索引時,查詢中將使用索引。只要OR前後有一個條件的列不是索引,那麼查詢中將不使用索引。
注: 1:where 語句裡面如果帶有or條件, myisam表能用到索引,innodb不行;2:必須所有的or條件都必須是獨立索引;
以上結論來自如下測試:
user表: 獨立索引:id、name 聯合索引:age && sex |
user_noindex表: 無任何索引列; |
CREATE TABLE `user` ( `id` int(11) NOT NULL, `name` varchar(30) NOT NULL, `age` int(11) NOT NULL, `sex` tinyint(4) NOT NULL, `isDeleted` tinyint(4) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `id_unidx` (`id`) USING BTREE, UNIQUE KEY `name_unidx` (`name`) USING BTREE, KEY `index_age_sex` (`age`,`sex`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; |
CREATE TABLE `user_noindex` ( `id` int(11) NOT NULL, `name` varchar(30) NOT NULL, `age` int(11) DEFAULT NULL, `sex` tinyint(4) DEFAULT NULL, `isDeleted` tinyint(4) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
【1】索引對查詢的影響-----加索引和不加索引的對比-----使用索引掃描的更少查詢更快
語句1:explain SELECT * FROM `user` where name = 'name6';
語句2:explain SELECT * FROM `user_noindex` where name = 'name6';
結果集 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
語句1 | 1 | SIMPLE | user | const | name_unidx | name_unidx | 32 | const | 1 | null |
語句2 | 1 | SIMPLE | user_noindex | ALL | null | null | null | null | 10 | Using where |
【2】索引對查詢的影響-----加索引----使用和未使用索引的對比-----在查詢語句中使用LIKE關鍵字進行查詢時,如果匹配字串的第一個字元為“%”時,索引不會被使用。如果“%”不是在第一個位置,索引就會被使用。
語句1:explain SELECT * FROM `user` where name like '%name6';
語句2:explain SELECT * FROM `user` where name like '%name6%';
語句3:explain SELECT * FROM `user` where name like 'name6%';
結果集 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
語句1 | 1 | SIMPLE | user | ALL | null | null | null | null | 10 | Using where |
語句2 | 1 | SIMPLE | user | ALL | null | null | null | null | 10 | Using where |
語句3 | 1 | SIMPLE | user | range | name_unidx | name_unidx | 32 | const | 1 | null |
【3】索引對查詢的影響-----加索引----使用和未使用索引的對比-----多列索引是在表的多個欄位建立一個索引。只有查詢條件中使用了這個欄位中的第一個欄位時,索引才會被使用。
語句1:explain SELECT * FROM `user` where age = '19';
語句2:explain SELECT * FROM `user` where sex = '1';
語句3:explain SELECT * FROM `user` where sex = '1' and age = '19';
結果集 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
語句1 | 1 | SIMPLE | user | ref | index_age_sex | index_age_sex | 4 | const | 1 | null |
語句2 | 1 | SIMPLE | user | ALL | null | null | null | null | 10 | Using where |
語句3 | 1 | SIMPLE | user | ref | index_age_sex | index_age_sex | 5 | const,const | 1 | null |
【4】索引對查詢的影響-----加索引----使用和未使用索引的對比-----查詢語句只有OR關鍵字時,如果OR前後的兩個條件的列都是索引時,查詢中將使用索引。如果OR前後有一個條件的列不是索引,那麼查詢中將不使用索引。
語句1:explain SELECT * FROM `user` where (age = '19' OR isDeleted = '0');
語句2:explain SELECT * FROM `user` where (sex = '1' OR age = '19'); -- 聯合索引
語句3:explain SELECT * FROM `user` where (name = 'name1' OR id = '1'); -- 獨立索引
-- alter table user engine = innodb;
結果集 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
語句1 | 1 | SIMPLE | user | ALL | index_age_sex | null | null | null | 10 | Using where |
語句2 | 1 | SIMPLE | user | ALL | index_age_sex | null | null | null | 10 | Using where |
語句3 | 1 | SIMPLE | user | ref | PRIMARY,id_unidx,name_unidx | index_age_sex | null | null | 10 | Using where |
-- alter table user engine = myisam;
結果集 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
語句1 | 1 | SIMPLE | user | ALL | index_age_sex | null | null | null | 10 | Using where |
語句2 | 1 | SIMPLE | user | ALL | index_age_sex | null | null | null | 10 | Using where |
語句3 | 1 | SIMPLE | user | index_merge | PRIMARY, id_unidx, name_unidx |
name_unidx, PRIMARY |
32,4 | null | 2 | Using union (name_unidx,PRIMARY); Using where |
很多查詢中需要使用子查詢。子查詢可以使查詢語句很靈活,但子查詢的執行效率不高。子查詢時,MySQL需要為內層查詢語句的查詢結果建立一個臨時表。然後外層查詢語句在臨時表中查詢記錄。查詢完畢後,MySQL需要撤銷這些臨時表。因此,子查詢的速度會受到一定的影響。如果查詢的資料量比較大,這種影響就會隨之增大。在MySQL中可以使用連線查詢來替代子查詢。連線查詢不需要建立臨時表,其速度比子查詢要快。