数据库很重要!很重要!很重要! 重要的事情说三遍。因此单独用一篇来说述SQL怎么优化。这里提早说到一点,不建议在业务代码里写不少复杂业务SQL,基本尽量的减小 join,子查询 等,也就说尽可能在应用层来解决问题,下降产生低效SQL的几率,数据库只是完成数据存储及最简单查询的组件。前端
主要4个方向,如下4个方向尽量达到了,SQL的执行效率就提升了。mysql
DBA开启MySQL的慢查询日志,对每日数据库慢查询进行监控。慢查询后每日汇总提供开发进行处理。DBA给出指导意见。sql
主要看对SQL的执行过程当中数据库
explain [extended] select … from … where …
获得结果是mysql优化
+—-+————-+——-+——-+————-+——-+——-+——————-+———+———+——-+-+——-+——-+—-+———-+—————+———-+———+———+——-+——+——-+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +—-+————-+——-+——-+————-+——-+——-+——————-+———+———+——-+-+——-+——-+—-+———-+—————+———-+———+———+——-+——+——-+
其中 table 表示是哪一个表的数据。性能
若是值为 distinct ,说明mysql 找到了域行联合匹配的行,就再也不查找了。
若是值为 not exits : mysql优化了 left join ,一旦找到了 left join 匹配的行,便再也不进行搜索了。
若是值为 rang checked for each : 没有找到理想的索引。
若是为 using filesort ,则须要改进sql了。这说明 mysql执行 须要 文件排序。这是比较影响效率的。
若是为 using temporary , 这是使用了 临时表。 这种状况也比较影响效率,sql须要改进。或者从应用层进行改进。
若是为 where used 说明使用了where语句。若是 type为 all 或者 index ,通常会出现这样的结果。这样的问题,通常是查询须要改进。
第一种分页写法优化
select * from t where thread_id = 771025 and deleted = 0 order by gmt_create asc limit 0, 15;
原理:日志
一次性根据过滤条件取出全部字段进行排序返回。code
数据访问开销=索引IO + 索引所有记录结果对应的表数据IO
缺点:排序
该种写法越翻到后面执行效率越差,时间越长,尤为表数据量很大的时候。适用场景:当中间结果集很小(10000行如下)或者查询条件复杂(指涉及多个不一样查询字段或者多表链接)时适用。
第二种分页写法:
select t.* from ( select id from t where thread_id = 771025 and deleted = 0 order by gmt_create asc limit 0, 15) a, t where a.id = t.id;
前提:
假设t表主键是id列,且有覆盖索引secondary key:(thread_id, deleted, gmt_create)
原理:
先根据过滤条件利用覆盖索引取出主键id进行排序,再进行join操做取出其余字段。
数据访问开销=索引IO+索引分页后结果对应的表数据IO
优势:
每次翻页消耗的资源和时间都基本相同,就像翻第一页同样
适用场景:
当查询和排序字段(即where子句和order by子句涉及的字段)有对应覆盖索引时,且中间结果集很大的状况时适用
减小和数据库交互次数
INSERT ... ON DUPLICATE KEY UPDATE REPLACE INTO INSERT IGNORE INSERT INTO VALUES()
alter table t add column b varchar(10);
而后增长索引:
alter table t add index idx_aa(aa);
正确的作法是:
alter table t add column b varchar(10),add index idx_aa(aa);
数据库是有状态的服务,变动复杂并且速度慢,若是把业务逻辑放到数据库中,将会限制业务的快速发展。建议把业务逻辑提早,放到前端或中间逻辑层,而把数据库做为存储层,实现逻辑与存储的分离。