文件版本升級:ORA-01805排查與DBMS_DST腳本實踐)
簡介面向 Oracle DBA 與數(shù)據(jù)庫運維人員的時區(qū)版本升級腳本包用于將數(shù)據(jù)庫時區(qū)版本調(diào)整至較新版本通常配合官方時區(qū)補(bǔ)丁使用。包內(nèi)共 4 個 SQL 文件壓縮包約 16KB體量輕便主要包含升級前檢查、時區(qū)調(diào)整應(yīng)用以及相關(guān)統(tǒng)計輔助腳本并附有執(zhí)行順序說明先運行檢查腳本評估環(huán)境再執(zhí)行應(yīng)用腳本完成調(diào)整便于在變更前確認(rèn)兼容性與影響范圍。已有 1693 人學(xué)習(xí)適合需要處理時區(qū)版本不一致、補(bǔ)丁配套升級或升級前預(yù)檢的運維場景。腳本以 SQL 形式組織方便在 SQL*Plus 等環(huán)境中按說明逐步執(zhí)行可作為時區(qū)版本調(diào)整的輔助工具幫助讀者快速完成環(huán)境核查、變更實施與結(jié)果驗證降低手工操作遺漏風(fēng)險。1. 凌晨兩點的 ORA-01805多半是時區(qū)文件版本沒對齊去年冬天一個報表庫半夜跑批失敗報ORA-01805: possible error in date/time operation詭異的是同一條 SQL 在數(shù)據(jù)庫服務(wù)器上手工執(zhí)行正常應(yīng)用連上來就報錯。查了兩個小時才定位數(shù)據(jù)庫用的時區(qū)文件和應(yīng)用服務(wù)器上客戶端帶的時區(qū)數(shù)據(jù)差了三四個版本兩邊對同一個TIMESTAMP WITH TIME ZONE值的偏移解釋不一致SQL 里只要帶AT TIME ZONE、FROM_TZ或者跨時區(qū)比較就必然報錯。這類問題不是改 SQL 能解決的動的是數(shù)據(jù)庫的時區(qū)版本time zone file version。手工做一遍要走BEGIN_PREPARE → UPGRADE_DATABASE → END_PREPARE → BEGIN_UPGRADE → UPGRADE_DATABASE → END_UPGRADE六個動作中間還得配合只讀窗口、錯誤表排查、版本校驗漏一步就白跑。這份 DBMS_DST_scripts V1.9 干的就是把這一串按順序固化成可重復(fù)執(zhí)行的腳本包。它適合手里有含 TSTZ 列的老庫、要在可控停機(jī)窗口里做一次時區(qū)版本抬升的運維和 DBA也適合第一次做這件事、想先照著一份能跑的流程走一遍的人。如果庫里一個 TSTZ 列都沒有那用不上它換掉 tzfile 重啟就完事。2. 拆包看結(jié)構(gòu)V1.9 封的是三段窗口和兩張錯誤表2.1 時區(qū)文件是張映射表升級動的是存量數(shù)據(jù)的偏移解釋先把概念掰清楚不然容易把時區(qū)版本升級當(dāng)成改參數(shù)。Oracle 的時區(qū)規(guī)則放在$ORACLE_HOME/oracore/zoneinfo/下文件名形如timezlrg_N.dat、timezone_N.datN 就是版本號。這個文件里存的不是北京時間等于 UTC8這種常量而是一張地區(qū) → 歷史偏移規(guī)則的映射表包含歷次夏令時的起止時間點。某個地區(qū)調(diào)整過一次切換日期就要出一個新版本。v$timezone_file告訴你當(dāng)前數(shù)據(jù)庫正在用第幾版v$timezone_file_supplied列出這套 ORACLE_HOME 里實際放了幾份、都到第幾版。兩個視圖一對你就知道能不能升、能升到幾。關(guān)鍵在于 TSTZ 列的物理存儲內(nèi)部記的是 UTC 時刻加一個偏移量不存地區(qū)名。數(shù)據(jù)庫沒有這條數(shù)據(jù)屬于哪個地區(qū)的信息一旦規(guī)則被修正舊數(shù)據(jù)里那個裸偏移量就沒有辦法再反推回正確的絕對時刻。所以升級動作本質(zhì)是按新規(guī)則把每一行 TSTZ 值重算一遍寫回新的內(nèi)部表示。這也解釋了為什么改DBTIMEZONE、ALTER SESSION SET TIME_ZONE全都沒用——它們只影響顯示不碰存量數(shù)據(jù)。一個直白的例子某地區(qū)把夏令時起點從 3 月最后一個周日改到第二個周日落在這一小時里的歷史數(shù)據(jù)按舊規(guī)則反推的 UTC 時刻會比正確值差 3600 秒。升級之后這批行的顯示值可能平移一小時這是正?,F(xiàn)象不是腳本寫錯了。2.2 三條路徑選錯會白白多停兩小時腳本包一般會把三種做法都留出入口按庫的體量選路徑動作序列停機(jī)特征適用場景單段式BEGIN_UPGRADE→UPGRADE_DATABASE→END_UPGRADE全程停機(jī)時長約等于全量掃 TSTZ 表庫不大、TSTZ 表少、能停夠時間兩段式BEGIN_PREPARE→UPGRADE_DATABASE試跑→END_PREPARE→BEGIN_UPGRADE→UPGRADE_DATABASE→END_UPGRADE試跑段不停機(jī)正式段停機(jī)生產(chǎn)庫、表多、不敢一次壓上只換 tzfile替換oracore/zoneinfo下文件后重啟一次重啟庫內(nèi)無 TSTZ 數(shù)據(jù)只需版本對齊兩段式是我默認(rèn)選的理由不是更穩(wěn)這種空話而是試跑段能提前把所有轉(zhuǎn)換異常的行炸出來。UPGRADE_DATABASE在 prepare 窗口里跑完不落盤END_PREPARE會把改動回滾代價只是多掃一遍表的 IO 和時間。生產(chǎn)庫上這一遍能換到正式窗口里不會因為臟數(shù)據(jù)中途停很劃算。第三個路徑容易被誤解只換 tzfile 只讓二進(jìn)制認(rèn)識新規(guī)則存量 TSTZ 數(shù)據(jù)仍按舊規(guī)則存著客戶端版本對齊的問題能解決數(shù)據(jù)層面的一致性問題解決不了。2.3 包里各腳本的分工腳本包各版本文件名略有出入按功能對號入座即可不要死記名字。功能分區(qū)典型內(nèi)容依賴對象什么時候跑環(huán)境體檢查v$timezone_file、v$timezone_file_supplied、TSTZ 列清單、行數(shù)估算數(shù)據(jù)字典視圖窗口前一周影響面分析調(diào)DBMS_DST.FIND_AFFECTED_TABLES輸出受影響的表和時區(qū)列表DBMS_DST窗口前一周試跑段BEGIN_PREPAREUPGRADE_DATABASE錯誤寫進(jìn)DST$ERRORSDBMS_DST低峰期可反復(fù)跑正式段END_PREPARE、BEGIN_UPGRADE、UPGRADE_DATABASE、END_UPGRADEDBMS_DST停機(jī)窗口內(nèi)校驗段版本核對、快照比對、失效對象統(tǒng)計上一階段產(chǎn)物正式段結(jié)束后立刻清理段刪快照表、刪錯誤表、刪臨時基線表SYS 權(quán)限觀察期結(jié)束后2.4 這份包管不到的三件事別指望一個 SQL 腳本包把周邊全包了有三塊必須自己收尾。一是客戶端側(cè)。應(yīng)用服務(wù)器上 Oracle Client 的 tzfile、JDBC 驅(qū)動自帶的時區(qū)數(shù)據(jù)、甚至某些語言的運行時庫都有自己的一份時區(qū)規(guī)則。數(shù)據(jù)庫升到新版本、客戶端還停在舊版本ORA-01805照樣復(fù)現(xiàn)。升級前后要逐個節(jié)點核對這一條我吃過虧。二是主備架構(gòu)。主庫做的升級會通過 redo 傳到備庫但備庫的二進(jìn)制里必須已經(jīng)包含新版本 tzfile否則 apply 會直接停住。順序是先把所有節(jié)點的二進(jìn)制和補(bǔ)丁對齊再在主庫動數(shù)據(jù)本文還有配套的精品資源點擊獲取