MySQL的EXPLAIN解释器
一、字段基本解讀
+-----+-------------+-------+------+---------------+------------+---------------+-----------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +-----+-------------+-------+------+---------------+------------+---------------+-----------+------+-------+ | 編號 | 查詢類型 | 表 | 類型 | 預測用到的索引 | 實際使用索引 | 實際使用索引長度 | 表之間引用 | 行數 | 額外信息 | +-----+-------------+-------+------+---------------+------------+---------------+-----------+------+-------+一般來說關注type,key,key_len,Extra段進行SQL優化即可。
二、創建例表
#創建用戶表 CREATE TABLE `users`(`id` INT UNSIGNED AUTO_INCREMENT,`name` VARCHAR(8) NOT NULL DEFAULT '',`age` TINYINT NOT NULL DEFAULT 0,`email` VARCHAR(32),`info` VARCHAR(255) COMMENT '無索引',PRIMARY KEY(id) COMMENT '主鍵索引',UNIQUE INDEX ui_email(email) COMMENT '唯一索引',INDEX i_age(age) COMMENT '普通索引',INDEX i_name_age(name,age) COMMENT '復合索引' )ENGINE = INNODB DEFAULT CHARSET = utf8; #插入一條 INSERT INTO `users`(`name`,`age`,`email`,`info`) VALUES('voyager',24,'772532526@qq.com','人生若只如初見'); #創建卡片表,用戶與卡片一對多 CREATE TABLE `card`(`cid` INT UNSIGNED AUTO_INCREMENT,`uid` INT NOT NULL DEFAULT 0,`card` VARCHAR(255) NOT NULL DEFAULT '',PRIMARY KEY(`cid`)#暫不為uid加索引 )ENGINE = InnoDB DEFAULT CHARSET = UTF8; #插入兩條數據 INSERT INTO `card`(`uid`,`card`) VALUES(1,'何事秋風悲畫扇'),(1,'等閑變卻故人心,卻道故人心易變');三、單獨釋義
1. id值
標記分解的sql執行順序,非直觀的從上至下的順序。
id值相同,從上至下執行。
id值不同,從大到小執行。
以此結論,反觀實例,僅觀察 id 和 table 部分。
#SQL1 mysql> EXPLAIN SELECT * FROM users,card WHERE id = uid AND cid = 1; +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | card | const | PRIMARY | PRIMARY | 4 | const | 1 | | | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+SQL1,雖然以cid為條件置于后邊,但因其為主鍵,SQL解釋器知道使用它先篩選更快。
#SQL2 mysql> EXPLAIN SELECT * FROM users,card WHERE uid = 1 AND id = uid ; +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+ | 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 4 | const | 1 | | | 1 | SIMPLE | card | ALL | NULL | NULL | NULL | NULL | 2 | Using where | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------------+SQL2,uid作為條件,卻先篩選users表,原因為:作為條件的字段非索引,則先篩選數據量小的表。
#SQL3 mysql> EXPLAIN SELECT * FROM users WHERE id = (SELECT uid FROM card WHERE cid = 2); +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+ | 1 | PRIMARY | users | const | PRIMARY | PRIMARY | 4 | const | 1 | | | 2 | SUBQUERY | card | const | PRIMARY | PRIMARY | 4 | const | 1 | | +----+-------------+-------+-------+---------------+---------+---------+-------+------+-------+SQL3,加入一個子查詢,id不同,先進行2子查詢,再進行1主查詢。
2.select_type查詢類型
| SIMPLE | 簡單查詢,不包含子查詢、UNION,例SQL1 |
| PRIMARY | 復雜查詢中的主查詢,例SQL3 |
| UBQUERY | 包含子查詢語句的子查詢可能出現,例SQL3 |
| UNION | 聯合查詢,t1 UNION t2 中的t2 |
| UNION RESULT | 聯合結果 |
| DERIVED | 衍生查詢,一般為產生的臨時表 |
舉例一個UNION的
#SQL4 mysql> EXPLAIN SELECT uid FROM card WHERE cid = 1 UNION SELECT uid FROM card WHERE cid = 2; +------+--------------+------------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+--------------+------------+-------+---------------+---------+---------+-------+------+-------+ | 1 | PRIMARY | card | const | PRIMARY | PRIMARY | 4 | const | 1 | | | 2 | UNION | card | const | PRIMARY | PRIMARY | 4 | const | 1 | | | NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | | +------+--------------+------------+-------+---------------+---------+---------+-------+------+-------+還有一些其他的,不詳細列出。
3.table表
一般指查詢的表,對于帶尖括號的,表示select_type + id的指向。例如SQL4,<union1,2>表示id為1和2聯合出來的表。
4.type索引類型
速度null > syetem > const > eq_ref > ref > range > index > all
| null | 甚至不需要訪問索引表,例如主鍵作為條件超過當前表主鍵最大值; |
| system | const的特殊情況,只有一條數據的系統表,或衍生表只有一條數據的主查詢?? |
| const | 使用唯一索引等價查詢,僅能匹配到一條數據 |
| eq_ref | 使用唯一索引作為關聯條件,匹配多條不重復數據 |
| ref | 普通索引等價 |
| range | 檢索給定范圍的索引 , > 、< 、>= 、<=、between and |
| index | 僅查詢索引表 |
| all | 遍歷全表以找到匹配的行 |
例子在后邊。
5.posibble_keys預測用到的索引
寫sql語句時,有些看起來會使用的索引,但實際可能拋棄索引,遍歷全表。
6.keys實際使用的索引
7.key_lengths實際使用的索引長度
一般用于判斷復合索引是否被完全使用。
utf8中一個字符占3個字節。
null占1個字節。
可變長度占2個字節。
SQL5,我本意是想用到聯合索引i_name_age,但是實際上被索引i_age干擾了,這也解釋了possible_keys和keys的不同,而i_age作為tinyint占1個字符,所以key_len值為1。好的,這種時候需要考慮i_age的必要性,要么刪掉此索引,要么強制使用索引。
這里我選擇了先刪除在添加回來,卻發現了一個有意思的事情。
沒問題,name為varchar(8) not null,8 * 3 + 2 + 1 = 27。
然后為了測試把i_age加回來。
哎?發現這回i_age并沒有干擾到復合索引的使用。我猜測與索引建立的順序有關,觀察兩次possible_keys索引順序,并刪除再添加回來i_name_age情況又和SQL5一樣,也驗證了這一點。
注意復合索引與普通索引的關系及創建順序。
8.ref
表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值
9.rows
根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數
10.extra
| Using index | 性能提升,索引覆蓋,此查詢僅查詢索引不需要回表查詢 |
| Using where | 在查找使用索引的情況下,需要回表去查詢所需的數據 |
| Using filesort | 性能消耗大,需要額外一次文件排序 |
| Using temporary | 性能消耗大,用到臨時表,常見于排序和分組查詢 |
| Using join buffer | 連接緩存 |
| Using where; Using index | 查找使用了索引,但是需要的數據都在索引列中能找到,所以不需要回表查詢數據 |
實例
為了更易懂,添加一列money,刪除索引i_name_age和i_age,創建i_money_name_age。
ALTER TABLE users ADD COLUMN money INT NOT NULL DEFAULT 10; ALTER TABLE DROP INDEX i_age; ALTER TABLE DROP INDEX i_name_age; ALTER TABLE users ADD INDEX i_money_name_age(money,name,age);關于order by使用索引
在這里插入圖片描述
疑惑
#SQL9 mysql> EXPLAIN SELECT * FROM users WHERE name = 'voyager' AND age > 12; +----+-------------+-------+-------+-----------------------------+------------+---------+------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+-----------------------------+------------+---------+------+------+-----------------------+ | 1 | SIMPLE | users | range | i_name_age,i_age,i_age_name | i_name_age | 27 | NULL | 2 | Using index condition | +----+-------------+-------+-------+-----------------------------+------------+---------+------+------+-----------------------+ 1 row in setmysql> EXPLAIN SELECT name,age FROM users WHERE name = 'voyager' AND age > 12; +----+-------------+-------+------+-----------------------------+------------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+-----------------------------+------------+---------+-------+------+--------------------------+ | 1 | SIMPLE | users | ref | i_name_age,i_age,i_age_name | i_name_age | 26 | const | 2 | Using where; Using index | +----+-------------+-------+------+-----------------------------+------------+---------+-------+------+--------------------------+ 1 row in setmysql> EXPLAIN SELECT name,age FROM users WHERE name = 'voyager' ORDER BY age; +----+-------------+-------+------+---------------+------------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------------+---------+-------+------+--------------------------+ | 1 | SIMPLE | users | ref | i_name_age | i_name_age | 26 | const | 2 | Using where; Using index | +----+-------------+-------+------+---------------+------------+---------+-------+------+--------------------------+總結
以上是生活随笔為你收集整理的MySQL的EXPLAIN解释器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 诺奖得主、院士,全职加盟国内211大学!
- 下一篇: SQL2005,如何将数据库从一台电脑上