MySQL调优之EXPLAIN分析详解

EXPLAIN分析详解

    • 1. id 列 (SQL 执行顺序,id相同从上到下执行,id不同id大的先执行)
    • 2. select_type 列 (查询顺序,区别于普通查询,联合查询,子查询等的复杂查询)
        • a. SIMPLE: 简单的 SELECT (没有 使用UNION 或者 子查询(PS:单表查询))
        • b. PRIMARY: 最外层的Select 作为primary 查询。(PS:含有子查询的情况,但是并不复杂)
        • c. UNION: 从第二个或者在union 之后的select 作为 union 查询
        • d. DEPENDENT UNION: 从第二个或者在union 之后的select 作为 union 查询, 依赖于外部查询(内层的SELECT语句与外层的SELECT语句有依赖关系)
        • e. UNION RESULT: 结果集是通过union 而来的
        • f. SUBQUERY: 第一个查询是子查询
        • g. DEPENDENT SUBQUERY: 第一个查询是子查询,依赖于外部查询
        • h. DERIVED: 在from 查询语句中的(派生,嵌套很多)子查询.(PS:递归操作这些子查询)
        • i. MATERIALIZED: (雾化) 子查询(PS:子查询是个视图?)
        • j. UNCACHEABLE SUBQUERY: 子查询结果不能被缓存, 而且必须重写(分析)外部查询的每一行
        • k. UNCACHEABLE UNION: 第二个 或者 在UNION 查询之后的select ,属于不可缓存的查询
    • 3. table 列 (访问的是哪个表)
    • 4. type 列(MySQL以哪种方式查找数据)
        • a. ALL(全表扫描)
        • b. index(全索引树扫描)
        • c. range(索引下的范围查询)
        • d. ref(索引查找或索引访问)
        • e. eq_ref(索引查找,用于联表查询的情况,只返回一条数据发生在主键和唯一索引)
        • f. const,system(常量,该表最多有一个匹配行)
        • e.NULL(用不着查表甚至连索引都不用查即可得到结果)
    • 5. possible_key 列(查询可以使用到的索引)
    • 6. key 列(MySQL采用了哪个索引)
    • 7. key_len 列(索引使用的字节数即可以查询到所有数据)
    • 8. ref 列(显示索引的哪一列被使用了)
    • 9. rows 列(MySQL估计需要读取的行数)
    • 10. filtered 列(悲观估算查询有效数据百分比)
    • 11. Extra 列(包含了不适合在其他列显示的额外信息)
        • a.Using index(查询使用到了覆盖查询,不需要回表查)
        • b.Using where(在存储引擎检索行后再进行过滤,暗示:查询可受益于不同的索引)
        • c.Using temporary(对查询结果排序时会使用一个临时表)
        • d.Using filesort(对结果使用一个外部索引排序,MySQL不会告诉你是在内存完成还是在磁盘完成)
        • e.Using index condition(5.6加的新特性, 会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行)
        • f.Range checked for each record (index map:N)

建表语句 用实际SQL把所有类型显示出来 SQL需要从上往下执行 有些依赖于上面的SQL
DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher (
id bigint NOT NULL AUTO_INCREMENT,
Tid varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
Tname varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

BEGIN;
INSERT INTO teacher VALUES (1, ‘01’, ‘张三’);
INSERT INTO teacher VALUES (2, ‘02’, ‘李四’);
INSERT INTO teacher VALUES (3, ‘03’, ‘王五’);
COMMIT;

DROP TABLE IF EXISTS course;
CREATE TABLE course (
id bigint NOT NULL AUTO_INCREMENT,
Cid varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
Cname varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
Tid varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

BEGIN;
INSERT INTO course VALUES (1, ‘01’, ‘语文’, ‘02’);
INSERT INTO course VALUES (2, ‘02’, ‘数学’, ‘01’);
INSERT INTO course VALUES (3, ‘03’, ‘英语’, ‘03’);
COMMIT;

DROP TABLE IF EXISTS sc;
CREATE TABLE sc (
id bigint NOT NULL AUTO_INCREMENT,
Sid varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
Cid varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
score decimal(18,1) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

BEGIN;
INSERT INTO sc VALUES (1, ‘01’, ‘01’, 80.0);
INSERT INTO sc VALUES (2, ‘01’, ‘02’, 90.0);
INSERT INTO sc VALUES (3, ‘01’, ‘03’, 99.0);
INSERT INTO sc VALUES (4, ‘02’, ‘01’, 70.0);
INSERT INTO sc VALUES (5, ‘02’, ‘02’, 60.0);
INSERT INTO sc VALUES (6, ‘02’, ‘03’, 80.0);
INSERT INTO sc VALUES (7, ‘03’, ‘01’, 80.0);
INSERT INTO sc VALUES (8, ‘03’, ‘02’, 80.0);
INSERT INTO sc VALUES (9, ‘03’, ‘03’, 80.0);
INSERT INTO sc VALUES (10, ‘04’, ‘01’, 50.0);
INSERT INTO sc VALUES (11, ‘04’, ‘02’, 30.0);
INSERT INTO sc VALUES (12, ‘04’, ‘03’, 20.0);
INSERT INTO sc VALUES (13, ‘05’, ‘01’, 76.0);
INSERT INTO sc VALUES (14, ‘05’, ‘02’, 87.0);
INSERT INTO sc VALUES (15, ‘06’, ‘01’, 31.0);
INSERT INTO sc VALUES (16, ‘06’, ‘03’, 34.0);
INSERT INTO sc VALUES (17, ‘07’, ‘02’, 89.0);
INSERT INTO sc VALUES (18, ‘07’, ‘03’, 98.0);
COMMIT;

DROP TABLE IF EXISTS student;
CREATE TABLE student (
id bigint NOT NULL AUTO_INCREMENT,
Sid varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
Sname varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
Sage datetime DEFAULT NULL,
Ssex varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

BEGIN;
INSERT INTO student VALUES (1, ‘01’, ‘赵雷’, ‘1990-01-01 00:00:00’, ‘男’);
INSERT INTO student VALUES (2, ‘02’, ‘钱电’, ‘1990-12-21 00:00:00’, ‘男’);
INSERT INTO student VALUES (3, ‘02’, ‘钱电’, ‘1990-12-21 00:00:00’, ‘男’);
INSERT INTO student VALUES (4, ‘03’, ‘孙风’, ‘1990-05-20 00:00:00’, ‘男’);
INSERT INTO student VALUES (5, ‘04’, ‘李云’, ‘1990-08-06 00:00:00’, ‘男’);
INSERT INTO student VALUES (6, ‘05’, ‘周梅’, ‘1991-12-01 00:00:00’, ‘女’);
INSERT INTO student VALUES (7, ‘06’, ‘吴兰’, ‘1992-03-01 00:00:00’, ‘女’);
INSERT INTO student VALUES (8, ‘07’, ‘郑竹’, ‘1989-07-01 00:00:00’, ‘女’);
INSERT INTO student VALUES (9, ‘08’, ‘王菊’, ‘1990-01-20 00:00:00’, ‘女’);
COMMIT;

1. id 列 (SQL 执行顺序,id相同从上到下执行,id不同id大的先执行)

2. select_type 列 (查询顺序,区别于普通查询,联合查询,子查询等的复杂查询)

a. SIMPLE: 简单的 SELECT (没有 使用UNION 或者 子查询(PS:单表查询))

EXPLAIN SELECT * from student;

b. PRIMARY: 最外层的Select 作为primary 查询。(PS:含有子查询的情况,但是并不复杂)

//获取学生id值最大的学生
EXPLAIN SELECT * from student a where Sid = (select MAX(Sid) from student b);

c. UNION: 从第二个或者在union 之后的select 作为 union 查询

EXPLAIN SELECT * from student WHERE id > 8
UNION
SELECT * from student WHERE id < 2;

d. DEPENDENT UNION: 从第二个或者在union 之后的select 作为 union 查询, 依赖于外部查询(内层的SELECT语句与外层的SELECT语句有依赖关系)

EXPLAIN
SELECT * from sc WHERE Sid in(
SELECT a.Sid from student a WHERE id > 8
UNION
SELECT b.Sid from student b WHERE id < 2);

e. UNION RESULT: 结果集是通过union 而来的

EXPLAIN SELECT * from student WHERE id > 8
UNION
SELECT * from student WHERE id < 2;

f. SUBQUERY: 第一个查询是子查询

EXPLAIN SELECT * from student a where Sid = (select MAX(Sid) from student b);

g. DEPENDENT SUBQUERY: 第一个查询是子查询,依赖于外部查询

特别关注 DEPENDENT SUBQUERY
1 会严重消耗性能
2 不会进行子查询,会先进行外部查询,生成结果集,再在内部进行关联查询
3 子查询的执行效率受制于外层查询的记录数
4 可以尝试改成join查询

EXPLAIN
SELECT * from sc WHERE Sid in(
SELECT a.Sid from student a WHERE id > 8
UNION
SELECT b.Sid from student b WHERE id < 2);

h. DERIVED: 在from 查询语句中的(派生,嵌套很多)子查询.(PS:递归操作这些子查询)

EXPLAIN
SELECT * from student s JOIN (SELECT Sid, max(score) from sc GROUP BY Sid) b ON s.Sid = b.Sid;

i. MATERIALIZED: (雾化) 子查询(PS:子查询是个视图?)

EXPLAIN SELECT * from student a where Sid in (select Sid from sc b where score > 80);

j. UNCACHEABLE SUBQUERY: 子查询结果不能被缓存, 而且必须重写(分析)外部查询的每一行

k. UNCACHEABLE UNION: 第二个 或者 在UNION 查询之后的select ,属于不可缓存的查询

3. table 列 (访问的是哪个表)

4. type 列(MySQL以哪种方式查找数据)

效率从低到高排列 最低查询要保证在range级别之上

a. ALL(全表扫描)

效率最低 无使用到任何索引,必须要优化

b. index(全索引树扫描)

create index Sid on student(Sid);
explain
SELECT * from student force index(Sid) ORDER BY Sid;

c. range(索引下的范围查询)

explain
SELECT * from student WHERE id > 4 and id < 8;

d. ref(索引查找或索引访问)

只发生在非唯一索引或者是唯一索引的非唯一查找
1.create index Sname on student(Sname);
explain
SELECT * from student where Sname = ‘赵雷’;
2.create unique index Tid on teacher(Tid);
#这里不建议在索引列使用null 只为测试用
insert into teacher(Tid,Tname) VALUES(null,‘老徐’);
insert into teacher(Tid,Tname) VALUES(null,‘栩栩’);
explain
SELECT * from teacher where Tid is null;

e. eq_ref(索引查找,用于联表查询的情况,只返回一条数据发生在主键和唯一索引)

explain
SELECT * from teacher t right JOIN student s ON s.id = t.id

f. const,system(常量,该表最多有一个匹配行)

explain
SELECT * from teacher where Tid = ‘01’;

e.NULL(用不着查表甚至连索引都不用查即可得到结果)

explain
SELECT day(NOW());

5. possible_key 列(查询可以使用到的索引)

6. key 列(MySQL采用了哪个索引)

7. key_len 列(索引使用的字节数即可以查询到所有数据)

8. ref 列(显示索引的哪一列被使用了)

9. rows 列(MySQL估计需要读取的行数)

10. filtered 列(悲观估算查询有效数据百分比)

11. Extra 列(包含了不适合在其他列显示的额外信息)

a.Using index(查询使用到了覆盖查询,不需要回表查)

explain
SELECT Sid from student; (Sid在上面已经建立了索引)

b.Using where(在存储引擎检索行后再进行过滤,暗示:查询可受益于不同的索引)

表示优化器需要通过索引回表查询数据

c.Using temporary(对查询结果排序时会使用一个临时表)

使用group by一个没有索引的列
explain
SELECT sum(score) from sc GROUP BY Cid

d.Using filesort(对结果使用一个外部索引排序,MySQL不会告诉你是在内存完成还是在磁盘完成)

filesort的意思是只要一个排序无法使用索引来排序,或者 ORDER BY 或 GROUP BY 的列不是来自JOIN语句序列的第一个表
explain
SELECT * from student ORDER BY Sage;

e.Using index condition(5.6加的新特性, 会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行)

f.Range checked for each record (index map:N)

这个值意味着没有好用的索引,新的索引将在联接每的每一行重新估算。N是显示在possible_key 列中索引的位图,并且是冗余的

’#
‘#
’#
‘#

下一篇总结一下对SQL优化作法

你可能感兴趣的:(MySQL学习)