MySQL中使用explain命令分析查询

MySQL中使用explain命令分析查询

在MySQL中,使用explain对查询(select)语句进行分析,可以根据分析结果对查询进行优化。

一、数据准备

创建两张表:部门(dept)和员工(emp),表结构如下:

create table dept(
    dept_id int primary key auto_increment comment '部门编号',
    dept_name char(20) comment '部门名称'
);
insert into dept(dept_name) values('销售部'),('财务部'),('生产部'),('人事部');

create table emp(
    emp_id int primary key auto_increment comment '员工号',
    emp_name char(20) not null default '' comment '员工姓名',
    gender char(2) not null default '男' comment '性别',
    birth datetime not null default '1990-1-1' comment '出生日期',
    salary decimal(10,2) not null default 0 comment '工资',
    address varchar(200) not null default '' comment '通讯地址',
    dept_id int comment '部门编号'
);

create index idx_name on emp(emp_name);
create index idx_birth on emp(birth);
create index idx_deptid_name on emp(dept_id,emp_name);

insert into emp(emp_name,gender,birth,salary,address,dept_id) 
values('张晓红','女','1980-1-23',5800,'河南省郑州市中原路10号',1),
('张静静','女','1987-10-3',5400,'河南省新乡市平原路38号',1),
('王云飞','男','1992-11-15',5600,'河南省新乡市人民路28号',1),
('王鹏飞','男','1987-10-1',6800,'河南省新乡市东明大道12号',1),
('王大鹏','男','1989-2-11',5900,'河南省郑州市东风路15号',1),
('王萌萌','女','1986-12-30',5000,'河南省开封市五一路14号',2),
('王大光','男','1988-11-8',6200,'河南省开封市八一路124号',2),
('王小明','男','1998-1-3',4800,'河南省驻马店市雪松路128号',2),
('王娜娜','女','1994-3-5',5200,'河南省驻马店市车站路2号',2),
('刘云飞','男','1992-8-13',6800,'河南省南阳市民生路255号',3),
('张陆军','男','1991-9-6',6200,'河南省南阳市张仲景路14号',3);

二、explain语句的语法

explain语句的基本语法如下:

explain select 语句;

使用explain对查询进行分析,结果如下:

mysql> explain select * from emp 
    -> where salary>(select salary from emp where emp_name='王大光')\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: emp
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 11
     filtered: 33.33
        Extra: Using where
*************************** 2. row ***************************
           id: 2
  select_type: SUBQUERY
        table: emp
   partitions: NULL
         type: ref
possible_keys: idx_name
          key: idx_name
      key_len: 60
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
2 rows in set, 1 warning (0.00 sec)

explain显示结果中每个项目的含义为:
1、select_type:select查询的类型,可能会有以下几种情况:
(1)simple:简单的select(没有使用 union或子查询);
(2)primary:最外层的 select;
(3)union:union连接的select查询,除了第一个表外,第二个及以后的表select_type都是union;
(4)dependent union:与union一样,但是这个查询要受到外部查询的影响;
(5)subquery:子查询中的第一个select(from后面的子查询除外);
(6)dependent subquery:表示子查询要受到外部表查询的影响;
(7)derived:from字句中出现的子查询;
2、table:查询引用的表,如果查询使用了别名,则显示的是别名,如果不涉及数据表的操作,显示null;
3、partitions:显示分区表命中的分区情况,非分区表该字段为空(null)。
4、type:表连接类型。从好到差依次为:依次从好到差:system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL,除了all之外,其他的type都可以使用到索引。
(1)system:表中只有一行数据或者是空表,且只能用于myisam和memory表;
(2)const:使用唯一索引或者主键进行检索,返回1行记录的等值where条件时为const;
(3)index_merge:表示查询时通过and和or使用了两个以上的索引;
(4)range:索引范围扫描,常见于使用 =, <>, >, >=, <, <=, BETWEEN, IN或like等运算符的查询中;
(5)index:索引全表扫描,把索引从头到尾扫一遍;
(6)all:进行完整的表扫描。
5、possible_keys:在搜索表记录时可能使用哪个索引,possible_keys所包含的索引在实际查询时可能没有被使用。如果为null则表示没有使用任何索引;
6、key:实际使用的索引。如果没有任何索引被用到则为null;
7、key_len:索引的长度。
8、ref:显示使用哪个列或常数与key一起从表中选择行;
9、rows:执行查询时需要检查的行数;
10、filtered:通过条件过滤出的行数的百分比;
11、Extra:显示的信息常用的有:
(1)distinct:在select部分使用了distinc关键字;
(2)no tables used:不带from字句的查询或者from dual查询;
(3)using filesort:排序时无法使用到索引时,常见带order by和group by子句的查询;
(4)using index:查询时使用了覆盖索引,直接通过索引就可以获取查询的数据;
(5)using temporary:使用临时表存储中间结果。

三、举例

(一)子查询

mysql> explain select emp_name,salary from emp where salary>(select avg(salary) from emp)\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: emp
   partitions: NULL
         type: ALL
possible_keys: idx_salary
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 11
     filtered: 54.55
        Extra: Using where
*************************** 2. row ***************************
           id: 2
  select_type: SUBQUERY
        table: emp
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_salary
      key_len: 5
          ref: NULL
         rows: 11
     filtered: 100.00
        Extra: Using index
2 rows in set, 1 warning (0.01 sec)

(二)union联合查询

mysql> explain select * from emp where dept_id=1 union select * from emp where dept_id=2\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: emp
   partitions: NULL
         type: ref
possible_keys: idx_deptid_name
          key: idx_deptid_name
      key_len: 5
          ref: const
         rows: 5
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 2
  select_type: UNION
        table: emp
   partitions: NULL
         type: ref
possible_keys: idx_deptid_name
          key: idx_deptid_name
      key_len: 5
          ref: const
         rows: 4
     filtered: 100.00
        Extra: NULL
*************************** 3. row ***************************
           id: NULL
  select_type: UNION RESULT
        table: <union1,2>
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
     filtered: NULL
        Extra: Using temporary
3 rows in set, 1 warning (0.01 sec)

(三)连接查询

mysql> explain select emp_name,salary,dept_name from emp join dept on dept.dept_id=emp.dept_id where dept.dept_id=1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: dept
   partitions: NULL
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ref
possible_keys: idx_deptid_name
          key: idx_deptid_name
      key_len: 5
          ref: const
         rows: 5
     filtered: 100.00
        Extra: NULL
2 rows in set, 1 warning (0.00 sec)

(四)索引覆盖

索引覆盖是查询性能很高的一种情况,当查询所需数据时直接从索引树中检索数据,不需要回写。

mysql> show create table emp\G
*************************** 1. row ***************************
       Table: emp
Create Table: CREATE TABLE `emp` (
  `emp_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '员工号',
  `emp_name` char(20) NOT NULL DEFAULT '' COMMENT '员工姓名',
  `gender` char(2) NOT NULL DEFAULT '男' COMMENT '性别',
  `birth` datetime NOT NULL DEFAULT '1990-01-01 00:00:00' COMMENT '出生日期',
  `salary` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '工资',
  `address` varchar(200) NOT NULL DEFAULT '' COMMENT '通讯地址',
  `dept_id` int(11) DEFAULT NULL COMMENT '部门编号',
  PRIMARY KEY (`emp_id`),
  KEY `idx_name` (`emp_name`),
  KEY `idx_deptid_name` (`dept_id`,`emp_name`),   --创建了联合索引
  KEY `idx_birth` (`birth`),
  KEY `idx_salary` (`salary`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> explain select emp_name from emp where dept_id=1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: emp
   partitions: NULL
         type: ref
possible_keys: idx_deptid_name
          key: idx_deptid_name
      key_len: 5
          ref: const
         rows: 5
     filtered: 100.00
        Extra: Using index   ---表示索引覆盖
1 row in set, 1 warning (0.00 sec)
发布了44 篇原创文章 · 获赞 48 · 访问量 5406

猜你喜欢

转载自blog.csdn.net/weixin_44377973/article/details/103224395