本文总结一下sql语句优化的一些知识和经验。

一.in 型子查询引出的陷阱
先举个例子,如果某商城系统,要查询id为6的大类商品下的所有小类商品。思路一般是先查出大类下所有小类,然后查商品表中商品类型是这些小类的所有商品。
直观上会先想到子查询:select goods_id,cat_id,goods_name from  goods where cat_id in (select cat_id from category where parent_id=6);
这条语句给我们的感觉是, 先查到内层的6号栏目的子栏目,如7,8,9,11 ,然后外层, cat_id in (7,8,9,11) 。
可事实是 goods表全扫描, 并逐行与category表对照, 看parent_id=6是否成立。In型子查询,会被查询优化器被改成了exists的执行效果.当goods表越大时, 查询速度越慢。如下图所示。

SQL语句的优化
如果我们在程序中分两次查询,先查出大类下所有小类,select cat_id from category where parent_id=6 。
然后再根据小类查询商品,select goods_id,cat_id,goods_name from  goods where cat_id in (7,8,9,11) 。
这样goods表就会走cat_id列的索引了,不会再全表扫描了。
如果要用一条语句执行,可以改为连接查询,
select g.goods_id,g.cat_id,g.goods_name from  goods as g inner join (select cat_id from ecs_category where parent_id=6) as t  on g.cat_id = t.cat_id;
内层的查询 select cat_id from ecs_category where parent_id=6 ; 用到Parent_id索引, 返回7,8,9,11 。
t和 goods 通过 cat_id 相连, 因为cat_id在 goods表中有索引, 所以相当于用7,8,911,快速匹配上 goods的行。

二.group by 语句
group by 语句语句要注意几点:
1.group by用于统计,而不用于筛选数据。比如: 适合统计平均分、最高分, 但用于筛选重复数据,则不适合。
2.在group by时, 用带有索引的列来group, 速度会稍快一些,另外,分组列用int型比char型,也要快一些。
3.两表连接查询,如果只查询A表的列, 那么 group by 、order by 尽量用A表的列,而且列应该显示声明为A的列。

三.子查询
有时需要使用子查询,在有些业务场景,适合使用子查询,使用子查询也未必慢。
注意:如果需要使用子查询的结果,内层from语句查到的临时表, 是没有索引的。所以from的返回内容要尽量少。

四.union优化
union all不过滤重复数据,效率比union高很多, 因为union去重的代价非常高,如非必须,请用union all。去重可以放在程序里去做。

五.避免产生临时表
应该尽量避免产生临时表,以下情况会产生临时表。
1.group by 的列没有索引。
2.order by 与group by为不同列时,或者表连接查询时,取A表的内容,order by 、group by 包含B表的列。
3.distinct 和 order by 一起使用时,可能会产生临时表。

以上这些只是一些技巧的总结,其实sql优化的核心和重点还是在索引。

相关文章: