现在大厂公司越来越注重MySQL调优,不单单只关注公司业务的crud,在完成基本功能的同时,我们就要注重sql语句的优化,让sql语句更高效,所以总结一下日常开发和学习过程中的一些调优经验,希望可以帮到大家,同时也加深下自己对mysql专业的技能,如果有理解或表达不到位的地方,请帮忙指出,相互学习。
Mysql调优的总结将分为上、下两篇文章,从六大方面总结归纳Mysql调优的一些经验,以及Mysql一些关于数据结构的知识点,还有一些底层的基本概念等等。
关于六大优化方面包括:
本篇文章为MySQL调优上,先说前三点。
首先在说调优之前,我们先了解一下一些基本知识。
零、基本知识
1.Mysql基本架构如图所示:
如图所示:基本架构分为三大块,第一大块就是客户端Client,第二大部分是 Mysql server,第三大部分是存储引擎。
2.存储引擎分为哪几种
Innodbd、Myisam、memory
特别声明:Innodb和Myisam的底层数据结构索引是B+Tree索引,而memoey底层数据结构索引用的是hash索引。memory存储引擎不支持持久化,只支持单一查询,不支持范围查询,单一查询上速度比另外两个存储引擎效率要高的多。日常开发中用到的memory存储引擎的场景基本较少,本篇文章不再赘述。
废话不多说,开启调优正式章节。
调优的基本原则就是减少IO次数磁盘的读写,来提高效率。
一、性能监测
1.show profile
使用show profile查询剖析工具,可以指定具体的type:
all:显示所有性能信息,show profile all for query n
block io:显示块io操作的次数,show profile block io for query n
context switches:显示上下文切换次数,被动和主动,show profile context switches for query n
cpu:显示用户cpu时间、系统cpu时间,show profile cpu for query n
IPC:显示发送和接受的消息数量,show profile ipc for query n
page faults:显示页错误数量,show profile page faults for query n
source:显示源码中的函数名称与位置,show profile source for query n
swaps:显示swap的次数,show profile swaps for query n
二、 数据类型的优化与索引的选择
1.数据类型的优化
①.在日常开发中数据库表设计的时候,字段选择合适的数据类型,
整型:TINYINT,SMALLINT,MEDIUMINT,INT,BIGINT分别使用8,16,24,32,64位存储空间。
尽量使用满足需求的最小数据类型
②.字符和字符串类型
varchar:
varchar根据实际内容长度保存数据,使用最小的符合需求的长度。栗子:varchar(n)
应用场景:
⑴.适合保存多字节字符,如:汉字,特殊字符等
⑵.存储长度波动较大的数据
char:
char固定长度的字符串,最大长度为255,保存的数据会自动删除末尾的空格,检索效率,写效率 会比varchar高,以空间换时间
应用场景:
⑴.存储长度波动不大的数据,如:md5加密后的等长字符串
⑵.存储短字符串、经常更新的字符串
③.BLOB和TEXT类型
MySQL 把每个 BLOB 和 TEXT 值当作一个独立的对象处理。
两者都是为了存储很大数据而设计的字符串类型,分别采用二进制和字符方式存储。
数据库设计的时候应尽量避免使用该类型,因为占据的硬盘存储空间较大,如果数据量大的话容易导致数据库磁盘空间占用率为100%,其次如果一定要存储的话可以选择varchar类型记录图片或文件的uri。
④.时间类型date、datetime、timestamp
date:
占用3字节,使用date类型还可以利用日期时间函数进行日期之间的计算,date类型用于保存1000-01-01到9999-12-31之间的日期
datetime:
占用8个字节,可保存到毫秒,可保存时间范围大,与时区无关,数据库底层时区配置,对datetime无效
timestamp(时间戳):
占用4个字节,时间范围:1970-01-01到2038-01-19,精确到秒,采用整形存储,依赖数据库设置的时区
这个时间类型格式还需要根据自己项目需求选择。
2.索引的选择
从存储引擎层级划分分为,聚簇索引和非聚簇索引,这里其实不是单独的索引类型,而是存储方式。
从数据类型(索引采用的数据机构)划分分为B+Tree索引和hash索引。
索引的分类:
⑴.主键索引:
⑵.唯一索引:
⑶.普通索引:
⑷.全文索引:
⑸组合索引:
组合索引中又引出了一些技术名词:
Ⅰ.回表:
Ⅱ.覆盖索引:
Ⅲ.最左匹配:
Ⅳ.索引下推:
三、SQL的执行计划
在企业的应用场景中,为了知道优化SQL语句的执行,需要查看SQL语句的具体执行过程,以加快SQL语句的执行效率。可以使用explain+SQL语句来模拟优化器执行SQL查询语句,从而知道mysql是如何处理sql语句的。
官网地址: https://dev.mysql.com/doc/refman/5.5/en/explain-output.html
1、执行计划中包含的信息
Column | Meaning |
---|---|
id | select查询的序列号,包含一组数字,表示查询中执行select子句或者操作表的顺序 |
select_type | 主要用来分辨查询的类型,是普通查询还是联合查询还是子查询 |
table | 对应行正在访问哪一个表,表名或者别名,可能是临时表或者union合并结果集 |
partitions | 匹配的分区 |
type | 显示的是访问类型,访问类型表示以何种方式去访问我们的数据 |
possible_keys | 显示可能应用在这张表中的索引 |
key | 实际使用的索引,如果为null,则没有使用索引 |
key_len | 索引占用的长度 |
ref | 显示索引的哪一列被使用了 |
rows | 根据表的统计信息及索引使用情况,大致估算出找出所需记录需要读取的行数 |
filtered | 按表条件筛选的行百分比 |
extra | 包含额外的信息 |
其中要说一下比较关键的参数
select_type:
select_type Value |
Meaning |
---|---|
SIMPLE | Simple SELECT (not using UNION or subqueries) |
PRIMARY | Outermost SELECT |
UNION | Second or later SELECT statement in a UNION |
DEPENDENT UNION | Second or later SELECT statement in a UNION, dependent on outer query |
UNION RESULT | Result of a UNION. |
SUBQUERY | First SELECT in subquery |
DEPENDENT SUBQUERY | First SELECT in subquery, dependent on outer query |
DERIVED | Derived table |
UNCACHEABLE SUBQUERY | A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query |
UNCACHEABLE UNION | The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) |
栗子:
--simple:简单的查询,不包含子查询和union
explain select * from emp;
--primary:查询中若包含任何复杂的子查询,最外层查询则被标记为Primary
explain select staname,ename supname from (select ename staname,mgr from emp) t join emp on t.mgr=emp.empno ;
--union:若第二个select出现在union之后,则被标记为union
explain select * from emp where deptno = 10 union select * from emp where sal >2000;
--dependent union:跟union类似,此处的depentent表示union或union all联合而成的结果会受外部表影响
explain select * from emp e where e.empno in ( select empno from emp where deptno = 10 union select empno from emp where sal >2000)
--union result:从union表获取结果的select
explain select * from emp where deptno = 10 union select * from emp where sal >2000;
--subquery:在select或者where列表中包含子查询
explain select * from emp where sal > (select avg(sal) from emp) ;
--dependent subquery:subquery的子查询要受到外部表查询的影响
explain select * from emp e where e.deptno in (select distinct deptno from dept);
--DERIVED: from子句中出现的子查询,也叫做派生类,
explain select staname,ename supname from (select ename staname,mgr from emp) t join emp on t.mgr=emp.empno ;
--UNCACHEABLE SUBQUERY:表示使用子查询的结果不能被缓存
explain select * from emp where empno = (select empno from emp where deptno=@@sort_buffer_size);
--uncacheable union:表示union的查询结果不能被缓存:sql语句未验证
type :
显示的是访问类型,访问类型表示以何种方式去访问我们的数据,直接暴力的遍历一张表去寻找需要的数据,效率非常低下,访问的类型有很多,效率从最好到最坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL;一般情况下,得保证查询至少达到range级别,最好能达到ref |
--all:全表扫描,一般情况下出现这样的sql语句而且数据量比较大的话那么就需要进行优化。
explain select * from emp;
--index:全索引扫描这个比all的效率要好,主要有两种情况,一种是当前的查询时覆盖索引,即我们需要的数据在索引中就可以索取,或者是使用了索引进行排序,这样就避免数据的重排序
explain select empno from emp;
--range:表示利用索引查询的时候限制了范围,在指定范围内进行查询,这样避免了index的全索引扫描,适用的操作符: =, <>, >, >=, <, <=, IS NULL, BETWEEN, LIKE, or IN()
explain select * from emp where empno between 7000 and 7500;
--index_subquery:利用索引来关联子查询,不再扫描全表
explain select * from emp where emp.job in (select job from t_job);
--unique_subquery:该连接类型类似与index_subquery,使用的是唯一索引
explain select * from emp e where e.deptno in (select distinct deptno from dept);
--index_merge:在查询过程中需要多个索引组合使用,没有模拟出来
--ref_or_null:对于某个字段即需要关联条件,也需要null值的情况下,查询优化器会选择这种访问方式
explain select * from emp e where e.mgr is null or e.mgr=7369;
--ref:使用了非唯一性索引进行数据的查找
create index idx_3 on emp(deptno);
explain select * from emp e,dept d where e.deptno =d.deptno;
--eq_ref :使用唯一性索引进行数据查找
explain select * from emp,emp2 where emp.empno = emp2.empno;
--const:这个表至多有一个匹配行,
explain select * from emp where empno = 7369;
--system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现