数据库版本:Oracle19c
事情的起因是这样的,我在做Oracle和崖山排序性能对比测试
https://blog.csdn.net/robinson1988/article/details/159086172?spm=1001.2014.3001.5501
发现下面SQL:
select *
from (select a.*, rownum rn from (select * from test01 order by rowid) a)
where rn = 40000000;
在PL/SQL Developer中跑22.07秒,在SQLPLUS中跑34.88秒,同样的执行计划,性能相差巨大
PL/SQL Developer A-Time执行计划如下:
-------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
-------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:22.07 | 635K| 717K| 717K| | | | |
|* 1 | VIEW | | 1 | 44M| 1 |00:00:22.07 | 635K| 717K| 717K| | | | |
| 2 | COUNT | | 1 | | 44M|00:00:21.41 | 635K| 717K| 717K| | | | |
| 3 | VIEW | | 1 | 44M| 44M|00:00:21.30 | 635K| 717K| 717K| | | | |
| 4 | SORT ORDER BY | | 1 | 44M| 44M|00:00:21.24 | 635K| 717K| 717K| 6307M| 24M| 1023M (0)| 5607M|
| 5 | TABLE ACCESS FULL| TEST01 | 1 | 44M| 44M|00:00:03.39 | 635K| 0 | 0 | | | | |
-------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN"=40000000)
SQLPLUS A-Time执行计划如下:
-------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem | Used-Tmp|
-------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:34.88 | 635K| 717K| 717K| | | | |
|* 1 | VIEW | | 1 | 44M| 1 |00:00:34.88 | 635K| 717K| 717K| | | | |
| 2 | COUNT | | 1 | | 44M|00:00:34.51 | 635K| 717K| 717K| | | | |
| 3 | VIEW | | 1 | 44M| 44M|00:00:30.96 | 635K| 717K| 717K| | | | |
| 4 | SORT ORDER BY | | 1 | 44M| 44M|00:00:27.03 | 635K| 717K| 717K| 6307M| 24M| 1023M (0)| 5607M|
| 5 | TABLE ACCESS FULL| TEST01 | 1 | 44M| 44M|00:00:03.36 | 635K| 0 | 0 | | | | |
-------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("RN"=40000000)
SQLPLUS中 Id=4 SORT ORDER BY 比 PLSQL DEV 中 Id=4 SORT ORDER BY 多花了近6秒
SQLPLUS中 Id=2 COUNT 比 PLSQL DEV 中 Id=2 COUNT 多花了多花了近4秒
发现这个问题之后,我又到Oracle26ai上进行测试,发现问题依然存在,于是到Oracle11.2.0.4上进行测试,11.2.0.4没有问题,Oracle12c我没测试,不知道有没有问题
既然11.2.0.4没问题,19c有问题,问题又出现在SQLPLUS上,那就对比SQLPLUS中的参数设置,在11.2.0.4的SQLPLUS中show all,在19c的SQLPLUS中show all,19c多了几个参数,rowprefetch引起了我的注意,默认=1,把它设置大点看看能否提升速度
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
SQL> show rowprefetch
rowprefetch 1
设置rowprefetch=100后(准确的说是设置到15以及15以后),SQLPLUS速度就正常了
SQL> set rowprefetch 100
这也太坑了,要不是SQL在PLSQL DEV中跑了一下,这次就被SQLPLUS中的耗时给欺骗了,从而得出错误的结论
顺便说一下在测试Oracle和崖山HASH JOIN性能对比时还遇到了Oracle19c"经典"的BUG:PGA memory operation
https://blog.csdn.net/robinson1988/article/details/159205315?spm=1001.2014.3001.5501
sqlplus中的rowprefetch原理研究了2天,没太搞明白,不想继续折腾了,记录一下:
1.rowprefetch默认为1,表示关闭预取功能
2.关闭预取功能之后,第一次fetch=1,哪怕SQL只返回1行,后面还会再fetch一次
3.我这条SQL确实是只返回1行,所以它要fetch两次
4.fetch两次效率也不应该相差这么大啊,SQL效率可是相差了12秒
5.测试其他SQL语句SQLPLUS和PLSQL DEV耗时又是一样的
6.我只能把原因归结为Oracle BUG了,由于没有metalink,无法问SR,先就这样吧
最后这里有篇文章讲的是rowprefetch和arraysize的关系,但是没有更深的原理
https://www.dbi-services.com/blog/arraysize-or-rowprefetch-in-sqlplus/#collapseEvents
Oracle本来就是个黑盒子,普通人无法联系到Oracle内核研发,要是国产数据库,直接问内核就行了