当前位置: 移动技术网 > IT编程>数据库>Mysql > explanin mysql 性能调优

explanin mysql 性能调优

2020年07月14日  | 移动技术网IT编程  | 我要评论

mysql中的 explain命令可以用来查看sql语句是否使用了索引,用了什么索引,有没有做全表扫描。可以帮助我们优化查询语句。

explain 命令的信息有10列 ,本文主要介绍 key 、type 、Extra 这三个字段.

部门表: 

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for dept
-- ----------------------------
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
  `dept_no` char(4) NOT NULL,
  `dept_name` varchar(40) NOT NULL,
  `desc` varchar(255) NOT NULL,
  PRIMARY KEY (`dept_no`),
  UNIQUE KEY `dept_no` (`dept_no`) USING BTREE,
  KEY `dept_name` (`dept_name`) USING BTREE,
  KEY `dept_no_name` (`dept_no`,`dept_name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of dept
-- ----------------------------
BEGIN;
INSERT INTO `dept` VALUES ('1', '部门1', '1');
INSERT INTO `dept` VALUES ('2', '部门2', '2');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

部门员工关联表:

DROP TABLE IF EXISTS `dept_emp`;
CREATE TABLE `dept_emp` (
  `emp_no` int(11) NOT NULL,
  `dept_no` char(4) NOT NULL,
  `from_date` date NOT NULL,
  `to_date` date NOT NULL,
  PRIMARY KEY (`emp_no`,`dept_no`),
  UNIQUE KEY `dept_no` (`dept_no`) USING BTREE,
  CONSTRAINT `dept_emp_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE,
  CONSTRAINT `dept_emp_ibfk_2` FOREIGN KEY (`dept_no`) REFERENCES `dept` (`dept_no`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of dept_emp
-- ----------------------------
BEGIN;
INSERT INTO `dept_emp` VALUES (1, '1', '2020-07-11', '2020-07-11');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;
 

员工表:

-- ----------------------------
DROP TABLE IF EXISTS `employees`;
CREATE TABLE `employees` (
  `emp_no` int(11) NOT NULL,
  `birth_date` date NOT NULL,
  `first_name` varchar(14) NOT NULL,
  `last_name` varchar(16) NOT NULL,
  `gender` enum('M','F') NOT NULL,
  `hire_date` date NOT NULL,
  PRIMARY KEY (`emp_no`),
  KEY `index_b_f` (`first_name`,`last_name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of employees
-- ----------------------------
BEGIN;
INSERT INTO `employees` VALUES (1, '2020-07-11', '张三', '张三', 'M', '2020-07-11');
INSERT INTO `employees` VALUES (2, '2020-07-11', '李四', '李四', 'F', '2020-07-11');
COMMIT;

SET FOREIGN_KEY_CHECKS = 1;

1、key : mysql 使用的索引列,有时候mysql会使用效果不好的索引列,这时我们可以使用 select 语句中的force index(indexname) 来强制使用mysql 的索引列.或者使用 ignore index(indexname) 来忽略指定索引列.

explain select dept_no  from  dept force index(dept_no) ;

explain select dept_no  from  dept ignore index(dept_no) ;

2、type: 访问类型,表示mysql 数据库引擎查找表的方式.常见的方式有 :all、index、range、ref、eq_ref、const;

  all:全表扫描,表示sql 语句会将整张表的数据读取扫描一遍,效率最低,我们应当避免.

explain select *  from  dept;

  index:全索引扫描,表示mysql 会将整颗索引树,全部扫描一遍.因为二级索引树的数据,比全表的数据量要小得多,所有效率比all 类型要高一些.一般查询语句,且无where 字段,type 就为index.

explain select dept_no from  dept;

range:部分索引扫描、当查询为区间查询时,且查询字段为索引查询.这时会根据where条件对索引进行部分扫描.

explain select * from  dept where dept_no >'1';

ref:出现于 where 后的条件为‘=’时,且where 后字段是非唯一索引的单表查询或联表查询.

explain select * from  dept where dept_name ='1';

 

eq_ref:出现于 where 后的条件为‘=’时,且where 后字段是唯一索引的联表查询.
 explain select * from dept_emp ,dept
 where dept_emp.dept_no=dept.dept_no;

const:出现于where 操作符为‘=’时,,且where 后字段是唯一索引的单表查询,此时最多会匹配到一行数据.

explain select dept_no from  dept where dept_no ='1';

单从type字段考虑效率比较:const>eq_ref>ref>range>index>all; 我们并不能用type去考虑两条sql 的效率.例如type为range的查询不一定比type为index的全表查询速度要快,还要看具体的sql。要判断是否有回表操作.

列如:sqlA(explain select dept_no from dept;)  sqlB(explain select dept_name from dept where  dept_no >'1';)

sqlA 虽然用的type:index 看起要比 sqlB type:range 要慢. 但是 sqlB where 条件后,dept_no>1 用到range,查询结果是 dept_name 字段,sqlB 需要进行回表操作,索引sqlB 比sqlA 效率更低.

3、Extra: extra列会包含一些十分重要的信息,我们可以根据这些信息进行sql优化.

useing index:sql 没有where查询条件 ,使用覆盖索引,不需要回表即可拿到结果.

explain select dept_no from dept;

useing where :没有使用索引列/使用了索引列但需要回表操作,且没有使用到下推索引.

explain select dept_name from dept where  dept_no >'1';

useing index & useing where :sql 语句有查询条件,且使用覆盖索引,不需要回表即可拿到结果.

explain select dept_name ,dept_no from dept where dept_no >'1' and dept_name='部门1';

using index condition :使用索引查询,且where子句 查询条件字段与查询字段为统一字段,且开启索引下推功能,需要回表即可拿到结果.

 explain  select * from employees where first_name ='张三'  and last_name like '%张%' 

using index condition& using where :使用索引查询,sql 语句的where子句查询条件字段,存在非同一索引字段,且开始索引开启下推功能,需要回表查询即可拿到结果.

 explain  select * from employees where first_name ='张三'  and last_name like '%张%'  and gender='F'

using filesort:当语句存在order by 时,order by 字段不是索引字段,这个时候mysql 就无法利用索引进行排序.只能用排序算法额外排序,会额外消耗资源.

 explain  select * from employees   order by birth_date

using temporary :建立临时表保存中间结果.查询完有把临时表删除,会影响性能,需要优化.

 explain select b.* from dept  b
left  join dept_emp  b1   on b1.dept_no =b.dept_no
order by b1.from_date desc

有时在extra字段中会出现"Impossible WHERE noticed after reading const tables"这种描述。翻看网上资料后,个人发现这是mysql一种很怪的处理方式。

当sql 满足:

1、根据主键查询或者唯一性索引查询

2、where 后操作符号为‘=’时.

在sql语句优化阶段,mysql会先根据查询条件找到相关记录,这样,如果这条数据不存在,实际上就进行了一次全扫描,然后得出一个结论,该数据不在表中。这样对于并发较高的数据库,会加大负载。所以,如果数据不用唯一的话,普通的索引比唯一索引更好用。

索引下推 (using condition)

解释:根据联合查询的其他索引做一个筛选,筛选通过的才回表查询,减少回表次数;

配置: 

索引下推优化是默认开启的。可以通过下面的脚本控制开关

SET optimizer_switch = ‘index_condition_pushdown=off’;
SET optimizer_switch = ‘index_condition_pushdown=on’;

回表: 简单说就是mysql内部需要经过两次查询. 第一次先索引扫描,然后再通过主键去取索引中未能提供的数据。

只有在使用了索引,且Extra是Using where的情况下,才代表回表查询数据。

 

本文地址:https://blog.csdn.net/qq_29651203/article/details/107282012

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网