一、在表中建立索引
较频繁地作为查询条件的字段,唯一性不太差的字段适合建立索引,更新不太频繁地字段适合创建索引,不会出现在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的代码,而是在循环外批量执行。