升級到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數據庫版本發布計划表:

這個圖,可能會讓大多數人看得頭暈,但是升級路徑有一個原則,記住這個原則就一目了然了。這個原則就是:主版本號后面的2個數字之和要小於等於目標版本。例如 18.8.2 的低位 8+2 =10,這個版本可以升級到 18.10.0 ,但是不可以升級到 18.9.0,因為 9+0 < 10 。

當然,在非特殊情況下,官方推薦采取 RU 路線的更新策略,這看起來就簡化多了:

當我們進行大版本升級時,總是建議用戶通過SPA(SQL Performance Analyzer),對源環境和目標版本之間的測試,以避免出現SQL的兼容性問題或者性能問題,通過在源庫進行SQL捕獲,在目標庫(通常是升級的高版本)進行重演,並生成性能對比報告,以指導用戶的升級變更:

而對於小版本的升級,往往無法進行如此詳盡的測試准備工作,這就需要我們能夠預先收集已知問題並做出防范。

在進行數據庫升級時,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 的過濾,這就使得大部分數據被拋棄了,進一步向上的查詢連接自然就出現了結果集的錯誤:

那么正常的情況應該是如何呢?去掉第二個輸出,可以獲得以下結果:

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執行結果恢復了正常:

 

那么這個BUG是如何發生的呢


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM