MySQL性能优化

因为

  • 数据库出现瓶颈,系统的吞吐量出现访问速度慢
  • 随着应用程序的运行,数据库的中的数据会越来越多,处理时间变长
  • 数据读写速度缓慢

就是咱们说的“性能问题”,程序员一遇到它总是焦头烂额!

优化

  1. like 前导符优化

like模糊查询形如‘%AAA%‘和‘%AAA‘将不会使用索引,但是业务上不可避免可能又需要使用到这种形式。

通常的方法有两种:

优化方案一:

使用覆盖索引,即查询出的列只是用索引就可以获取,而无须查询表记录,这样也走了索引;

优化方案二:

使用locate函数或者position函数代替like查询:如table.field like ‘%AAA%‘可以改为locate(‘AAA‘, table.field) > 0或POSITION(‘AAA‘ IN table.field)>0
  1. in 和 exist

如果查询的两个表大小相当,那么用in和exists差别不大。 如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in: 例如:表A(小表),表B(大表)

示例一:

MySQL性能优化

示例二:

MySQL性能优化

  1. 如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not exist 的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in要

MySQL性能优化

  1. 子查询优化
  • 1、MySQL 5.6 之前的版本对子查询处理:不会将查询的结果集计算出来用作与其他表做join,outer表每扫描一条数据,子查询都会被重新执行一遍。

  • 2、MySQL 5.6 对子查询的处理 :将子查询的结果集 cache 到临时表里,临时表索引主要用来移除重复记录,并且随后也可能用于做join查询,这种技术在 5.6 中叫做物化的子查询,物化子查询可以看到select_type字段为subquery,而在 5.5 里为DEPENDENT SUBQUERY。

  • 3、子查询一般都可以改成表的关联查询,子查询会有临时表的创建、销毁,效率低下。

MySQL性能优化

  1. straight_join

mysql hint:

Mysql 优化器在处理多表的关联的时候,很有可能会选择错误的驱动表进行关联,导致了关联次数的增加,从而使得sql语句执行变得非常的缓慢。

这个时候需要有经验的DBA进行判断,选择正确的驱动表,这个时候 straightjoin 就起了作用了,下面我们来看一看使用straight_join进行优化的案例:

尝试采用user表做驱动表,使用straight_join强制连接顺序:

MySQL性能优化

  1. 高效分页

传统分页

select * from table limit 10000,10

limit原理

(1) Limit 10000,10(2)偏移量越大则越慢

推荐分页

MySQL性能优化

7. 复杂关联sql的优化

  • 1、首先查询返回的结果集,通常查询返回的结果集很少,是有优化的空间的。

  • 2、通过查看执行计划,查看优化器选择的驱动表,从执行计划的rows可以大致反应出问题的所在。

  • 3、搞清各表的关联关系,查看关联字段是否有合适的索引

  • 4、使用straight_join关键词来强制调整驱动表的选择,对优化的想法进行验证。

  • 5、如果条件允许,对复杂的SQL进行拆分。尽可能越简单越好。

8. force index

有时优化器可能由于统计信息不准确等原因,没有选择最优的执行计划,可以人为改变mysql的执行计划,例如:

MySQL性能优化

9. count的优化

按照效率排序的话,count(字段)<count(主键id)<count(1)≈count(*),所以我建议你,尽量使用count(*)

10. 总结

MySQL 性能优化 最主要是理解 innodb 的索引原理及结构及 SQL 的执行计划,在不断累积经验的基础上熟能生巧。

性能提升之force index()

force index() 方法强制使用这个索引

出现这个问题的原因在于 MySQL 每次查询只能使用一个索引, 而你的 SQL 语句 WHERE 条件和 ORDER BY 的条件不一样, 索引没建好的话, 那么 ORDER BY 就使用不到索引, 出现了 Using filesort 问题。

解决这个问题就是建立一个包含 WHERE 和 ORDER BY 条件的混合索引。

比如原来 SQL 语句是:

SELECT * FROM user u where u.id=100 order by u.update_time

而索引是 idx_user_id(id)

现在重新建立索引为 idx_user_id_update_time(id,update_time)

使用 explain 命令查看, 如果 key 使用的是上述新建的 idx_user_id_update_time 索引, 则可以看到 Using file sort 问题消失了如果 key 不是使用新建 idx_user_id_update_time 索引, 可以使用 force index() 方法强制使用这个索引此时 using filesort 问题就解决了。

force index()使用方式:

SELECT * FROM user u force index(idx_user_id_update_time) where u.id=100 order by u.update_time

性能提升之STRAIGHT_JOIN

STRAIGHT_JOIN,在数据量大的联表查询中灵活运用的话,能大大缩短查询时间。

首先来解释下STRAIGHT_JOIN到底是用做什么的:

STRAIGHT_JOIN is similar to JOIN, except that the left table is always read before the right table. 
This can be used for those (few) cases for which the join optimizer puts the tables in the wrong order.

意思就是说STRAIGHT_JOIN功能同join类似,但能让左边的表来驱动右边的表,能改表优化器对于联表查询的执行顺序。

接下来我们举个例子进行大致的分析:

select t1.*
from Table1 t1
inner join Table2 t2
on t1.CommonID = t2.CommonID
where t1.FilterID = 1

以上sql大数据量下执行需要30s,是不是很奇怪?明明Table1表的FilterID字段建了索引啊,Table1和Table2的CommonID也建了索引啊。通过explain来分析,你会发现执行计划中表的执行顺序是Table2->Table1

这个时候要略微介绍下驱动表的概念,mysql中指定了连接条件时,满足查询条件的记录行数少的表为驱动表;如未指定查询条件,则扫描行数少的为驱动表。mysql优化器就是这么粗暴以小表驱动大表的方式来决定执行顺序的

但如下sql的执行时间都少于1s:

select t1.*
from Table1 t1
where t1.FilterID = 1

select t1.*
from Table1 t1
inner join Table2 t2
on t1.CommonID = t2.CommonID

这个时候STRAIGHT_JOIN就派上用场,我们对sql进行改造如下:

select t1.*
from Table1 t1
STRAIGHT_JOIN  Table2 t2
on t1.CommonID = t2.CommonID
where t1.FilterID = 1

用explain进行分析,发现执行顺序为Table1->Table2,这时就由Table1来作为驱动表了,Table1中相应的索引也就用上了,执行时间竟然低于1s了。

分析到这里,必须要重点说下:

  • STRAIGHT_JOIN只适用于inner join,并不使用与left join,right join。(因为left join,right join已经代表指定了表的执行顺序)
  • 尽可能让优化器去判断,因为大部分情况下mysql优化器是比人要聪明的。使用STRAIGHT_JOIN一定要慎重,因为啊部分情况下认为指定的执行顺序并不一定会比优化引擎要靠谱。

MySQL性能优化

上一篇:Mybatis防止SQL注入


下一篇:[20160325]参数resumable_timeout.txt