百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>数据库> 实践(1)--MySQL机能优化
分享文章到:

实践(1)--MySQL机能优化

发布时间:09/01 来源:未知 浏览: 关键词:

SQL语句优化-Explain工具

使用EXPLAIN关键字可以模拟优化器施行SQL语句,剖析你的查询语句或是构造的机能瓶颈 在 select 语句此前增添 explain 关键字,MySQL 会在查询上设定一个标志,施行查询会返回施行方案的信息,而不是施行这条SQL。

留意:假如 from 中包括子查询,仍会施行该子查询,将结果放入暂时表中

Explain剖析示例

DROP TABLE IF EXISTS `actor`; 
CREATE TABLE `actor` (`id` int(11) NOT NULL,`name` varchar(45) DEFAULT NULL, `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `actor` (`id`,`name`,`update_time`) VALUES (1,'a','2020-09-16 14:26:11'), (2,'b','2020-09-16 14:26:11'), (3,'c','2020-09-16 14:26:11');DROP TABLE IF EXISTS` film`; 
CREATE TABLE`film`(`id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`),KEY `idx_name` (`name`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `film`(`id`,`name`) VALUES (3,'film0'),(1,'film1'),(2,'film2');DROP TABLE IF EXISTS `film_actor`;CREATE TABLE`film_actor`(`id` int(11) NOT NULL,`film_id` int(11) NOT NULL,`actor_id` int(11) NOT NULL,`remark` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),KEY `idx_film_actor_id` (`film_id`,`actor_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO`film_actor`(`id`,`film_id`,`actor_id`)VALUES(1,1,1), (2,1,2),(3,2,1);复制代码
explain select * from actor;复制代码
image.png

查询中的每个表会输出一行,假如有两个表通过join连接查询,那么会输出两行。每一列详细的说明在后面停止说明。

Explain 两个变种

  1. explain extended

会在 explain 的根基上额外供给一些查询优化的信息。紧随其后通过 show warnings 命令可以得到优化后的查询语句,从而看出优化器优化了什么。额外还有 filtered 列,是一个半分比的值,rows * filtered/100 可以预算出将要和 explain 中前一个表停止连接的行数(前一个表指 explain 中的id值比当前表id值小的表)。

explain extended select * from film where id = 1;复制代码
image.png
show warnings;复制代码
image.png
  1. explain partitions

比拟 explain 多了个 partitions 字段,假如查询是基于分区表的话,会显示查询将拜访的分区。

Explain中的列

接下来我们将展现 explain 中每个列的信息。

id 列

id 列的编号是 select 的序列号,有几个 select 就有几个 id,并且id的次序是按 select 显现的次序递增的。id列越大施行优先级越高,id雷同则从上往下施行,id为 NULL 最后施行。

select_type 列

select_type 表示对应行是简便还是复杂的查询。

  • simple :简便查询。查询不包括子查询和union
explain select * from film where id = 2;复制代码
image.png
  • primary :复杂查询中最外层的 select
  • subquery :包括在 select 中的子查询(不在 from 子句中)
  • derived :包括在 from 子句中的子查询。MySQL 会将结果存置在一个暂时表中,也称为派生表(derived的英文含义)

用下面这个例子来理解 primary、subquery、derived类型。

explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;复制代码

未关闭MySQL5.7新特性对衍生表的合并优化,如下:

image.png
#关闭mysql5.7新特性对衍 生表的合并优化set session optimizer_switch='derived_merge=off'; 
复制代码
image.png
#复原默许配置set session optimizer_switch='derived_merge=on'; 
复制代码
  • union :在 union 中的第二个和随后的 select
explain select 1 union all select 1;复制代码
image.png

table 列

这一列表示 explain 的一行正在拜访哪个表。 当 from 子句中有子查询时,table列是 格局,表示当前查询依靠 id=N 的查 询,于是先施行 id=N 的查询。 当有 union 时,UNION RESULT 的 table 列的值为<union1,2>,1和2表示参与 union 的 select 行id。

type 列

这一列表示关联类型或拜访类型,即MySQL决议怎样查寻表中的行,查寻数据行记载的大约范畴。

顺次从最优到最差离别为:

system > const > eq_ref > ref > range > index > ALL复制代码

一样来说,得包管查询到达 range 级别,最好到达 ref

NULL:MySQL 能够在优化阶段分解查询语句,在施行阶段用不着再拜访表或索引。例如:在索引列中拔取最小值,可以独自查寻索引来完成,不需要在施行时拜访表。

explain select min(id) from film;复制代码
image.png

systemconst :MySQL 能对查询的某部分停止优化并将其转化成一个常量(可以看 show warnings 的)。用于 primary keyunique key 的所有列与常数比力时,所以表最多有一个匹配行,读取1次,速度比力快。system 是 const 的特例,表里只要一条元组匹配时为 system。

explain extended select * from (select * from film where id = 1) tmp;复制代码
image.png
show warnings;复制代码
image.png

eq_ref :primary key 或 unique key 索引的所有部分被连接使用,最多只会返回一条相符前提的记载。这大概实在 const 之外最好的连接类型了,简便的 select 查询不会显现这种 type。

explain select * from film_actor left join film on film_actor.film_id = film.id;复制代码
image.png

ref :比拟 eq_ref ,不使用独一索引,而是使用一般索引或者独一性索引的部分前缀,索引要和某个值比拟较,大概会寻到多个相符前提的行。

(1)简便 select 查询,name 是一般索引(非独一索引)

explain select * from film where name = 'film1';复制代码
image.png

(2)关联表查询, idx_film_actor_id 是 film_id 和 actor_id 的结合索引,这里使用到了 film_actor 的左边前缀 film_id 部分。

 explain select film_id from film left join film_actor on film.id = film_actor.film_id;复制代码
image.png

range : 范畴扫描平常显现在 in()、betwwen、>、<、>= 等操纵中。使用一个索引来检索给定范畴的行。

explain select * from actor where id > 1;复制代码
image.png

index :扫描全表索引,通过比 ALL 快一些。

explain select * from film;复制代码
image.png

ALL :即全表扫描,意味着MySQL需要从头到尾去查寻所需要的行。平常状况下这需要增添索引来停止优化了。

explain select * from actor复制代码
image.png

possible_keys 列

这一列显示查询大概使用哪些索引来查寻。 explain 时大概显现 possible_keys 有列,而 key 显示 NULL 的状况,这种状况是由于表中数据不多,mysql认为索引对此查询帮忙不大,选中了全表查询。 假如该列是NULL,则没有相关的索引。在这种状况下,可以通过检查 where 子句看可否可以制造一个恰当的索引来提高查询机能,然后用 explain 查看结果。

key 列

这一列显示mysql实际采纳哪个索引来优化对该表的拜访。 假如没有使用索引,则该列是 NULL。假如想强迫mysql使用或无视possible_keys列中的索 引,在查询中使用 force indexignore index

key_len 列

这一列显示了mysql在索引里使用的字节数,通过这个值可以算出详细使用了索引中的哪些 列。 举例来说,film_actor的结合索引 idx_film_actor_id 由 film_id 和 actor_id 两个int列组成, 并且每个int是4字节。通过结果中的key_len=4可推断出查询使用了第一个列:film_id列来执 行索引查寻。

explain select * from film_actor where film_id = 2;复制代码
image.png

key_len运算规则如下: 字符串

  • char(n):n字节长度
  • varchar(n):2字节储备字符串长度,假如是utf-8,则长度 3n +2

数值类型

  • tinyint:1字节
  • smallint:2字节
  • int:4字节
  • bigint:8字节

时间类型

  • date:3字节
  • timestamp:4字节
  • datetime:8字节

假如字段同意为 NULL,需要1字节记载可否为 NULL

索引最大长度是768字节,当字符串过长时,mysql会做一个相似左前缀索引的处置,将前半部分的字符提取出来做索引。

ref 列

这一列显示了在key列记载的索引中,表查寻值所用到的列或常量,常见的有:const(常 量),字段名(例:film.id)

rows 列

这一列是mysql估量要读取并检测的行数,留意这个不是结果集里的行数。

Extra 列

这一列展现的是额外信息。常见的重要值如下:

(1)Using index :使用覆盖索引

explain select film_id from film_actor where film_id = 1;复制代码
image.png

(2)Using where :使用 where 语句来处置结果,查询的列未被索引覆盖

explain select * from actor where name = 'a';复制代码
image.png

(3)Using index condition :查询的列不完全被索引覆盖,where 前提中是一个前导列的范畴

explain select * from film_actor where film_id > 1;复制代码
image.png

(4)Using temporary :MySQL 需要创立一张暂时表来处置查询。显现这种状况一样是要停止优化的,第一是想到用索引来优化。

  • actor.name没有索引,此时创立了张暂时表来distinct
explain select distinct name from actor;复制代码
image.png
  • film.name创立了idx_name索引,此时查询时extra是using index,没有用暂时表
explain select distinct name from film;复制代码
image.png

(5)Using filesort : 将用外部排序而不是索引排序,数据较小时从内存排序,不然需要在磁盘 完成排序。这种状况下一样也是要思考使用索引来优化的。

  • actor.name没有索引,会阅读 actor 整个表,留存排序关键字 name 和对应的 id,然后排序 name 并检索行记载。
explain select * from actor order by name;复制代码
image.png
  • film.name创立了idx_name索引,此时查询时extra是using index
explain select * from film order by name;复制代码
image.png

(6)Select tables optimized away :使用某些聚合函数(比方 max、min)来拜访存在索引 的某个字段是

explain select min(id) from film;复制代码
image.png

SQL语句优化-索引最好实践

# 示例表CREATE TABLE`employees`(`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
PRIMARY KEY (`id`), KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
 )ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='员工记载表'; 
INSERT INTO employees(name,age,position,hire_time)VALUES('ZhangSan',23,'Manager',NOW());INSERT INTO employees(name,age,position,hire_time)VALUES('HanMeimei', 23,'dev',NOW());INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());复制代码

全值匹配

EXPLAIN SELECT * FROM employees WHERE name= 'ZhangSan';复制代码
image.png
EXPLAIN SELECT * FROM employees WHERE name= 'ZhangSan' AND age = 22;复制代码
image.png
EXPLAIN SELECT * FROM employees WHERE name= 'ZhangSan' AND age = 22 AND position ='manager';复制代码
image.png

最左前缀规则

假如索引了多列,要遵照最左前缀规则。指的是查询从索引的最左前列开端并且不跳过索引中的列。

EXPLAIN SELECT * FROM employees WHERE age = 22 AND position ='manager';复制代码
image.png
EXPLAIN SELECT * FROM employees WHERE position = 'manager';复制代码
image.png
EXPLAIN SELECT * FROM employees WHERE name = 'ZhangSan';复制代码
image.png

不在索引列上做任何操纵

不在索引列上做任何操纵(运算、函数、(主动or手动)类型转换),会致使索引失效而转向全表扫描。

EXPLAIN SELECT * FROM employees WHERE name = 'ZhangSan';EXPLAIN SELECT * FROM employees WHERE left(name,3) = 'ZhangSan';复制代码
image.png

给hire_time增添一个一般索引:

ALTER TABLE `employees`ADD INDEX `idx_hire_time` (`hire_time`) USING BTREE;复制代码
EXPLAIN select * from employees where date(hire_time) ='2020-09-30';复制代码
image.png

转化为日期范畴查询,会走索引:

EXPLAIN select * from employees where hire_time >='2020-09-30 00:00:00' and hire_time <='2020-09-30 23:59:59';复制代码
image.png

复原最初索引状态

ALTER TABLE `employees`DROP INDEX `idx_hire_time`;复制代码

储备引擎不克不及使用索引中范畴前提右侧的列

EXPLAIN SELECT * FROM employees WHERE name= 'ZhangSan' AND age = 22 AND position ='manager';EXPLAIN SELECT * FROM employees WHERE name= 'ZhangSan' AND age > 22 AND position ='manager';复制代码
image.png

尽量使用覆盖索引

尽量使用覆盖索引(只拜访索引的查询(索引列包括查询列)),减少select *语句。

EXPLAIN SELECT name,age FROM employees WHERE name= 'ZhangSan' AND age = 23 AND position ='manager';复制代码
image.png
EXPLAIN SELECT * FROM employees WHERE name= 'ZhangSan' AND age = 23 AND position ='manager';复制代码
image.png

mysql在使用不等于(!=或者<>)的时候没法使用索引会致使全表扫描

EXPLAIN SELECT * FROM employees WHERE name != 'ZhangSan';复制代码
image.png

is null、is not null 也没法使用索引

EXPLAIN SELECT * FROM employees WHERE name is null复制代码
image.png

like以通配符开头('%abc...')mysql索引失效会变成全表扫描操纵

EXPLAIN SELECT * FROM employees WHERE name like '%Zhang'复制代码
image.png
EXPLAIN SELECT * FROM employees WHERE name like 'Zhang%'复制代码
image.png

问题:解决like'%字符串%'索引不被使用的办法?

  • 使用覆盖索引,查询字段必需是创立覆盖索引字段
EXPLAIN SELECT name,age,position FROM employees WHERE name like '%Zhang%';复制代码
image.png
  • 假如不克不及使用覆盖索引则大概需要借助搜索引擎

字符串不加单引号索引失效

EXPLAIN SELECT * FROM employees WHERE name = '1000'; 
EXPLAIN SELECT * FROM employees WHERE name = 1000;复制代码
image.png

少用or或in

少用or或in,用它查询时,mysql不必然使用索引,mysql内部优化器会按照检索比例、 表大小等多个因素团体评估可否使用索引,详见范畴查询优化。

EXPLAIN SELECT * FROM employees WHERE name = 'ZhangSan' or name = 'HanMeimei';复制代码
image.png

范畴查询优化

给年龄增加单值索引

ALTER TABLE`employees`ADD INDEX `idx_age` (`age`)USING BTREE;复制代码
explain select * from employees where age >=1 and age <=2000;复制代码
image.png

没走索引缘由:mysql内部优化器会按照检索比例、表大小等多个因素团体评估可否使用索引。比方这个例子,大概是由于单次数据量查询过大致使优化器终究选中不走索引 优化办法:可以讲大的范畴拆分成多个小范畴。

explain select * from employees where age >=1 and age <=1000;explain select * from employees where age >=1001 and age <=2000;复制代码
image.png

复原最初索引状态:

ALTER TABLE `employees`DROP INDEX `idx_age`;复制代码

索引使用总结

假设 index(a,b,c)

image.png

like KK% 相当于=常量,%KK 和 %KK% 相当于范畴

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有151人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板