MySQL优化

1. 性能下降原因:查询语句没写好;索引失效;关联太多join;服务器参数设置不合理(JoinBuffer大小,SortBuffer大小,最大连接数);mysql的瓶颈:(CPU饱和:一般发生在数据装入内存或者从磁盘上读取数据的时候;磁盘IO瓶颈:一般发生在装入数据远大于内存容量的时候;服务器(linux)硬件性能的瓶颈:top,free,iostat和vmstat来查看系统的性能状态)

2. 使用 join 时应该遵循小数据集驱动大数据集(小表驱动大表)的原则因为mysql的join是使用嵌套循环(nested loop)实现的,假设A表5条数据,B表1000条数据,用A连接B,则只需要连接5次,而B 连接A 则需要连接1000次。(类似java代理里面循环次数少的放在外面,循环次数多的放在里面)

3. sql执行顺序:mysql执行的时候首先从from后面开始,然后按照下图的顺序执行

4. 索引:索引是帮助MySQL高效获取数据的一种数据结构,即索引的本质是数据结构。

5. 索引的原理:索引分为单值索引,唯一索引,复合索引,我们通常使用的索引一般都是B树(多路搜索树,不一定二叉树)结构组织的索引。

6. 索引的优缺点:
 优点:使用索引查询可以提高数据检索效率,降低数据库IO成本;使用索引排序可以降低数据排序的成本,降低了CPU的消耗。

 缺点:索引实际上也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引也会占用空间,虽然索引大大提高了查询速度,但是会降低表的更新速度,例如执行insert,update,delete操作时除了更新表数据,还需要更新索引。

7. 适合创建索引的情况:

(1).主键自动建立唯一索引

(2).频繁作为查询条件的字段应该创建索引

(3).查询中与其他表关联的字段,外键关系建立索引

(4).查询中排序的字段可以建立索引,如果排序字段通过索引访问将会大大提高排序速度

(5).查询中统计或者分组字段,应该建立索引

(6).尽量建立复合索引而不是单值索引(高并发环境下倾向创建复合索引)

8. 不适合创建索引的情况:

(1).表的记录太少

(2).频繁更新的字段不适合建立索引(维护成本较高),或者经常增删改的表不适合建立索引

(3).数据重复且分布平均的表字段不适合建立索引(效果不大,例如学生表的性别,国籍字段,前者只有两个值,后者几乎只有一个值)

9. 通过explain查看sql执行计划,我们可以获得以下信息:表的读取顺序(id),数据读取操作的操作类型(select_type),哪些索引被使用(possible_keys,key),表之间的引用关系(table),以及每张表有多少行被查询优化器查询(rows)。具体含义如下:

(1). id : select 查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序:如果id相同,执行顺序自上至下;如果id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行。

(2). select_type : 查询的类型,主要用于区别普通查询,联合查询,子查询等复杂的查询。有以下可能值:simple,primary,subquery,derived,union,union result。

simple:简单查询,不包含子查询和union;
primary:查询中若包含任何复杂的子部分,最外层的查询被标记为primary;
subquery:select或者where中有子查询;
derived:from中有子查询;
union:union之后的查询;
union result:从union表获取结果的select

(3). table :显示这一行的数据来自哪张表
(4). type : 显示查询使用了哪种访问类型,从最好到最差依次为:system>const>eq_ref>ref>range>index>All。一般来说,要保证查询至少达到range级别,最好达到ref级别

system : 表只有一行记录,const类型特例,基本不会出现;
const : 表示索引依次就找到了。const用于比较primary key或者unique索引。 因为只匹配一行数据,所以能很快找到,例如将主键置于where条件中,mysql就能将查询转换为一个常量;
eq_ref : 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主键或唯一性索引扫描;
ref : 非唯一性索引扫描,返回匹配某个单独值的所有行;
range :检索给定范围。一般出现在where字句中有between,<,>,in等的查询;
index : full index scan,遍历全部索引。虽然和下面出现的All都会扫描全表,但是因为索引文件通常都比数据小,而且index是从索引文件中读取的,而All是从硬盘中读取的;
all : full table scan 

(5).possible_keys : 可能用在这张表中的索引,查询的字段上存在索引就会被列出来
(6).key : 实际使用的索引查询中如果使用了覆盖索引,则该索引和查询的字段重合
(7).key_len:索引使用的字节数
(8).ref:显示查询的哪一列用到了索引,可能是一个常数或者表的某一个字段。哪些列或常量被用于查找索引列上的值
(9).rows:根据表统计信息以及索引使用情况,大致算出找到所需的记录所需要读取的行数
(10).Extra:额外的重要信息。有以下可能值:  

using filesort:无法利用索引完成的排序,出现这种情况很影响性能
using temporary:使用了临时表保存中间结果,对查询结果排序的时候使用了临时表,常见于order by和group by,十分影响性能,必须优化
using index:使用了覆盖索引(select查询的字段的个数和顺序与缩建立的复合索引的字段和个数一一一致),避免访问了数据行,效率不错
using where:使用了where过滤
using join buffer:使用了连接缓存--可以通过调整join buffer size 优化

[注]覆盖索引:select的数据列只从索引中就可以得到,不必读取数据行,利用索引返回表中的数据字段。即查询的列被所建的索引覆盖。
如果使用覆盖索引,一定要注意select表中只取出所需要的列,不可select * 

10. 索引优化:

 (1).全职匹配:where条件中的字段顺序与建立的索引列顺序相同且最好个数一致。
 (2).最佳左前缀原则:如果查询了多列,查询应该从索引的最左前列开始并且不要不要跳过索引中的列
 (3).不在索引上做任何操作(计算,函数,类型转换(自动或手动)),否则会导致索引失效而转向全表扫描
 (4).存储引擎不能使用索引中范围条件右边的列
 (5).尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少或避免select *
 (6).mysql在使用不等于(!=或者<>),is null,is not null 的时候无法使用索引会导致全表扫描
 (7).like以通配符开头(like "%abc")会导致索引失效,但是百分号结尾不会(like "abc%"),解决like "%"开头的可以使用覆盖索引解决
 (8).字符串不加引号会导致索引失效
 (9).少用or,用它来连接会导致索引失效
 (10).使用group by需谨慎,因为分组之前必先排序,有可能会导致临时表的产生
 (11).当使用A表left join B表时,如连接条件为A.id = B.id,则索引应该建立在B表的id字段,如果为右连接则应该建立在B.id

 总结成口诀如下:
  全职匹配我最爱,最左前缀要遵守;带头大哥不能死,中间兄弟不能断;索引列上少计算,范围之后全失效;
  like百分写右边,覆盖索引不写星;不等控制还有or,索引失效要少用; varchar引号不可丢,SQL高级也不难。

11. sql优化步骤:发现系统变慢 --> 通过慢查询日志抓取慢sql  -->  explain分析 -->  优化索引与查询语句 。

如果问题还没解决,使用show profile查看更加细粒度的sql执行时的资源消耗情况,如果问题仍未解决,则需要判断是否mysql服务器问题,根据情况对各种影响性能的参数进行调优和更改。

原文地址:https://www.cnblogs.com/pepper7/p/7091049.html