升级到Oracle 19c:你不可不知的十大SQL问题(上)

众所周知,自 Oracle 18c开始,Oracle将数据库的版本发布变更为年度发布,以践行敏捷迭代的研发理念。所谓年度发布也就是按照年份,每年发布一个版本。2018年发布了Oracle 18c,2019年是Oracle 19c,2020年发布Oracle 20c(20c 云上版本已经在2月14日发布,按照官方计划公众发布是在4月)。


这其中,18c = 12.2.0.2,19c = 12.2.0.3,这两个年度版本仍然处于 12c 的发布序列中,19c 属于 12c 体系的最后一个版本。由于 11g 已经退出了官方支持序列,越来越多的用户开始升级到 19c 。

随着版本号的变化,补丁策略也随之改变,自18c开始,Oracle推出RU策略(Release Update),每个季度发布一个RU,所以对应18c,我们看到的RU系列版本号就是18.1,18.2等等,RU是一个累积的增量补丁,也就是说后发布的包含之前RU的内容,如果我们从18.1开始,可以直接应用18.4,跳过其间的18.2和18.3版本。

由于每个季度的间隔事实上很大,如果期间用户报告了安全问题或严重的Bug,那么针对每个RU,Oracle还可能发布最多两个RUR(Release Update Revision)修订版本,其中主要包含安全补丁和重要的回归修复。

下图是新策略下的Oracle数据库版本发布计划表:

升级到Oracle 19c:你不可不知的十大SQL问题(上)_第1张图片

这个图,可能会让大多数人看得头晕,但是升级路径有一个原则,记住这个原则就一目了然了。这个原则就是:主版本号后面的2个数字之和要小于等于目标版本。例如 18.8.2 的低位 8+2 =10,这个版本可以升级到 18.10.0 ,但是不可以升级到 18.9.0,因为 9+0 < 10 。

当然,在非特殊情况下,官方推荐采取 RU 路线的更新策略,这看起来就简化多了:

升级到Oracle 19c:你不可不知的十大SQL问题(上)_第2张图片

当我们进行大版本升级时,总是建议用户通过SPA(SQL Performance Analyzer),对源环境和目标版本之间的测试,以避免出现SQL的兼容性问题或者性能问题,通过在源库进行SQL捕获,在目标库(通常是升级的高版本)进行重演,并生成性能对比报告,以指导用户的升级变更:

升级到Oracle 19c:你不可不知的十大SQL问题(上)_第3张图片

而对于小版本的升级,往往无法进行如此详尽的测试准备工作,这就需要我们能够预先收集已知问题并做出防范。

在进行数据库升级时,SQL 是最容易受到影响的部分,这些影响包括:

  1. SQL 语法发生改变:原应用SQL出错无法正确执行或执行结果发生改变;

  2. 内部函数改变:函数返回值或返回值类型发生变化,导致SQL结果出错或异常;

  3. 执行计划改变:因为算法调整,SQL的执行计划发生改变,一部分执行计划变坏,影响性能;

  4. 新特性的BUG:往往新特性引入,会带来相应的新BUG,影响系统性能或者稳定性;

  5. 次生BUG:因为修复某些BUG,而引入的新BUG,导致SQL可能出现不兼容或其他错误和异常;

本文针对SQL方面的几个 19c 中典型案例,作为范例,希望能够为即将升级到 19c的朋友们提供一些经验借鉴。考虑到这些内容是DBA们知识储备的一部分,所以在一些知识点上做了介绍和扩展。

1. Oracle 19.3 中优化器问题导致的执行结果错误

在 Oracle 数据库跨版本升级时,很多SQL的新特性被引入到数据库中来,不可避免的,一些BUG会潜移默化的发生。而我们认为,最让人困扰的是那些SQL不出异常,但是查询结果出错的语句,这类SQL很难通过测试发现,只能在人们注意到查询结果出错时,才会追究并发现问题。

以下就是这样一个问题,在 19.3 版本中广泛存在。创建简单的测试表和测试数据:

SQL> CREATE TABLE ENMO AS SELECT * FROM DBA_OBJECTS;SQL> UPDATE ENMO SET EDITION_NAME = 'ORA$BASE' WHERE MOD(ROWNUM, 10000) = 0;SQL> CREATE TABLE TECH AS SELECT ROWNUM ID FROM ENMO;SQL> analyze table ENMO compute statistics;

此时执行如下查询,可以从结果看到返回了2个零值,这个结果显然是错误的:

SQL> set autotrace onSQL> SELECT COUNT(OBJECT_NAME || ‘, ‘ || OBJECT_TYPE), COUNT(EDITION_NAME) FROM ENMO, TECH WHERE ID = OBJECT_ID;
COUNT(OBJECT_NAME||’,’||OBJECT_TYPE) COUNT(EDITION_NAME)------------------------------------ -------------------0                         0

在以下执行计划中,可以看出执行计划的错误出现在第三个步骤,在这个步骤中,通过Filter增加了一个 NOT NULL 的过滤,这就使得大部分数据被抛弃了,进一步向上的查询连接自然就出现了结果集的错误:

升级到Oracle 19c:你不可不知的十大SQL问题(上)_第4张图片

那么正常的情况应该是如何呢?去掉第二个输出,可以获得以下结果:

SQL> SELECT COUNT(OBJECT_NAME || ', ' || OBJECT_TYPE) FROM ENMO, TECH WHERE ID = OBJECT_ID;
COUNT(OBJECT_NAME||','||OBJECT_TYPE)------------------------------------             71789

经过确认,这是一个因为修复BUG而引入的BUG。Oracle最为强大的地方是,几乎为每一个修正都加入了一个开关,如果发现某个修正引起了新的问题,那么通过开关就可以恢复原有的工作方式。

以下语句就关闭了这个修复:

SQL> alter session set "_fix_control"='24761824:OFF';
Session altered.

再来看现在的执行计划,去掉了 NOT NULL 的过滤,SQL执行结果恢复了正常:

升级到Oracle 19c:你不可不知的十大SQL问题(上)_第5张图片

 

那么这个BUG是如何发生的呢

你可能感兴趣的:(升级到Oracle 19c:你不可不知的十大SQL问题(上))