MySQL调优总结(上)

现在大厂公司越来越注重MySQL调优,不单单只关注公司业务的crud,在完成基本功能的同时,我们就要注重sql语句的优化,让sql语句更高效,所以总结一下日常开发和学习过程中的一些调优经验,希望可以帮到大家,同时也加深下自己对mysql专业的技能,如果有理解或表达不到位的地方,请帮忙指出,相互学习。

Mysql调优的总结将分为上、下两篇文章,从六大方面总结归纳Mysql调优的一些经验,以及Mysql一些关于数据结构的知识点,还有一些底层的基本概念等等。
关于六大优化方面包括:

  1. 性能监控
  2. 数据类型的优化
  3. SQL与的执行计划
  4. 通过索引进行优化
  5. 查询优化
  6. 分库分表

本篇文章为MySQL调优上,先说前三点。
首先在说调优之前,我们先了解一下一些基本知识。
零、基本知识
1.Mysql基本架构如图所示:
MySQL调优总结(上)_第1张图片
如图所示:基本架构分为三大块,第一大块就是客户端Client,第二大部分是 Mysql server,第三大部分是存储引擎。

  1. 客户端发送一个连接到Mysql server(数据库常用的链接池c3p0,DBCP等)
  2. Mysql server通过连接器校验之后会将sql语句发送给分析器,分析器会通过抽象语法树对sql语句做词法分析(本质上一条sql语句就是一个字符串,分析器会通过抽象语法树,对sql语句中的关键词进行拆分)
  3. 将分析后的sql语句提交给优化器,优化器又分为Rbo 基于规则, Cbo 基于成本。
  4. 将优化后的sql语句提交给执行器。
  5. 执行器在提交给存储引擎做sql语句的真正执行。

2.存储引擎分为哪几种
Innodbd、Myisam、memory
MySQL调优总结(上)_第2张图片

特别声明: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类型的特例,平时不会出现

你可能感兴趣的:(mysql优化)