原本应该先发这篇的,如今才发现漏掉了mysql
1.开发人员具有必定的SQL优化基本功ios
2.在开发阶段,每条写的SQL在测试环境看看他的执行计划sql
3.上线后让DBA收集查询比较慢的SQL数据库
4.经过explain工具和show profile 分析慢SQL,修改代码,从新上线,从新收集。若是贵公司的DBA关系和你很好,在优化的时候能够拉他一块儿,多学点理论和经验oracle
5.数据库参数调优工具
6.操做系统调优测试
7.更换硬件设备优化
MySQL有专门负责SELECT的优化器模块,根据先前收集到的统计信息,为SQL生成一条它认为最优的执行计划,但该计划不必定是DBA认为最优的。也就是说它有可能根据错误的统计信息生成了自认为合理的执行计划。这种时候须要DBA介入,重建索引——》从新收集统计信息,这样MySQL才可能按照真正最优的方式运行,若是MySQL仍是不能生成想要的执行计划,DBA还能够固化执行计划spa
使用top、free、iostat、vmstat命令查看机器的硬件资源负载状况操作系统
执行计划是MySQL对SQL的执行生成的一套优化策略,以效率为首要目的,提高SQL执行的速度
能够在MySQL中使用explain SQL或者desc SQL来生成执行计划,如:
有了执行计划能干吗?
1.查看表的读取顺序
2.数据读取操做的操做类型
3.那些索引能够被使用
4.实际使用了那些索引
5.表之间的引用
6.每张表有多少行被优化器查询
若是ID相同,执行顺序由上而下;
若是ID不一样,执行顺序是ID越大越先执行,为何喃,越早缩小结果集对整个执行越有效,由于过滤的数据量更少,IO次数越少,CPU消耗越低
若是ID相同与不一样同时存在,则先执行ID大的,ID相同的则按照顺序执行
其中的derived2中的2就是id=2
取值范围
ID | select_type | |
---|---|---|
1 | simple | |
2 | primary | |
3 | subquery | |
4 | derived | |
5 | union | |
6 | union result |
用于指明这个SQL是一个什么类型的查询语句,简单查询、复合查询、嵌套查询
simple:
sql中不包含子查询或union
primary:
查询中若包含任何复杂的子查询,则最外层就被标记为primary
subquery:
在select或者where部分中包含的查询就被称为子查询
dependent subquery:
相关子查询,MySQL遇到这种状况,不会先将子查询的结果集找出来再匹配,而是从外部表拿到每个关联的值到子查询表去找捞数据,不少同窗常用的in,不论是在oracle仍是mysql都不推荐使用in(subquery),可使用join来代替
derived:
在from部分包含的第一个完整查询,其结果为被放在临时表,在执行计划中被标记为derived(衍生)
union:
在from部分union关键字后面的查询都会被标记为union
depentent union:
相关子查询合并的结果集
union result:
在from部分全部查询union的结果被标记为union result
经过下图能够看到一个比较全的执行计划
SQL:该SQL只是为了演示执行计划,不要去扣里面的写法是否合理
explain select * from (select * from tb_item a union select * from tb_item b union select * from tb_item c) d join tb_order_item b on d.id = b.item_id where d.id in( select id from tb_item a1 union select id from tb_item b1 union select id from tb_item c1 );
就是这一步使用到的表名字,多是实际的表名,也多是MySQL处理过程当中的中间表别名,如derivedxxx或者unionxxx
显示查询使用了什么类型,最好的结果顺序是system>>const>>eq_ref>>ref>>range>>index>>all,在实际的开发和生产维护中,可以作到eq_ref是最好,达到ref级别彻底OK,尽可能减小index和all两种状况出现。若是出现本身解决不了,找DBA或者你的项目经理帮忙
1.system
一张表只有一行记录,实际系统中应该不多出现这种状况,若是有我估计也是什么配置,可是这种状况彻底能够写到配置文件,或者ZK、REDIS中
2.const
表示经过索引一次就找到,好比
explain select * from tb_item_cat where id = 1;
id是表tb_item_cat的主键,因此id=1一次查询只能找到一行记录。不管条件如何,必需要返回一行,多行就不会是const类型
3.eq_ref
惟一索引扫描,对于每一个索引建,表中只有一条记录与之匹配。常见于主键和UNIQUE索引,好比
explain select * from tb_item_cat a join tb_order_item b on a.id=b.item_id;
MySQL会先处理b表中的数据,而后b.item_id在a表中根据索引只能找到一行记录,所以符合要求,是eq_ref类型
4.ref
依然走索引扫描,可是一个索引键会对应表中多行数据
explain select * from tb_item_cat a where a.parent_id=2;
由于parent_id和item_id是多对一的关系,所以查询条件为parent_id=2必然会返回多条记录,符合上面的条件,是ref类型
5.range
走索引扫描,可是扫描的是索引的一段范围,好比使用between, < , > ,in等关系运算符
explain select * from tb_item_cat a where a.parent_id in(2,3);
6.index
走索引扫描,可是扫描的整个索引,这种状况比全表扫描会好一点,由于单个索引在磁盘所占空间一段是比整个表要少不少
explain select parent_id from tb_item_cat
由于我想要查询的返回结果集只有parent_id字段,而该字段所有在索引中就能找到,因此走索引全扫描彻底OK,不须要再去扫描表
7.all
最惨的扫描方式,速度最慢,若是你的执行计划打出来有它出现必定要注意
explain select * from tb_item_cat
理论上可能用到的索引,好比一个列上有2个索引,主键和一个复合索引(包含主键列),那么在这里显示的就会有这啷个索引名
执行时实际会用的索引
查询条件长度,在不损失查询精度的状况下,能够尽可能减小查询条件长度
显示被用于索引扫描的列或常量值
explain select * from tb_item_cat where id=1;
此时ref就是const
explain select * from tb_item_cat a join tb_order_item b on a.id = b.item_id
能够看到使用数据库mydb的表b的item_id列被用于索引的扫描
估算出来的可能被扫描出来的行
三大重要的额外信息,会在这里显示
using filesort
索引自己的排序没有被使用到,MySQL会将数据作另外的排序,这样将会很耗费时间。在实际生产中,若是真的出现这种状况,而索引又没有必要建立的话,你能够将数据读出来以后本身在代码中进行排序
using temporary
使用临时表来保存中间结果,若是常常出现这种状况,计算会不断的申请内存,耗费内存和CPU,形成数据库吞吐量严重降低,应用没法响应开始排队,最终应用没法响应客户端请求
using index
它是一个很好的提示,说明你的SQL写得很不错,未来的执行效果会很好