(1)概述
    possible_keys,顾名思义,其实就是针对一个表进行查询的时候有哪些潜在可以使用的索引,比如有两个索引,一个KEY(x1,x2,x3),一个是Key(x1,x2,x4),此时要是在where条件里根据x1和x2两个字段进行查询,那么此时明显是上述两个索引都可以使用的,那么到底使用哪个呢?
    此时就需要估算使用两个索引进行查询的成本,看使用哪个索引的成本更低,那么就选择哪个索引,最终选择的索引,就是执行计划里的key字段的值。
    key_len,就是当key里选择使用某个索引后,那个索引里的最大值的长度是多少,这个就是一个参考,大概知道那个索引里的值最大有多长。
    执行计划ref相对关键一些,当查询方式是索引等值匹配的时候,比如const,ref,eq_ref,ref_or_null这些方式,此时执行计划的ref字段就是告诉你:跟索引列等值匹配的是什么?等值匹配一个常量值?还是等值匹配另一个字段的值。

    比如SQL语句: EXPALIN SELECT * FROM t1 WHERE x1=’xxx’,此时的执行计划如下:

    1. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
    2. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    3. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
    4. | 1 | SIMPLE | t1 | NULL | ref | index_x1 | index_x1 | 589 | const | 468 | 100.00 | NULL |
    5. +----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+

    针对t1表的查询,type是ref方式的,也就是基于普通的二级索引进行等值匹配,然后possible_keys只有一个,就是index_x1,针对x1字段建立的索引,而实际使用的也是索引 index_x1,然后key_ken是589,意思就是index_x1这个索引里的x1字段最大值长度就是589字节,不过基本可以肯定这个x1字段是存储字符串的,
    ref:针对二级索引进行等值匹配,那么跟index_x1索引进行等值匹配的是什么?是一个常量还是别的字段?这里的ref是const,意思是说,是使用一个常量值跟index_x1索引的值进行等值匹配的。

    EXPLAIN SELECT * FROM t1 INNER JOIN t2 ON t1.id = t2.id,
    此时执行计划肯定不是const,因为跟t1表字段等值匹配的是另一个表的id字段,此时ref的值就是那个字段的名称,执行计划如下:

    1. +----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
    2. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    3. +----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
    4. | 1 | SIMPLE | t1 | NULL | ALL | PRIMARY | NULL | NULL | NULL | 3457 | 100.00 | NULL |
    5. | 1 | SIMPLE | t2 | NULL | eq_ref | PRIMARY | PRIMARY | 10 | test_db.t1.id | 1 | 100.00 | NULL |
    6. +----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+

    针对t1表作为驱动表执行一个全表扫描,接着针对t1表里每条数据都会去t2表根据t2表的主键执行等值匹配,所以第二个执行计划的type是eq_ref,意思就是被驱动表基于主键进行等值匹配,而且使用的索引是PRIMARY就是使用了t2表的主键。
    ref:到底是谁跟t2表的聚簇索引里的主键值进行等值匹配呢?是常量值嘛?不是,是test_db这个库下的id字段,这里跟t2表的主键进行等值匹配的是t1表的主键id字段,所以ref这里显示的是是如上。
    最后,rows和filtered,这个rows就是使用指定的查询方式,会查出多少条数据,而filtered意思是,在查询方式查询出这批数据里再用上其他不在索引范围里的查询条件,又会过滤出百分之几的数据。

    比如下面的SQL语句:
    EXPLAIN SELECT * FROM t1 WHERE x1>’xxx’ AND x2=’xxx’,他只有一个x1字段建立了索引,x2字段是没有索引的,此时执行计划如下:

    1. +----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
    2. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    3. +----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
    4. | 1 | SIMPLE | t1 | NULL | range | index_x1 | index_x1 | 458 | NULL | 1987 | 13.00 | Using index condition; Using where |
    5. +----+-------------+-------+------------+--------+---------------+---------+---------+-----------------+------+----------+-------+
    1. 上面的执行计划,针对t1表的查询方式是range,也就是基于索引进行范围查询,用的索引是index_x1,也就是x1字段的索引,然后基于 x1>'xxx' 这个条件通过index_x1索引查询出来的数据大概是1987条,接着会针对这1987条数据再基于where条件里的其他条件,也就是x2='xxx'进行过滤,这个filtered13.00,意思是估算基于x2='xxx'条件过滤后的数据大概是13%,也就是最终查询的数据大概时1987*13.00% 258条。