您的位置:首页 > 数据库 > MySQL

MySQL性能优化总结

2016-10-27 08:57 387 查看
优化的几个建议:先从业务角度出发去看待优化问题,从以下方面着手:架构模式、MySQL的配置、SQL语句、索引、分库分表、表结构等进行优化

MySQL引擎介绍

非事务性存储引擎MyISAM
支持三种索引可见MyISAM的读取效率是很高的
1、B-Tree索引

B-Tree索引,顾名思义,就是所有的索引节点都按照balancetree的数据结构来存储,所有的索引数据节点都在叶节点。

MyISAM引擎的实现与Innodb引擎的实现略有差异。Innodb一种是Cluster形式的主键索引,另一种则是和其他存储引擎存放形式(MyISAM引擎)基本相同的普通B-Tree索引,这种索引被称为Secondary Index。两种索引在根节点与分支点一样,但是在叶子节点上主键索引不仅仅 包括主键字段的数据,还包括其他字段的数据,整个数据以主键值有序的排列。Secondaty
Index与B-tree索引的区别是除了存放索引建的相关信息外,还存放了Innodb的主键值。

所以在Innodb中如果通过主键来访问数据效率非常高,而通过SecondaryIndex来访问数据的,通过索引建检索到叶子节点之后,再通过叶子节点存放的主键,访问主键索引中存放的数据。

对于MyISAM来说,主键索引和非主键索引差别很小,只不过是主键索引的索引建是一个唯一且非空的建而已。存储结构与SecondaryIndex的存储结构相似,但是在叶子节点中除了存放索引建信息之外,在存放MyISAM数据文件中相应的数据行信息,但不会存放主键。
2、R-Tree索引
R-Tree索引的存储方式和b-tree索引有一些区别,主要设计用于为存储空间和多维数据的字段做索引,解决空间数据检索的问题,所以目前的MySQL版本来说,也仅支持geometry类型的字段作索引。
3、Full-text索引
Full-text索引就是我们长说的全文索引,他的存储结构也是b-tree。主要是为了解决在我们需要用like查询的低效问题。
目前仅有MyISAM存储引擎支持,仅有CHAR,VARCHAR和TEXT这三种数据类型的列可以建FullText索引,对于模糊匹配度查找有了更高的支持。
4.hash索引
用到的hash索引的数据库较少,不在这里做详细介绍.

事务性存储引擎InnoDB
特点
1、支持事务安装

2、数据多版本读取
3、锁定机制的改进(行锁定机制,高并发的情况下增加读写性能)

4、实现外键(保证数据库的完整性)
补充:针对Innodb的行锁级优化,尽可能让所有的数据检索都通过索引来完成,从而避免Innodb无法通过索引建加锁,从而升级为表锁定。尽可能减少基于范围的数据检索的过滤条件,避免间隙锁锁定了不该锁定的记录。尽量控制事务的大小,减少锁定的资源量与锁定时间的长度、

二者数据库引擎比较:

在 MySQL 中有两个存储引擎 MyISAM 和 InnoDB,每个引擎都有利有弊。
MyISAM 适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。
InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。

其它存储引擎

Merge、BDB、BLACKHOLE等引擎

索引相关

合理创建索引:

1、表的主键、外键必须有索引;

2、数据量超过300的表应该有索引;

3、经常与其他表进行连接的表,在连接字段上应该建立索引;

4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;

5、索引应该建在选择性高的字段上;

6、索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;

7、复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:

A、正确选择复合索引中的主列字段,一般是选择性较好的字段;

B、复合索引的几个字段是否经常同时以AND方式出现在Where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引;

C、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;

D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段;

E、如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;

8、频繁进行数据操作的表,不要建立太多的索引;
9、删除无用的索引,避免对执行计划造成负面影响;

在分析语句之前我们需要在slow_querry_log的日志中查找相关的SQL语句,这样比较有针对性。
结合配置:根据实际的业务需要设定慢查询的时间,然后开启慢查询为ON。
注意:开启慢查询日志可能会消耗大量的磁盘空间,如果长期开启慢查询日志,注意要部署日志轮转工具,或者不要长期启用慢查询日志。
分析日志的工具推荐一个:percona toolkit
macOS下homebrew直接安装,命令使用 pt-query-digest

使用EXPLAIN分析语句,还可以执行SET profiling = 1;在服务器上执行所有的语句都会被记录,查看调用 SHOW PROFILES;SHOW PROFILE FOR QUERY 1;这样就可以看到Query_id为1的相信的信息,SHOW STATUS 本省也会创建一个临时表,而且

EXPLAIN分析SQL语句列字段的解释
1、id
语句的执行顺序标识,如果在语句中没有子查询或联合,说明只有一个SELECT,于是这个列显示为1,否则内层的SELECT会顺序编号.

 

2、select_type
显示了对应的查询是简单还是复杂SELECT,主要有以下几种查询类型
1)、simple 简单类型
语句中没有子查询或union

2)、primary

 最外层的select ,不是主键
 3)、union
union是在select 语句中第二个select语句后面所有的select,第一个select 为primary 
 4)、dependent subquery

子查询中内层中第一个select语句

 5)、dependent  union
 子查询中union且为union中第二个select开始的后面所有select,依赖于外部的结果集。

6)、SUBQUERY

 子查询内层查询的第一个SELECT,结果不依赖于外部查询结果集。
7)、devived 
派生表的查询语句
8)、uncacheable subquery 
  结果集无法缓存的子查询
9)、union result 
  union中合并的结果

3、table 
1)、显示对应行正在访问哪个表

2)、当FROM子句中有子查询或UNION时,table列是<derivedN>,其中N是id列对应的值

 
4、type 
这列很重要,显示了连接使用了哪种类别,有无使用索引。主要包括以下几种类型
1)、all
全表扫描,效果是最不理想的。
2)、const
const是在where条件以常量作为查询条件,最多只会有一条记录匹配,由于是常量,实际上只须要读一次。
3)、eq_ref
最多只会有一条匹配结果,一般是通过主键或唯一键索引来访问。一般会出现在连接查询的语句中。
4)、fulltext
进行全文索引检索。
5)、index
全索引扫描。MySQL在扫描表时按索引次序进行而不是行。
6)、index_merge
查询中同时使用两个(或更多)索引,然后对索引结果进行合并(merge),再读取表数据。
7)、index_subquery
子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或唯一索引。
8)、rang
索引范围扫描。一个有限制的索引扫描,它开始于索引里的某一点,返回匹配这个值域的行(显而易见的范围扫描.即带有BETWEEN或在WHERE子句中带有>的查询,当MySQL使用索引去查找一系列值的时候,如IN()和OR列表,也为显示的范围扫描)
9)、ref
也叫索引查找,他返回所有匹配某单个值的行,它可能会找到多个符合条件行。
10)、ref_or_null
与ref的唯一区别就是在使用索引引用的查询之外再增加一个空值的查询。
11)、system
系统表,表中只有一行数据;
12)、unique_subquery
子查询中的返回结果字段组合是主键或唯一约束。

5、possible_keys
这一列显示了查询可以使用哪些索引,是基于查询访问的列和使用的比较操作符来判断的.如果没有任何索引可以使用,就会显示成null

6、key
显示了MySQL决定采用哪个索引来优化对该表的访问

7、key_len
1)、key_len列显示mysql决定使用的键长度,如果键是null,则长度为null。
2)、显示MySQL在索引里使用的字节数.举个例子就是在查询中使用到了主键,而主键的数据类型为INT,则为4,SMALLINT则为2
3)、使用的索引长度,一般越短越好。
 
8、Ref
显示了之前的表在key列记录的索引中查询值所用到的列或常量。

9、rows
显示的是MySQL为了找到所需的值而要读取的行数.

10、extra
在此显示的是在其他列不适合显示的额外信息,主要可能会是以下内容:
1)、Distinct
查找distinct 值,当mysql找到了第一条匹配的结果时,将停止该值的查询,转为后面其他值查询。
2)、Full scan on NULL key
子查询中的一种优化方式,主要在遇到无法通过索引访问null值的使用。
3)、Using index
MySQL将使用覆盖索引,以避免访问表(就是仅仅使用了索引中信息而没有读取表中)
4)、Using where
意味着MySQL服务器将在存储引擎检索行后在进行过滤(将会通过WHERE条件来筛选存储引擎返回的记录)
5)、Using temporary
看到这个的时候,查询就需要优化了。意味着MySQL在对查询结果排序时会用到一个临时表.
6)、Using filesort
看到这个的时候,查询就需要优化了。意味着MySQL会对结果使用一个外部索引排序,而不是按索引次序从表里读出来.

索引的优点,提高查询效率,降低数据的IO成本。但是其也同样带来了一些问题,更新数据时会更新索引信息,在插入数据时索引也会占用一定的存储空间。所以在建立索引时我们应该如何创建索引。

创建索引:
1.较为频繁的作为查询条件的字段,应该创建索引
2.唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件,例如性别
3.更新非常频繁的字段不适合创建索引,注意非常频繁的的定义应该是,查询与更新的比率。
4.不会再WHERE子句中的字段不该创建索引
5.组合索引与单键索引,组合索引当中不应当包含主键,(组合索引更适合并发量高的情况,更高的IO情况)
6.对于单键索引,尽量选择针对当前 Query 过滤性更好的索引;
7.在选择组合索引的时候,当前 Query 中过滤性最好的字段在索引字段顺序中排列越靠前越好;
8.在选择组合索引的时候,尽量选择可以能够包含当前 Query 的 WHERE 子句中更多字段的索引;

使用索引,避免全表扫描:
1. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null.
2. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
MySQL只有对以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些时候的LIKE。可以在LIKE操作中使用索引的情形是指另一个操作数不是以通配符(%或者_)开头的情形。例如,“SELECT idFROM t WHERE col LIKE 'Mich%';”这个查询将使用索引,但“SELECT
id FROM t WHERE col  LIKE '%ike';”这个查询不会使用索引。
3.尽量避免子查询Join查询,子查询很难得到很好的执行计划,mysql会在下一版本中进行优化。越复杂的join查询会锁定的资源也会越多,这也就体现了Innodb在高并发时优越的特性。
4.优化查询语句orderBy()这样的排序应该在索引上进行排序,避免groupBy语句带来的建立临时表额外的IO开销.
5.join语句中join条件字段类型不一致的时候无法使用索引

优化数据库的表结构
第三范式与反范式
首先解释一下第一范式与第二范式的含义:
第一范式:原子性 字段不可再分,否则就不是关系数据库
第二范式:唯一性 一个表只说明一个事物
1.为什么不选择第一二范式,第三范式的满足就包含了第一二范式。
2.一般数据库中表结构的设计符合第三范式。
3.第三范式的含义,每列都与主键有直接关系不存在传递依赖。

假设我们设计了一张活动相关的表 user(id,user_name,create_time,activity_id,activity_name) 可以看出user_name,create_time,activity_id依赖于id,但是activity与id的关系是由activity_id联系起来的,这就叫做传递依赖。因此在设计表时我们需要将这样的表拆分成两张表user(id,user_name,create_time,activity_id),activity(activity_id,activity_name)
这样符合了第三范式设计的模式.表结构清晰,唯一性与原子性都满足.

反范式的设计模式

反范式的设计是牺牲存储数据的空间,因为会有很多冗余的数据被存储,但是查询效率较高,避免过多的表关联延长查询时间。言而总之这样的设计目的,是用空间置换时间。根据不同的业务需求制定自己的表结构设计模式,这也是对于数据库来说也是一种优化。在上面的例子中,直接这样设计表user(id,user_name,create_time,activity_id,activity_name)
称为反范式设计,虽然我们每次得存储多余的字段activity_name,但是查询的时候根据id我们就可以从一个表中得到很多的信息。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  MySQL