SQL调优

一、在表中建立索引

较频繁地作为查询条件的字段,唯一性不太差的字段适合建立索引,更新不太频繁地字段适合创建索引,不会出现在where条件中的字段不该建立索引。

二、查询条件中,一定不要使用select *
1、连接查询中的冲突

当在JOIN查询中使用SELECT *时,当多个表有相同名称的列时,可能会引入并发症,例如status、active、name等。

2、不需要的列会增加数据传输时间和网络开销

select * 会需要解析更多的对象、字段、权限、属性等相关内容,会给数据库造成负担,增大网络开销。* 有时会误带上如log、IconMD5之类无用的大文本字段,数据传输size会几何增涨。

3、对于无用的大字段,如varchar、blob、text 会增加io操作

长度超过728字节的时候,会先把超出的数据序列化到另一个地方,因此读取这条记录会增加一次io操作。

4、需要查询数据字典

Oracle在解析的过程中, 会将*依次转换成所有的列名,这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间。

5、失去mysql优化器“覆盖索引”策略优化的可能性

例如,有一个表为t(a,b,c,d,e,f),其中,a为主键,b列有索引。

那么,在磁盘上有两棵 B+ 树,即聚集索引和辅助索引(包括单列索引、联合索引),分别保存(a,b,c,d,e,f)和(a,b),如果查询条件中where条件可以通过b列的索引过滤掉一部分记录,查询就会先走辅助索引,如果用户只需要a列和b列的数据,直接通过辅助索引就可以知道用户查询的数据。

如果用户使用select *,获取了不需要的数据,则首先通过辅助索引过滤数据,然后再通过聚集索引获取所有的列,这就多了一次b+树查询,速度必然会慢很多。

三、不要在where条件中使用左右两边都是%的like模糊查询
select * from t_order where customer like '%zhang%'

这样会导致数据库引擎放弃索引进行全表扫描。优化:尽量在字段后面使用模糊查询或使用全文索引。

select * from t_order where customer like 'zhang%'

四、尽量不要使用in 和not in,会造成全表扫描

select * from t_order where id not in (2,3)
select * from t_order1 where customer in (select customer from t_order2)

可以用exists代替

五、尽量不要使用or,会造成全表扫描

select * from t_order where id = 1 or id = 3

优化:可以用union代替or

select * from t_order where id = 1
union
select * from t_order where id = 3

六、尽量不要在 where 子句中对字段进行表达式操作,这样也会造成全表扫描

select id from t_order where num/2=100

应改为

select id from t_order where num=100*2

七、where条件里尽量不要进行null值的判断,null的判断也会造成全表扫描

select * from t_order where score is null

优化:给字段添加默认值,对默认值进行判断。

select * from t_order where score = 0

八、尽量不要在where条件中等号的左侧进行表达式、函数操作,会导致全表扫描

select * from t_order2 where score/10 = 10
select * from t_order2 where substr(customer,1,5) = 'zhang'
select * from tb_order where DATE_FORMAT(dt,'%Y%m%d') ='20220207'

优化:将表达式.函数操作移动到等号右侧

select * from t_order2 where score = 10*10
select * from t_order2 where customer like 'zhang%'
select * from tb_order  where  dt=DATE_FORMAT('20220207','%Y-%m-%d')

九、尽量不要使用where 1=1的条件

有时候,在开发过程中,为了方便拼装查询条件,我们会加上该条件,这样,会造成进行全表扫描。

select * from t_order where 1=1

优化:如果用代码拼装sql,则由代码进行判断,没where加where,有where加and。如果用mybatis,请用mybatis的where语法。

十、查询条件两边数据类型不一致索引失效

例如我们在订单表tb_order建立了索引idx_order_id,order_id字段类型为varchar在查询时如果使用where order_id= 20220207123654100,这样的查询方式会直接造成索引失效。

要让索引生效,正确的用法为

where order_id=’20220207123654100’

再来看一个例子:

explain select * from tb_user  where phone = 12345678936
explain select * from tb_user  where phone = '12345678936'

从这两条SQL执行的结果我们可以看出,执行第一条SQL没有使用到索引,而执行第二条SQL时使用到了索引。这是为什么呢?我们需要先了解下mysql索引优化器工作的原理。选择索引是优化器工作,优化器工作有自己的一套规则,如果等号两边的数据类型不一致,则会发生隐式转换。基于这条规则,我们回过头看看

explain select * from tb_user where phone = 12345678936;

这条SQL语句执行时就会变为

explain select * from tb_user where cast(phone as signed int) = 12345678936;

由于对索引列进行了函数操作,所以才导致索引失效,从而全表扫描了。

十一、程序要尽量避免大事务操作,提高系统并发能力

即将事务的范围尽量缩小,可提高性能。

十二、一个表的索引数最好不要超过6个

如果索引太多的话,就需要考虑一下那些不常使用到的列上建的索引是否有必要。

十三、尽量使用多表连接(join)查询(避免子查询)

子查询效率特别低,而一般的子查询都可以由关连查询来实现相同的功能,关联查询的效率要提高很多,所以建议在数据查询时避免使用子查询(尤其是在记录很多时),而最好用关联查询来实现。

分析MySQL的SQL性能瓶颈,可借助explain来分析优化。推荐阅读一张图彻底搞懂MySQL的 explain

十四 循环里不要调用DB执行SQL

避免在循环里写调用SQL的代码,而是在循环外批量执行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容