SQL 优化准则
在应用层,通过pt工具和慢查询日志的配合,可以轻松地分辨出全表扫描的语句
基本原则
避免全表扫描
建立索引
尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理
尽量避免大事务操作,提高系统并发能力
使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。尽量避免使用游标,因为游标的效率较差。
关于where 后的条件
应尽量避免在where子句中使用 != 或 <> 操作符,否则引擎将放弃使用索引,而是进行全表扫描。
应尽量避免在where子句中使用or来连接条件,可以考虑使用union代替
in和not in也要慎用,对于连续的数值,能用between就不要用in,exists 代替 in
尽量避免在where子句中对字段进行表达式操作和函数操作
关于数据类型
尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为变长字段存储空间小,对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL。
任何地方都不要使用 select from t ,用具体的字段列表代替“”,不要返回用不到的任何字段。
关于临时表
避免频繁创建和删除临时表,以减少系统表资源的消耗。对于一次性事件,最好使用导出表。
在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量log,以提高速度;
如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。如果使用到了临时表,在最后将所有的临时表显式删除时,先truncate table ,然后drop table,这样可以避免系统表的较长时间锁定。
关于索引
先应考虑在 where 及 order by 涉及的列上建立索引。
在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引, 否则该索引将不会被使用,
并且应尽可能的让字段顺序与索引顺序相一致。索引并不是越多越好,索引固然可以提高相应的select的效率,但同时也降低了insert和update的效率,因为insert或update时有可能会重建索引,所以
视具体情况而定。一个表的索引数最好不要超过7个,若太多则应考虑一些不常使用到的列上建的索引是否有必要.
数据库架构调优
- 分区分表
- 业务分库
- 主从同步与读写分离
- 数据缓存
- 主从热备与HA双活
SQL 优化实战
explain
1 | explain select * from..... |
输出结果说明
select_type:查询类型
table:查询表名
type:扫描方式,all全表
possible_keys:可能使用到的索引
key:实际使用到的索引
rows:sql语句扫描了多少行记录才得到所要的结果
extra:附加说明,比如排序方式
group by
在使用group by 分组查询是,默认分组后,还会排序,可能会降低速度。在group by 后面增加 order by null 就可以防止排序。
有些情况下,可以使用连接来替代子查询。因为使用join,MySQL不需要在内存中创建临时表。