拼命工作好好玩 2019-06-28
数据库很重要!很重要!很重要! 重要的事情说三遍。所以单独用一篇来讲述SQL怎么优化。这里提前说到一点,不建议在业务代码里写很多复杂业务SQL,基本尽可能的减少 join,子查询 等,也就说尽量在应用层来解决问题,降低产生低效SQL的概率,数据库只是完成数据存储及最简单查询的组件。
主要4个方向,以下4个方向尽可能达到了,SQL的执行效率就提高了。
DBA开启MySQL的慢查询日志,对每日数据库慢查询进行监控。慢查询后每日汇总提供开发进行处理。DBA给出指导意见。
主要看对SQL的执行过程中
explain [extended] select … from … where …
得到结果是
+—-+————-+——-+——-+————-+——-+——-+——————-+———+———+——-+-+——-+——-+—-+———-+—————+———-+———+———+——-+——+——-+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +—-+————-+——-+——-+————-+——-+——-+——————-+———+———+——-+-+——-+——-+—-+———-+—————+———-+———+———+——-+——+——-+
其中 table 表示是哪个表的数据。
第一种分页写法
select * from t where thread_id = 771025 and deleted = 0 order by gmt_create asc limit 0, 15;
原理:
一次性根据过滤条件取出所有字段进行排序返回。
数据访问开销=索引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);
数据库是有状态的服务,变更复杂而且速度慢,如果把业务逻辑放到数据库中,将会限制业务的快速发展。建议把业务逻辑提前,放到前端或中间逻辑层,而把数据库作为存储层,实现逻辑与存储的分离。