Extrah是为了提供一些附加的信息 , 可以通过该信息来判断Mysql到底要如何执行给定的语句

No table used

  • 当查询语句没有from子句时会提示该信息
  • mysql> EXPLAIN SELECT 1;

    Impossible WHERE

  • 查询语句的where条件永远是FALSE

  • mysql> EXPLAIN SELECT * FROM s1 WHERE 1 != 1;

    No matching max/min row

  • 使用MIN / MAX聚合函数 , 但是其where条件并没有查询到相应的信息

  • mysql> EXPLAIN SELECT MIN(key1) FROM s1 WHERE key1 = ‘abcdefg’;

    Using index

  • 使用到我条件列覆盖到索引的时候

  • mysql> EXPLAIN SELECT key1 FROM s1 WHERE key1 = ‘a’;

    Using index condition

  • 出现了索引列 , 但是却无法使用索引

  • SELECT * FROM s1 WHERE key1 > ‘z’ AND key1 LIKE ‘%a’;
    • 首先key1是索引列 , 通过二级索引检索 key1 > ‘ z’ , 找到二级索引记录的id
      • 此步操作通过改进 , 在查询到二级索引记录的id的时候 , 先去匹配看是否满足后面条件 , 如果满足就返回 , 不满足再回表 , 减少随机IO时间
      • 然后通过二级索引的id进行回表 , 查询 key1 like ‘%a’
  • 像这种使用索引条件下推 (Index condition pushdown) 的查询语句 , 就会显示Using index condition的信息

    Using where

  • 当查询扫描全表 , 并且使用到了改表包含的where条件

  • mysql> EXPLAIN SELECT * FROM s1 WHERE common_field = ‘a’;

    Using join buffer (Block Nested Loop)

  • 当被驱动表无法有效利用索引 , Mysql会为其分配一块 join buffer的内存区域 , 是一种 基于块的循环嵌套算法

  • mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.common_field = s2.common_field;
    • 这段sql的执行计划中 ,s2的extra信息显示为 Using where,Using join buffer(Block Nested Loop)
    • 首先在s2无法有效利用到索引的情况下 , 就使用了join buffer来减少IO的次数
    • 其次 , 在联查的时候 , s1. = s2. , 那么就意味着s2此时是一个常量 , 所以提示到了Using where

余下的还有别的extra的附加信息 , 但是不想写了….. 感觉常见的就这几个吧 , 后续如果有经常遇到的再补充吧

Json格式

  • 在语句中加上 FORMAT = JSON可以查看执行计划中”成本”的一环
  • mysql> EXPLAIN FORMAT=JSON SELECT * FROM s1 INNER JOIN s2 ON s1.key1 = s2.key2 WHERE s1.common_field = ‘a’\G

    1. EXPLAIN: {
    2. "query_block": {
    3. "select_id": 1, # 整个查询语句只有1SELECT关键字,该关键字对应的id号为1
    4. "cost_info": {
    5. "query_cost": "3197.16" # 整个查询的执行成本预计为3197.16
    6. },
    7. "nested_loop": [ # 几个表之间采用嵌套循环连接算法执行
    8. # 以下是参与嵌套循环连接算法的各个表的信息
    9. {
    10. "table": {
    11. "table_name": "s1", # s1表是驱动表
    12. "access_type": "ALL", # 访问方法为ALL,意味着使用全表扫描访问
    13. "possible_keys": [ # 可能使用的索引
    14. "idx_key1"
    15. ],
    16. "rows_examined_per_scan": 9688, # 查询一次s1表大致需要扫描9688条记录
    17. "rows_produced_per_join": 968, # 驱动表s1的扇出是968
    18. "filtered": "10.00", # condition filtering代表的百分比
    19. "cost_info": {
    20. "read_cost": "1840.84", # 稍后解释
    21. "eval_cost": "193.76", # 稍后解释
    22. "prefix_cost": "2034.60", # 单次查询s1表总共的成本
    23. "data_read_per_join": "1M" # 读取的数据量
    24. },
    25. "used_columns": [ # 执行查询中涉及到的列
    26. "id",
    27. "key1",
    28. "key2",
    29. "key3",
    30. "key_part1",
    31. "key_part2",
    32. "key_part3",
    33. "common_field"
    34. ],
    35. # s1表访问时针对单表查询的条件
    36. "attached_condition": "((`xiaohaizi`.`s1`.`common_field` = 'a') and (`xiaohaizi`.`s1`.`key1` is not null))"
    37. }
    38. },
    39. {
    40. "table": {
    41. "table_name": "s2", # s2表是被驱动表
    42. "access_type": "ref", # 访问方法为ref,意味着使用索引等值匹配的方式访问
    43. "possible_keys": [ # 可能使用的索引
    44. "idx_key2"
    45. ],
    46. "key": "idx_key2", # 实际使用的索引
    47. "used_key_parts": [ # 使用到的索引列
    48. "key2"
    49. ],
    50. "key_length": "5", # key_len
    51. "ref": [ # key2列进行等值匹配的对象
    52. "xiaohaizi.s1.key1"
    53. ],
    54. "rows_examined_per_scan": 1, # 查询一次s2表大致需要扫描1条记录
    55. "rows_produced_per_join": 968, # 被驱动表s2的扇出是968(由于后边没有多余的表进行连接,所以这个值也没啥用)
    56. "filtered": "100.00", # condition filtering代表的百分比
    57. # s2表使用索引进行查询的搜索条件
    58. "index_condition": "(`xiaohaizi`.`s1`.`key1` = `xiaohaizi`.`s2`.`key2`)",
    59. "cost_info": {
    60. "read_cost": "968.80", # 稍后解释
    61. "eval_cost": "193.76", # 稍后解释
    62. "prefix_cost": "3197.16", # 单次查询s1、多次查询s2表总共的成本
    63. "data_read_per_join": "1M" # 读取的数据量
    64. },
    65. "used_columns": [ # 执行查询中涉及到的列
    66. "id",
    67. "key1",
    68. "key2",
    69. "key3",
    70. "key_part1",
    71. "key_part2",
    72. "key_part3",
    73. "common_field"
    74. ]
    75. }
    76. }
    77. ]
    78. }
    79. }
    80. 1 row in set, 2 warnings (0.00 sec)