上篇我们讲了下在数据库表设计时如何根据业务需求来选取最适合自己的字段属性设计,今天我们来聊聊当你拿到一句sql语句,你会从哪些方面来优化它。
方面一、in、exists还是join
使用场景:我们要查询整个湖北省所有的水土流失信息,显然全国的水土流失表中的数据比湖北省城市数要大很多,假设全国的水土流失表有100万条数据,湖北省总共有80个市(包括直辖市、县级市和市辖区等)。
问题:那么对于这种使用场景,sql中使用in还是exists?
测试:
1、select * from shuituInfo where cid in(select id from city );
2、select * from shuituInfo where exists(select id from city where shuituInfo.cid= city.id);
测试下来,在表结构一样的情况下,我们发现1比2的效率要高很多。
分析:
如果两个表中一个较小,一个较大,则子查询表数据大的用exists,子查询表数据小的用in。因为in会使用城市表中的id去到水土流失信息表中直接匹配所需要的行,而exists是根据匹配项去判断是或者否,然后根据是否返回结果。当子查询的表数据量大而主表数据量小,用exists判断,效率就会高,而当子查询的表数据量小而主表数据量大的时候,直接匹配你需要的值则更快。
主表有100万行,子查询里面有80条数据,那么exists会把100万行在子查询里面进行匹配,匹配上了就显示,匹配不上就不显示,所以需要判断100万次,而in则会使用子查询的80条记录直接匹配主表中的100万行数据,in的效率通常会更高,但是如果反过来,主表80条记录,子查询里面有100万行,exists只进行80次判断,而in会用100万个数据去匹配这80条记录,所以比exists更快。所以说in的效率取决于子表的数据量大小,而exists的效率取决于主表的数据量大小。如果字表的数据量小,使用in时只需要从主表中检索符合字表的数据就好了;如果主表的数据量小,使用exists只需要判断主表中的数据是否满足子查询。
3、select s.* from shuituInfo s, city c where s.cid = c.id;
其实我们使用隐式(implicit) inner join的效率会更高一点:
EXISTS <= IN <= JOIN
NOT EXISTS <= NOT IN <= LEFT JOIN
所以在同等情况下,尽量避免子查询,而用join来实现。个人理解是,join之所以更有效率一些,是因为MySQL不需要在内存中创建临时表来完成查询工作。
方面二、union 和 union all
在一些应用场景下,我们常需要使用union来写一些去重的sql,但union会将各查询子集的记录做比较并去除相同的记录,所以比起单纯的union all(不排除重复的值)来说通常速度都会慢上许多。一般来说,如果我们确定在某些应用场景下合并子集后不会出现重复值那么使用union all。
对于索引列最好使用union all,因复杂的查询【包含运算等】将使or、in放弃索引而全表扫描。
对于只有非索引字段最好使用or或者in,因为非索引字段本来要全表扫描而union all会成倍增加表扫描的次数。见文献-MySQL中使用or、in与union all在查询命令下的效率对比
方面三、常见的优化手段
1、应该尽量把字段设置为not null
,这样在将来执行查询的时候,数据库不用去比较null
值。
2、最好是在相同类型的字段间进行比较的操作。在MySQL3.23版之前,这甚至是一个必须的条件。例如不能将一个建有索引的INT字段和BIGINT字段进行比较;但是作为特殊的情况,在CHAR类型的字段和VARCHAR类型字段的字段大小相同的时候,可以将它们进行比较。
3、在建有索引的字段上尽量不要使用函数进行操作,或者进行计算。比如:在一个DATE类型的字段上使用YEAE()函数时,将会使索引不能发挥应有的作用。
4、在搜索字符型字段时,我们有时会使用like关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。因为在有些情况(比如like '%param%'
)下,like查询使用不到索引,会扫描全表,但如果是like 'param'
或like 'param%'
的情况下,索引不会失效。但在数据量非常大的时候还是建议不使用like。
参考文献:
MySQL中使用or、in与union all在查询命令下的效率对比:http://www.jb51.net/article/75171.htm
MySQL数据库优化的八种方式:http://www.cnblogs.com/zhyunfe/p/6209074.html
20+条MySQL性能优化的最佳经验:http://www.jfox.info/20-tiao-mysql-xing-nen-you-hua-de-zui-jia-jing-yan.html