sqlplus rowprefetch 严重影响order by + rownum性能

数据库版本: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内核研发,要是国产数据库,直接问内核就行了

相关推荐
胡斌附体9 个月前
mobaxterm终端sqlplus乱码问题解决
数据库·乱码·sqlplus·字符集设置
失心疯_20232 年前
021.PL-SQL控制结构
数据库·sql·oracle·pl/sql·if语句·sqlplus·oracle教程
失心疯_20232 年前
011. Oracle-约束
数据库·oracle·pl/sql·关系型数据库·sqlplus·oracle教程·数据库教程