央视有个黄西博士主持的节目,叫做《是真的吗?》,会以实验的方式验证一些奇奇怪怪的问题。
那我们今天就来验证一个神奇的事情:count(8) 会比count(*) 快很多倍,是真的吗?
首先我们先炮制一个1千万的大表:T10M,这是一个占用空间1.2G的普通表,没有任何索引。建表过程略。
速度对比验证开始:
SQL>set timing on
SQL> select count(*) from t10m;
COUNT(*)
----------
10000000
Elapsed: 00:00:05.33
SQL> select count(8) from t10m;
COUNT(8)
----------
10000000
Elapsed: 00:00:00.75
哇,非常神奇,5.33秒 VS 0.75秒,整整7倍的性能差距,难道就是因为一个少敲了一个shift键吗(为了娱乐效果,故意使用了count(8),等同于常见的count(1))。
通过实验结果,这个结论看起来确实是真实的。
如果是初学者,看了上面的结论,没有接着往下看,可能真的会回去把代码里面的count(*) 都改成了count(8),这样一个天大的秘密怎么今天才知道呢?!
别急,实验还没完。如果我们再执行一次count(*),看看发生了什么:
SQL> select count(*) from t10m;
COUNT(*)
----------
10000000
Elapsed: 00:00:00.63
这次count(*) 反而又比count(8) 速度快了,神马情况?
内存的读取速度要比磁盘快是路人皆知的事实,第一次的PK实际上就是磁盘读与内存读的区别(这里不多解释),根据执行计划,count(*) 与 count(8) (通常都习惯写成count(1))在性能上根本就没有任何区别。
之前得到的结论就是在不清楚数据库原理的情况下,得到的片面结论。如果把这个结论当成一般性结论加以推广,岂不是贻笑大方。
有人可能会比较奇怪,老虎刘为什么故弄玄虚搞出这么一个小儿科的案例来欺骗大家的感情?
因为老虎刘在一本书上看到一个优化案例,说是
sql1:select rowid from t_xxx where rownum<=1;
的性能要比
sql2:select count(1) from t_xxx where rownum<=1;
好。
(瑕不掩瑜,书还是一本好书,写了作者的一些实际运维技巧和案例,我也学到了一些技巧,具体书名就不在这里说了)
作者是通过set autotrace on ,分别执行sql2和sql1(注意执行顺序),然后比较两次sql执行显示的 consistent gets数来判断两个SQL的性能情况。 实验结果显示确实是sql2消耗的 consistent gets要比sql高很多(我的实验结果是770 : 5)。由此得出上面的结论。
我第一次看到这个案例的时候,就非常怀疑。因为是专家写的案例,万一是真的我还学了一招。于是我通过实验验证了一下,结果如我所料,两个SQL基本上没有什么区别:
sql2第一次执行时,因为recursive calls次数多,消耗了绝大部分的consistent gets。再执行sql1时,不需要那么多的recursive calls了,consistent gets确实少了很多。
如果再次执行SQL1和SQL2,都是只有3个consistent gets,没有任何差别。而sql2执行计划中多出来的一步 SORT AGGREGATE,在CPU看来基本上是可以忽略的。
如果实验顺序是先执行sql1,再执行sql2,反而就会得出sql2的性能比sql1好的结论来。
总结:
我要表达是意思是,我们要通过理论来指导测试,而不是把片面的测试结果当成一般性结论,这样会误导自己,更会误导广大的读者。尤其是对一些有影响力的专家,在做出一些结论的时候,最好看看是不是有理论根据。
顺便提一句,select ... from a where a.id in (select b.id from b);这种SQL,如果要改成表关联,不是
select distinct .... from a,b where a.id=b.id; 两者是不等价的。
等价改写是: select .... from a,(select distinct b.id from b) bb where a.id=bb.id; 注意distinct的位置。
本文分享自 老虎刘谈oracle性能优化 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!