mysql 执行计划 SELECT_TYPE类型详解

文章目录

        • 测试表&&数据
        • SIMPLE
        • PRIMARY && DEPENDENT SUBQUERY
        • MATERIALIZED
        • SUBQUERY
        • UNION RESULT
        • UNION
        • DEPENDENT UNION
        • DERIVED

测试表&&数据
create table t_user(
    id int unsigned auto_increment primary key,
    name varchar(10)
) engine = innodb default charset utf8;

insert into t_user (id,name) values (1,"test1"),(2,"test2"),(3,"test3");

create table t_user_level(
    level_id int unsigned auto_increment primary key,
    user_id  int unsigned not null,
    name varchar(10)
) engine = innodb default charset utf8;

insert into t_user_level (user_id, name) values (1, "青铜会员"),(2, "白银会员"),(3, "钻石会员")

create table t_level_log (
    log_id int unsigned auto_increment primary key ,
    level_id int unsigned not null
)engine = innodb default charset utf8;

insert into t_level_log (level_id) values (1),(2),(3)
SIMPLE

简单查询,不包括子查询或者union操作

mysql> explain select * from t_user;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

PRIMARY && DEPENDENT SUBQUERY

在未被SEMIJOIN的情况下
如果有子查询,那么最外层的查询被标记为PRIMARY
由于select name from t_user id 依赖于子查询的查询结果,所以该子查询被标记为 DEPENDENT SUBQUERY
使用max是防止查询优化器SEMIJOIN

mysql> explain select name from t_user where id in (select max(user_id) from t_user_level);
+----+--------------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type        | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+--------------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | PRIMARY            | t_user       | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | Using where |
|  2 | DEPENDENT SUBQUERY | t_user_level | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL        |
+----+--------------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+

MATERIALIZED

被查询优化器SEMIJOIN,生成临时表
最后是临时表去和user join 得到的结果

mysql> explain select name from t_user where id in (select user_id from t_user_level);
+----+--------------+--------------+------------+--------+---------------+---------+---------+---------------------+------+----------+-------+
| id | select_type  | table        | partitions | type   | possible_keys | key     | key_len | ref                 | rows | filtered | Extra |
+----+--------------+--------------+------------+--------+---------------+---------+---------+---------------------+------+----------+-------+
|  1 | SIMPLE       | <subquery2>  | NULL       | ALL    | NULL          | NULL    | NULL    | NULL                | NULL |   100.00 | NULL  |
|  1 | SIMPLE       | t_user       | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | <subquery2>.user_id |    1 |   100.00 | NULL  |
|  2 | MATERIALIZED | t_user_level | NULL       | ALL    | NULL          | NULL    | NULL    | NULL                |    3 |   100.00 | NULL  |
+----+--------------+--------------+------------+--------+---------------+---------+---------+---------------------+------+----------+-------+

SUBQUERY

不被最外层直接依赖的子查询
id 1 直接依赖于 id2
id 1 不直接依赖于 id3
id 2 依赖于 id3

mysql> explain select name from t_user where id in (select max(user_id) from t_user_level where level_id in (select min(level_id) from t_level_log));
+----+--------------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type        | table        | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+--------------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | PRIMARY            | t_user       | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | Using where |
|  2 | DEPENDENT SUBQUERY | t_user_level | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | Using where |
|  3 | SUBQUERY           | t_level_log  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL        |
+----+--------------------+--------------+------------+------+---------------+------+---------+------+------+----------+-------------+

将上面语句修改下,去掉min,让查询优化器对其进行SEMIJOIN
t_level_log 生成临时表
最外层被标记为PRIMARY
id1 依赖于id2,但不是直接依赖,而是依赖于 id2 的 join 结果,故此id2被标记为 SUBQUERY 而不是 DEPENDENT SUBQUERY

mysql> explain select name from t_user where id in (select max(user_id) from t_user_level where level_id in (select level_id from t_level_log));
+----+--------------+--------------+------------+--------+---------------+---------+---------+----------------------+------+----------+-------------+
| id | select_type  | table        | partitions | type   | possible_keys | key     | key_len | ref                  | rows | filtered | Extra       |
+----+--------------+--------------+------------+--------+---------------+---------+---------+----------------------+------+----------+-------------+
|  1 | PRIMARY      | t_user       | NULL       | ALL    | NULL          | NULL    | NULL    | NULL                 |    3 |   100.00 | Using where |
|  2 | SUBQUERY     | <subquery3>  | NULL       | ALL    | NULL          | NULL    | NULL    | NULL                 | NULL |   100.00 | NULL        |
|  2 | SUBQUERY     | t_user_level | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | <subquery3>.level_id |    1 |   100.00 | NULL        |
|  3 | MATERIALIZED | t_level_log  | NULL       | ALL    | NULL          | NULL    | NULL    | NULL                 |    3 |   100.00 | NULL        |
+----+--------------+--------------+------------+--------+---------------+---------+---------+----------------------+------+----------+-------------+

UNION RESULT

使用union产生的结果集被标记为 UNION RESULT

mysql> explain select * from t_user union  select * from t_user;
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
| id | select_type  | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra           |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+
|  1 | PRIMARY      | t_user     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL            |
|  2 | UNION        | t_user     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL            |
| NULL | UNION RESULT | <union1,2> | NULL       | ALL  | NULL          | NULL | NULL    | NULL | NULL |     NULL | Using temporary |
+----+--------------+------------+------------+------+---------------+------+---------+------+------+----------+-----------------+

UNION

使用union 或 union all 后的查询被标记union
将第2,3两个查询与1合并
1 被标记为PRIMARY
2,3 被标记为union

mysql> explain select name from t_user union all select name from t_user union all select name from t_user;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | PRIMARY     | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
|  2 | UNION       | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
|  3 | UNION       | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+

DEPENDENT UNION

直接依赖 UNION 查询的结果
PRIMARY 直接依赖于 t1结果,t1标记为PRIMARY
由于t2的结果也直接被PRIMARY依赖,且是UNION,t2标记为 DEPENDENT UNION

mysql> explain select * from t_user where id in (select id from t_user as t1 union all select id from t_user as t2);
+----+--------------------+--------+------------+--------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type        | table  | partitions | type   | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+--------------------+--------+------------+--------+---------------+---------+---------+------+------+----------+-------------+
|  1 | PRIMARY            | t_user | NULL       | ALL    | NULL          | NULL    | NULL    | NULL |    3 |   100.00 | Using where |
|  2 | DEPENDENT SUBQUERY | t1     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | func |    1 |   100.00 | Using index |
|  3 | DEPENDENT UNION    | t2     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | func |    1 |   100.00 | Using index |
+----+--------------------+--------+------------+--------+---------------+---------+---------+------+------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)

DERIVED

from 后的子查询被标记为DERIVED
第二个被标记为 SIMPLE 是因为经过优化器后变成
select * from t_user,from后面并不是子查询

mysql> explain select * from (select * from t_user as t1 union all  select * from t_user as t2) as a;
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    6 |   100.00 | NULL  |
|  2 | DERIVED     | t1         | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
|  3 | UNION       | t2         | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
+----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+
3 rows in set, 1 warning (0.00 sec)

mysql> explain select * from (select * from t_user) as b;
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    3 |   100.00 | NULL  |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------+

你可能感兴趣的:(#,Mysql,mysql,数据库,sql)