14.MySQL 优化
目录
2、执行完上述命令之后,再执行show profiles 指令, 来查看SQL语句执行的耗时:
3、通过show? profile for? query? query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间:
概述
????????优化方式:
????????????????分别从 设计、查询、索引、存储 上优化
查看sql执行频率
-- SQL的优化
insert into account values(3,'wangwu',1000);
-- 查看当前会话SQL执行类型的统计信息
show session status like 'Com______';
-- 查看全局(自从上次MySQL启动至今)执行类型的统计信息
show global status like 'Com______';
-- 查看针对innodb引擎的统计信息
show status like 'Innodb_rows_%';
定位 低效率执行的SQL
慢查询日志
通过慢查询日志定位执行效率低的SQL语句
-- 查看慢日志配置信息
show variables like '%slow_query_log%';
-- 开启慢日志查询
set global slow_query_log=1;
-- 查看慢日志记录sql的最低阈值时间 默认执行时间>=10s,就会被记录在慢日志中
show variables like 'long_query_log%';
-- 修改慢日志记录sql的最低阈值时间,修改的是本会话的最低阈值时间,如果想修改全局,修改ini文件
set global long_query_log=4;
show processlist
查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时的查看sql的执行情况,同时对一些锁表操作进行优化
Explain 分析执行计划
Explain 之 id
- id字段是select查询的序列号,是一组数字,表示的是查询中执行select子句或者是操作表的顺序。id情况有三种:
- id相同表示加载表的顺序是从上到下。
- id不同id值越大,优先级越高,越先被执行。
- id有相同,也有不同,同时存在。id相同的可以认为是一组,从上往下顺序执行;在所有的组中,id的值越大,优先级越高,越先执行。
-- Explain 之 id
-- id相同表示加载表的顺序是从上到下。
explain select * from user u, user_role ur, role r where u.uid = ur.uid and ur.rid = r.rid ;
-- id不同id值越大,优先级越高,越先被执行。
explain select * from role where rid = (select rid from user_role where uid = (select uid from user where uname = '张飞'));
-- id有相同,也有不同,同时存在。id相同的可以认为是一组,从上往下顺序执行;在所有的组中,id的值越大,优先级越高,越先执行
explain select * from role r , (select * from user_role ur where ur.uid = (select uid from user where uname = '张飞')) t where r.rid = t.rid ;
Explain 之 select_type
select_type的取值
-- Explain 之 select_type
-- simple:没有子查询和union
explain select * from user;
-- primary:主查询,也就是子查询中的最外层查询
explain select * from role where rid = (select rid from user_role where uid = (select uid from user where uname = '张飞'));
-- subquery:在select和where中包含子查询
explain select * from role where rid = (select rid from user_role where uid = (select uid from user where uname = '张飞'));
-- derived:在from中包含子查询,被标记为衍生表
explain select * from (select * from user limit 2) t;
-- union
-- union result 联合表
explain select * from user where uid = 1 union select * from user where uid = 3;
?Explain 之 type
type显示的是访问类型,是较为重要的一个指标
type的取值
结果值从最好到最坏以此是:system > const > eq_ref > ref > range > index > ALL
Explain 之 其他指标字段
Explain 之 table
显示这—步所访问数据库中表名称有时不是真实的表名字,可能是简称,
?
Explain 之 rows
扫描行的数量。
?
Explain 之 key
possible_keys :显示可能应用在这张表的索引,一个或多个。
key :实际使用的索引,如果为NULL,则没有使用索引。
key_len :表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好。
Explain 之 extra
其他的额外的执行计划信息,在该列展示。
show profile 分析SQL
- Mysql从5.0.37版本开始增加了对 show profiles 和 show profile 语句的支持。show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了
了解SQL执行的过程
1、我们可以执行一系列的操作
2、执行完上述命令之后,再执行show profiles 指令, 来查看SQL语句执行的耗时:
3、通过show? profile for? query? query_id 语句可以查看到该SQL执行过程中每个线程的状态和消耗的时间:
4、在获取到最消耗时间的线程状态后,MySQL支持进一步选择all、cpu、block io 、context switch、page faults等明细类型类查看MySQL在使用什么资源上耗费了过高的时间。例如,选择查看CPU的耗费时间? :
trace分析优化器执行计划
- ??MySQL5.6提供了对SQL的跟踪trace, 通过trace文件能够进一步了解为什么优化器选择A计划, 而不是选择B计划
执行步骤
????????1、打开trace , 设置格式为 JSON,并设置trace最大能够使用的内存大小,避免解析过程中因为默认内存过小而不能够完整展示。
????????2、执行SQL语句 :
????????3、最后, 检查?information_schema.optimizer_trace?就可以知道MySQL是如何执行SQL的 :
优化
索引优化
????????索引是数据库优化最常用也是最重要的手段之一, 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。
避免索引失效应用
全值匹配
该情况下,索引生效,执行效率高。
-- 创建组合索引
create index idx_seller_name_sta_addr on tb_seller(name,status,address);
-- 全值匹配 和字段匹配成功即可,与字段无关
explain select * from tb_seller where name='小米科技' and status='1' and address='北京市';
explain select * from tb_seller where status='1' and name='小米科技' and address='北京市';
最左前缀法则
从左边第一个开始,逐个配对
-- 最左前缀法则
-- 如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。
explain select * from tb_seller where name='小米科技'; -- 403
?
explain select * from tb_seller where name='小米科技' and status='1'; -- 410
explain select * from tb_seller where status='1' and name='小米科技'; -- 410
-- 违法最左前缀法则 , 索引失效:
explain select * from tb_seller where status='1'; -- nulll
?
-- 如果符合最左法则,但是出现跳跃某一列,只有最左列索引生效:
explain select * from tb_seller where name='小米科技' and address='北京市'; -- 403
其他匹配原则 -- 1
-- 范围查询(status >'1')右边的列,不能使用索引 。
explain select * from tb_seller where name='小米科技' and status >'1' and address='北京市’;
-- 不要在索引列上进行运算操作, 索引将失效。
explain select * from tb_seller where substring(name,3,2)='科技’
-- 字符串不加单引号,造成索引失效。
explain select * from tb_seller where name='小米科技' and status = 1 ;
-- 1、范围查询右边的列,不能使用索引 。
-- 根据前面的两个字段name , status 查询是走索引的, 但是最后一个条件address 没有用到索引。
explain select * from tb_seller where name='小米科技' and status >'1' and address='北京市';
?
-- 2、不要在索引列上进行运算操作, 索引将失效。
explain select * from tb_seller where substring(name,3,2)='科技'
?
-- 3、字符串不加单引号,造成索引失效。
explain select * from tb_seller where name='小米科技' and status = 1 ;
?
-- 4、尽量使用覆盖索引,避免select *
-- 需要从原表及磁盘上读取数据 -- 效率低
explain select * from tb_seller where name='小米科技' and address='北京市'; -- 效率低
?
-- 从索引树中就可以查询到所有数据
explain select name from tb_seller where name='小米科技' and address='北京市'; -- 效率高
explain select name,status,address from tb_seller where name='小米科技' and address='北京市'; -- 效率高
-- 如果查询列,超出索引列,也会降低性能。
explain select name,status,address,password from tb_seller where name='小米科技' and address='北京市'; -- 效率低
-- 尽量使用覆盖索引,避免select *
-- 需要从原表及磁盘上读取数据
explain select * from tb_seller where name='小米科技' and address='北京市'; -- 效率低
?
-- 从索引树中就可以查询到所有数据
explain select name from tb_seller where name='小米科技' and address='北京市'; -- 效率高
explain select name,status,address from tb_seller where name='小米科技' and address='北京市'; -- 效率高
-- 如果查询列,超出索引列,也会降低性能。
explain select name,status,address,password from tb_seller where name='小米科技' and address='北京市'; -- 效率低
-- 用or分割开的条件, 那么涉及的索引都不会被用到。
explain select * from tb_seller where name='黑马程序员' or createtime = '2088-01-01 12:00:00';
explain select * from tb_seller where name='黑马程序员' or address = '西安市';
explain select * from tb_seller where name='黑马程序员' or status = '1';
?
-- 以%开头的Like模糊查询,索引失效。
explain select * from tb_seller where name like '科技%'; -- 用索引
explain select * from tb_seller where name like '%科技'; -- 不用索引
explain select * from tb_seller where name like '%科技%';-- 不用索引
-- 弥补不足,不用*,使用索引列
explain select name from tb_seller where name like '%科技%';
其他匹配原则 -- 2
-- 1、如果MySQL评估使用索引比全表更慢,则不编辑
-- 2、is NULL , is NOT NULL有时有效,有的索引失效。
-- 3、 in走索引,not in索引失效。
-- 4、单列索引和复合索引,尽量使用复合索引
?
-- 1、如果MySQL评估使用索引比全表更慢,则不使用索引。
-- 这种情况是由数据本身的特点来决定的
create index index_address on tb_seller(address);
?
explain select * from tb_seller where address = '北京市'; -- 没有使用索引
explain select * from tb_seller where address = '西安市'; -- 没有使用索引
?
?
-- 2、is NULL , is NOT NULL 有时有效,有时索引失效。
create index index_address on tb_seller(nickname);
explain select * from tb_seller where nickname is NULL; -- 索引有效
explain select * from tb_seller where nickname is not NULL; -- 无效
-- 3、 in走索引,not in索引失效。--普通索引
explain select * from tb_seller where nickname in('阿里小店', '百度小店');--使用索引
explain select * from tb_seller where nickname not in('阿里小店','百度小店');--不使用索引
--主键索引
explain select * from tb_seller where sellerid in( 'alibaba' , 'baidu'); --使用索引explain select * from tb_seller where sellerid not in( 'alibaba' , 'baidu' ); --使用索引
-- 4、单列索引和复合索引,尽量使用复合索引
create index idx_seller_name_sta_addr on tb_seller(name,status,address);
/*
等价于:
name
name + status
name + status + address
*/
--如果一张表有多个单列索引,即使where中都使用了这些索引列,则只有一个最优索引生效
-- 最优索引由优化器决定
大批量数据加载优化
当使用load 命令导入数据的时候,适当的设置可以提高导入的效率。对于 InnoDB 类型的表,有以下几种方式可以提高导入的效率:
1、?主键顺序插入
????????因为InnoDB类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。
????????如果InnoDB表没有主键,那么系统会自动默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这点,来提高导入数据的效率。
-- 1、首先,检查一个全局系统变量 'local_infile' 的状态, 如果得到如下显示 Value=OFF,则说明这是不可用的
show global variables like 'local_infile';
?
-- 2、修改local_infile值为on,开启local_infile
set global local_infile=1;
?
-- 3、加载数据
-- 结论 当通过load向表中加载数据时,尽量保证文件中的主键有序,这样可以提高执行效率
/*
脚本文件介绍 :
sql1.log ----> 主键有序
sql2.log ----> 主键无序
*/
-- 主键有序 -22.617s
load data local infile 'D:\\sql_data\\sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n';
-- 主键无序 - 81.739s
load data local infile 'D:\\sql_data\\sql2.log' into table tb_user fields terminated by ',' lines terminated by '\n';
2、关闭唯一性校验
????????在导入数据前执行 SET UNIQUE_CHECKS=0,关闭唯一性校验,
????????在导入结束后执行 SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率。
-- 关闭唯一性校验
SET UNIQUE_CHECKS=0;
?
truncate table tb_user;
load data local infile 'D:\\sql_data\\sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n';
?
SET UNIQUE_CHECKS=1;
DML优化
优化 insert 语句
1、如果需要同时对一张表插入很多行数据时,应该尽量使用多个值表的insert语句,这种方式将大大的缩减客户端与数据库之间的连接、关闭等消耗。使得效率比分开执行的单个insert语句快。
2、在事务中进行数据插入
3、数据有序插入
DQL优化
优化 order by 语句
第一种是通过对返回数据进行排序,也就是通常说的 filesort 排序,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。
?第二种通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要额外排序,操作效率高。?
-- 排序, order by
explain select * from emp order by age; -- Using filesort
explain select * from emp order by age,salary; -- Using filesort
explain select id from emp order by age; -- Using index
explain select id,age from emp order by age; -- Using index
explain select id,age,salary, name from emp order by age;-- Using filesort
-- order by后边的多个排序字段要求尽量排序方式相同
explain select id,age from emp order by age asc, salary desc; -- Using index; Using filesort
explain select id,age from emp order by age desc, salary desc;-- Backward index scan;Using index
-- order by后边的多个排序字段顺序尽量和组合索引字段顺序一致
explain select id,age from emp order by salary,age; -- Using index; Using filesort
Filesort 的优化
通过创建合适的索引,能够减少 Filesort 的出现,但是在某些情况下,条件限制不能让Filesort消失,那就需要加快 Filesort的排序操作。对于Filesort , MySQL 有两种排序算法:
1) 两次扫描算法 :MySQL4.1 之前,使用该方式排序。首先根据条件取出排序字段和行指针信息,然后在排序区 sort buffer 中排序,如果sort buffer不够,则在临时表 temporary table 中存储排序结果。完成排序之后,再根据行指针回表读取记录,该操作可能会导致大量随机I/O操作。
2)一次扫描算法:一次性取出满足条件的所有字段,然后在排序区 sort? buffer 中排序后直接输出结果集。排序时内存开销较大,但是排序效率比两次扫描算法要高。
????????MySQL 通过比较系统变量 max_length_for_sort_data 的大小和Query语句取出的字段总大小, 来判定是否那种排序算法,如果max_length_for_sort_data 更大,那么使用第二种优化之后的算法;否则使用第一种。
????????可以适当提高 sort_buffer_size? 和 max_length_for_sort_data? 系统变量,来增大排序区的大小,提高排序的效率。
子查询 优化
- 多表查询的效率高于子查询
优化 limit 语句
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!