sql优化基本规则

234 阅读4分钟
  1. **建表时设置索引字段为not null,或者默认值。**因为索引不存储null值,null值不能拿来判断 例子:建立了唯一索引的字段,可以重复插入null值。
    当列上允许为null值时:
    where子句使用了基于is null的情形,其执行计划走全表扫描。
    where子句使用了基于is not null的情形,其执行计划走索引扫描(索引范围扫描或            索引全扫描)。
    当列上不允许为null值时,存在非null约束 :
    where子句使用了基于is null的情行,其执行计划走索引扫描。
    where子句使用了基于is not null的情形,其执行计划也是走索引扫描。

  2. 不能在索引列上进行计算或者函数运算,会导致索引失效

  3. 进行多表连接查询的时候,要用小表驱动大表,总之就是尽量减少加载进内存的表数据量。可以在连接时先用条件筛选出数据(临时表),再进行连接。

  4. 不要使用or,这样会使索引失效,可以使用union或者union all进行结果集合并来替代。

  5. 在经常查询使用的字段上建立索引,数据区分度比较小的字段不要建立索引,比如性别。因为每次插入数据都要维护索引,所以过多索引会降低数据插入的效率

  6. 如果有复合索引,使用的时候要遵循最左匹配原则(使用like关键字的使用也一样),否则不能完全使用符合索引。

  7. 减少回表查询,不要用select * ,只返回自己需要的数据,这样也可以减少数据IO。

  8. 排序是一个很耗时和消耗空间的操作,数据量大的排序,要给排序的列建立索引,如果有多个列,尽量建立复合索引

  9. 尽量使用内连接(inner join),减少使用外连接(left join,right join),因为内连接只会返回双方都存在数据的行,如果要使用外连接,要遵从小表驱动大表的原则,使基准表尽可能的小。减少使用子查询(where后面的查询),子查询的效率比外连接还要慢,因为循环外表,每一条数据就执行一次子查询,相当的慢.

  10. 也不要在返回大量数据中的select 中使用函数调用或者存储过程调用,也是每一条数据执行一次调用。

  11. 在外表小于子表时,使用exist代替in。select * from A a where a.id in (select  id from B) , 如果A表小于B表,要使用exist代替in 。
    因为使用in的话,数据库需要加载子查询中的结果集到内存中,然后再进行比较,比较次数时a.length*b.length(),如果使用exist的话,select * from A a where a.id exist (select 1 from B b where a.id = b.id) ,对于数据库来讲,后面那个只是一次查询判断,索引次数是a.lenght()。
    但是如果A表很大,B表很小的话,A表有10000条记录,B表有100条记录,那么exists()还是执行10000次,还不如使用in()遍历10000*100次,因为in()是在内存里遍历比较,而exists()需要查询数据库,这时候in效率比较高。

  12. 比较的字段一定要数据类型一致,不然会产生隐式转换,导致索引失效

示例:

1)select * from table_a where table_a.id not in (select table_b.id from table_b)

2)select * from table_a left join table_b on table_a.id = table_b.id where table_b.id is null

语句2的效率是要高于语句1的,SQL的结果是获取到在table_a中存在但是table_b中不存在的数据,如果直接用not in是不走索引的,而且在table_b比较大的时候效率会非常低,实际工作中我试了一下直接not in,然后数据达到一万条的时候大概需要150S左右才能查出数据(感谢DBA和运维不杀之恩),我采取的方法是,先查出两个表的交集,这样得到的表会小很多,而且是用的in,效率会高很多,然后再用not in,最终的效果也是一样,但是时间只要2.56S,然后采取语句2的关联表来处理,时间缩短到了1.42S,基本上效率是比较高的,当然理想的是在1S内。