Mysql-Explain(五):輸出列-type

簡介

type 訪問類型排序,顯示查詢使用了何種類型,從最好到最差依次是:system>const>eq_ref>ref>range>index>ALL system 表只有一行記錄,這是const類型的特例,這個平時很少出現
const 表最多有一個匹配行,它將在查詢開始時被讀取。因爲僅有一行記錄匹配,所以這行的列值可被優化器剩餘部分認爲是常數。const表很快,因爲它們只讀取一次!
eq_ref 驅動表和關聯表中的每行進行組合並且僅有一行記錄。這是除了system 和 const 類型之外, 這是最好的聯接類型。當連接使用索引的所有部分時, 索引是主鍵或唯一非 NULL 索引時, 將使用該值
ref 非唯一性索引掃描,返回符合某個索引值的所有記錄,可能會有多條記錄匹配
range 使用一個索引來檢索給定範圍的行,這種範圍索引掃描比全表掃描效率要高
index 使用覆蓋索引
all 全表掃描(full table scan)

演示

  • system:表只有一行記錄,這是const類型的特例

    mysql> explain select * from (select * from student limit 1) s;
    +----+-------------+------------+------------+--------+---------------+------+---------+------+---------+----------+-------+
    | id | select_type | table      | partitions | type   | possible_keys | key  | key_len | ref  | rows    | filtered | Extra |
    +----+-------------+------------+------------+--------+---------------+------+---------+------+---------+----------+-------+
    |  1 | PRIMARY     | <derived2> | NULL       | system | NULL          | NULL | NULL    | NULL |       1 |   100.00 | NULL  |
    |  2 | DERIVED     | student    | NULL       | ALL    | NULL          | NULL | NULL    | NULL | 1800825 |   100.00 | NULL  |
    +----+-------------+------------+------------+--------+---------------+------+---------+------+---------+----------+-------+
    2 rows in set, 1 warning (0.00 sec)
    

    上圖所示from列表子查詢派生出的臨時表<derived2>只有一行記錄,因此外層臨時表的select查詢的type值就是system。其實這種情況在實際的應用中非常少見,上面例子的Sql語句也僅僅是爲了演示這樣寫。

  • const:表最多有一個匹配行,它將在查詢開始時被讀取

    mysql> explain select * from student where id = 1;
    +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
    | id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
    +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | student | NULL       | const | PRIMARY       | PRIMARY | 4       | const |    1 |   100.00 | NULL  |
    +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
    1 row in set, 1 warning (0.00 sec)
    

    where條件是id=常量,所以肯定只有一行記錄被匹配,所以type的值爲const。

    mysql> SELECT * FROM mydb.student where name = 'NnbtPQLjMf';
    +----+------------+------+-----------+----------+
    | id | name       | age  | school_id | major_id |
    +----+------------+------+-----------+----------+
    |  1 | NnbtPQLjMf |   23 |       321 |      314 |
    +----+------------+------+-----------+----------+
    1 row in set (0.60 sec)
    
    mysql> explain select * from student where name = 'NnbtPQLjMf';
    +----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    | id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
    +----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    |  1 | SIMPLE      | student | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1800825 |    10.00 | Using where |
    +----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    

    上圖所示第一條SQL語句查詢結果只有一條記錄,但是下面explain的結果顯示type值卻是all。
    這裏要理解清楚,const是表示mysql優化器在執行語句之前判斷其結果肯定只有一條記錄,因爲id作爲主鍵具有唯一性,id=常量肯定只有一條結果,因此mysql只有讀取到第一條記錄就可以停止查詢直接返回結果。而第二個例子中,name字段既不是主鍵也不是唯一性索引,所以優化器無法判斷其結果的數量(哪怕實際結果只是一條記錄),所以要掃描所有記錄。explain是sql語句執行前的優化和分析,不是執行後的統計!

  • 驅動表和關聯表中的每行進行組合並且僅有一行記錄

    mysql> explain select * from student left join school on student.school_id = school.id;
    +----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+---------+----------+-------+
    | id | select_type | table   | partitions | type   | possible_keys | key     | key_len | ref                    | rows    | filtered | Extra |
    +----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+---------+----------+-------+
    |  1 | SIMPLE      | student | NULL       | ALL    | NULL          | NULL    | NULL    | NULL                   | 1800825 |   100.00 | NULL  |
    |  1 | SIMPLE      | school  | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | mydb.student.school_id |       1 |   100.00 | NULL  |
    +----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+---------+----------+-------+
    2 rows in set, 1 warning (0.02 sec)
    

    以表student爲驅動表關聯查詢表school的時候,表student和表school是一對一關係,因爲student.school_id對於的是school的主鍵(如果是唯一索引也可以),所以一個學生只能關聯一所學校,所以表student的每一行記錄都只能和關聯表school組合成最多一條記錄,所以第二行記錄中type是eq_ref,表示驅動表每行記錄只需要和關聯表組合到第一行記錄即可,你可以理解成student表的每一行記錄在關聯表school都是進行了一次type=const的查詢。eq_ref是一種比較理想的查詢方式,是我們在性能優化中比較原因看到的結果。

  • ref:非唯一性索引掃描,返回符合某個索引值的所有記錄,可能會有多條記錄匹配。

    mysql> ALTER TABLE `mydb`.`student` ADD INDEX `ik_name` USING BTREE (`name`) VISIBLE;
    Query OK, 0 rows affected (20.56 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    

    先創建普通索引ik_name,該索引只有name一個字段。

    mysql> explain select * from student where name = 'NnbtPQLjMf';
    +----+-------------+---------+------------+------+---------------+---------+---------+-------+------+----------+-------+
    | id | select_type | table   | partitions | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
    +----+-------------+---------+------------+------+---------------+---------+---------+-------+------+----------+-------+
    |  1 | SIMPLE      | student | NULL       | ref  | ik_name       | ik_name | 1023    | const |    1 |   100.00 | NULL  |
    +----+-------------+---------+------------+------+---------------+---------+---------+-------+------+----------+-------+
    1 row in set, 1 warning (0.00 sec)
    

    單表查詢,表game的type_id字段是普通索引,所以優化器判斷其可能會有多條匹配的記錄,所以type=ref,會讀取所有匹配的記錄,而不會像const一樣碰到第一行記錄匹配便返回。但是ref是使用索引去查詢記錄,比全表掃描效率還是要高出很多,所以在性能優化分析中ref也是一種比較理想的結果。

  • range:使用一個索引來檢索給定範圍的行,這種範圍索引掃描比全表掃描效率要高。

    mysql> explain select * from student where id between 1 and 10;
    +----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
    | id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | student | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |   10 |   100.00 | Using where |
    +----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.04 sec)
    

    range和ref同樣是使用了所以進行查詢,但是range是範圍刷選,所以效率要比ref要低,但是還是要比全表掃描效率要高,而且範圍查詢在實際應用中是一種很普遍的存在,因此在性能優化分析中,range也是一種比較不錯的結果。

  • index:使用了覆蓋索引

    mysql> explain select id,name from student;
    +----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
    | id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       |
    +----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
    |  1 | SIMPLE      | student | NULL       | index | NULL          | ik_name | 1023    | NULL | 1800825 |   100.00 | Using index |
    +----+-------------+---------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    

    select列表只包含id,name兩個字段,而所以索引ik_name就包含這兩列,所以Mysql只需要掃描索引樹既可以找到所需要的所有值,不需要去掃描表。這是一種非常高效的查詢方式,在性能優化分析中,是我們非常樂意看到的結果。

  • all:全表掃描

    mysql> explain select * from student where age < 25;
    +----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    | id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra       |
    +----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    |  1 | SIMPLE      | student | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 1800825 |    33.33 | Using where |
    +----+-------------+---------+------------+------+---------------+------+---------+------+---------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)
    

    掃描全表,讀取數據。如果表的數據不大的情況,這是一種可以接受的情況,但是數據量增大,尤其上百萬之後,那就要小心了。如果explain返回這個值,那就要考慮是否要優化了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章