Oracle 19c DST v35时区补丁与DBMS_DST升级避坑指南

发布时间:2026/11/4 5:36:35
Oracle 19c DST v35时区补丁与DBMS_DST升级避坑指南 简介这份压缩包面向使用 Oracle 19c 的数据库管理员与运维人员针对 19.0.0 补丁环境下的时区升级需求提供 TSTZ 35 版本时区补丁 p31335037 的 Linux x86-64 安装文件可用于处理 ORA-39405 时区版本不一致报错。补丁包共 10 个文件以 6 个 dat 数据文件、2 个 xml 配置文件和 2 个 txt 说明文本为主压缩包约 394KB结构精简便于在测试或维护窗口内校验与部署。需要注意该补丁仅适用于 Oracle 19.3 版本添加 35 版本时区其他版本使用会报错可通过查询时区文件版本确认当前状态并结合 README 等文本了解补丁说明。对需要排查 TSTZ 版本问题、核对补丁适用条件与文件组成的读者而言可据此确认补丁批次和安装前检查项减少因版本不匹配导致的重复尝试更稳妥地安排维护与验证。已有 2570 人学习下载适合数据库运维、升级迁移和时区告警处理场景参考。1. 时区补丁不是解压就完事19c DST v35 装之前先看清三笔账某开发者半夜被叫起来处理一套 19c 库报错是跨时区跑批的结果差了三十分钟翻到最后发现不是业务代码的锅是数据库里的时区文件版本还停在旧档。这类事在 oracle19c 环境里不算罕见19.0.0 基线自带的时区文件版本偏老操作系统那边的 tzdata 早就往前跑了好几轮补丁 p31335037 干的就是把差距一次性拉到 DST v35。但它不是解压、apply 就收工的补丁——补丁本身只负责把新的时区文件铺进$ORACLE_HOME数据库内部的时区版本得另走一遍DBMS_DST升级历史里带时区的那批数据还得先探测再决定怎么处置。顺序装错、版本没对齐轻则 ORA-39405 在数据泵上反复弹重则带时区的历史数据算出来是偏的。这套流程最该先看的是正在维护 19c 单实例或 RAC、要跟上下游做时区口径对齐、或者被导入报错逼到墙角的运维。2. 打补丁之前的账19.0.0 基线、OPatch 版本与时区文件现状时区补丁的翻车点八成不在opatch apply那几秒而在打之前没把三样东西确认清楚数据库自己的版本、OPatch 的版本、以及V$TIMEZONE_FILE里现在到底是哪一档。这三样任何一样对不上后面要么补丁根本装不进去要么装进去了数据库还没认。2.1 三个版本号先对齐数据库、OPatch、timezone file先登库把当前状态摸一遍别凭印象。19c 的V$TIMEZONE_FILE只有一行有效记录VERSION字段就是当前数据库在用的时区文件版本号这个数字决定了后面DBMS_DST要升到哪个目标版本。-- 数据库版本确认是 19.0.0 这一支 select banner_full from v$version; -- 当前时区文件版本记住这个数字升级前后都要看 select version from v$timezone_file; -- 顺带确认实例状态与是否 CDB select name, cdb, open_mode from v$database;V$TIMEZONE_FILE返回的VERSION常见是 31 或 32 这一档具体取决于你手上这套ORACLE_HOME打到了哪个月的 RU。这个值不是补丁一装就自动变的很多人的误区就在这——补丁把/u01/app/oracle/product/19.0.0/dbhome_1/oracore/zoneinfo/下的timezlrg_35.dat放进去了但数据库启动时读哪个文件是由数据字典里的版本号决定的不跑升级流程就还是老版本在生效。再看 OPatch这个工具版本太旧会直接导致补丁识别失败# OPatch 版本19c 上常见做法是 12.2.0.1.36 及以上 $ORACLE_HOME/OPatch/opatch version # 已装补丁清单顺便存一份基线回滚时要用 $ORACLE_HOME/OPatch/opatch lsinventory -detail /backup/lsinventory_before_$(date %F).log如果opatch version低于 12.2.0.1.36先单独把 OPatch 升上去再谈补丁。OPatch 升级是替换$ORACLE_HOME/OPatch整个目录替换前把旧目录改名留底出问题直接改回来就行这一步比补丁本身好救得多。2.2 补丁包里到底有什么p31335037 的组成与安装形态拿到p31335037_190000_Linux-x86-64.zip之后不要直接解压到$ORACLE_HOME先看结构。这个包的命名规则本身就带信息190000表示面向 19.0.0 的ORACLE_HOMELinux-x86-64表示平台31335037是补丁号。解压后的目录里除了README.html、etc/config这些标准件还有一份README.txt里面写着这个补丁的前置条件和是否需要额外跑脚本值得花五分钟看一遍。# 先列出压缩包内容确认目录层级再解压 unzip -l p31335037_190000_Linux-x86-64.zip | head -20 # 解压到独立的补丁目录不要放在 ORACLE_HOME 里面 mkdir -p /u01/soft/patches cd /u01/soft/patches unzip /u01/soft/p31335037_190000_Linux-x86-64.zip # 解压后应该能看到 31335037 目录 ls -ld /u01/soft/patches/31335037这个补丁属于时区数据类补丁安装形态是二进制文件替换不带 SQL 脚本所以它不归datapatch管。这一点和 RU 完全不同很多人习惯性 apply 完就跑datapatch看到输出里 0 个应用就以为失败了其实是正常现象。真正的“落地”动作是后面的DBMS_DST升级这个顺序不能反。提示如果这套库是 RAC补丁要在每个节点的$ORACLE_HOME上分别 apply$GRID_HOME不需要动时区补丁只影响数据库侧。2.3 备份与回退预案打之前要留的后路时区升级是不可逆的——或者说回退的代价远大于重装。DBMS_DST升级完再想退回旧版本官方没有提供反向脚本只能靠备份恢复。所以打之前这几样必须齐全缺一样我都建议先别动手。备份对象手段用途数据库全量RMANbackup database plus archivelog时区升级失败后整库回退$ORACLE_HOMEtar整目录打包OPatch 回滚、文件被覆盖后比对补丁清单opatch lsinventory -detail确认回滚后状态回到基线受影响数据清单DBMS_DST.FIND_AFFECTED_TSTZ结果升级后核对数据是否被正确转换# 1) 数据库全备带归档 rman target / EOF backup database plus archivelog; backup current controlfile; EOF # 2) ORACLE_HOME 整目录打包注意排除临时目录 tar -czf /backup/oracle_home_$(date %F).tar.gz \ --exclude*/temp/* --exclude*/log/* \ $ORACLE_HOMEtar这一步看着笨但时区升级出问题时它是最快的后悔药——$ORACLE_HOME/oracore/zoneinfo/下的.dat文件被覆盖后直接比对两个版本的文件就能判断补丁到底有没有铺进去不用靠猜。3. 应用补丁OPatch 命令行里每一步的实际含义补丁应用这一步本身不复杂复杂的是环境变量没对、服务没停干净、冲突没提前查。我一般把这三件事拆成三段做每段都要看到预期输出才往下走。3.1 停库停监听的顺序与环境变量确认第一条命令永远是确认环境变量不是 apply。在错误的ORACLE_HOME里打补丁是新手最容易犯的错尤其是机器上装过多套 19c 的时候——$ORACLE_HOME指向 A 库$ORACLE_SID连的是 B 库opatch apply会把补丁铺到 A 库上然后你在 B 库里怎么查都查不到白白排查半天。# 三连确认任何一个输出不对就停下来 echo ORACLE_HOME $ORACLE_HOME echo ORACLE_SID $ORACLE_SID which opatch # 必须落在 $ORACLE_HOME/OPatch/opatch 下 # 确认 opatch 与当前 ORACLE_HOME 匹配 $ORACLE_HOME/OPatch/opatch lsinventory | head -5确认无误之后再停服务。单实例和 RAC 的停法不一样RAC 要走srvctl让集群感知到实例下线否则补丁打完了实例起不来还得回头清状态。# 单实例先停监听再停实例 lsnrctl stop sqlplus / as sysdba EOF shutdown immediate; exit EOF # RAC用 srvctl 停整库别直接 shutdown srvctl stop database -d ORCL -o immediate srvctl status database -d ORCL # 确认所有实例都已停止停监听这一步在单实例上不是必须的但我会做——补丁替换期间如果有客户端连进来触发 ORA-01034日志里会混进无关报错排查时干扰太大。3.2 冲突检查与 opatch apply 的参数取舍在补丁目录里执行冲突检查这一步比 apply 更重要。它会告诉你这个补丁和已装的哪些补丁有文件重叠重叠的如果已经被更高版本的补丁覆盖过apply 会直接拒绝。cd /u01/soft/patches/31335037 # 冲突检查-ph 后面跟补丁目录 $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./输出里如果只看到Prereq checkConflictAgainstOHWithDetail passed就可以往下走。如果报Patch 31335037 conflicts with patch XXXXXXXX先看是谁覆盖谁——时区补丁的文件是oracore/zoneinfo/下的固定文件名如果之前打过更高版本的时区补丁比如 DST v36 及以上这个补丁就是降级opatch 会拦住。# 正式应用默认交互式确认 $ORACLE_HOME/OPatch/opatch apply # 无人值守场景比如批量节点加 -silent $ORACLE_HOME/OPatch/opatch apply -silent交互式会列出补丁信息、ORACLE_HOME路径、受影响组件最后让你输入y。我一般不用-silent因为这一步的输出是判断补丁有没有正确识别的关键——如果Components一栏里没有oracle.server或版本对不上说明补丁包和ORACLE_HOME不匹配此时CtrlC还来得及。apply 完成后有两件事必须确认# 1) 补丁已登记 $ORACLE_HOME/OPatch/opatch lspatches | grep 31335037 # 2) 时区文件已铺到位 ls -l $ORACLE_HOME/oracore/zoneinfo/ | grep -E timezlrg_35|timezone_35第二条是关键。opatch lspatches里有记录只说明补丁注册成功timezlrg_35.dat存在才说明文件真的铺进去了。两个文件类别要分清timezone_35.dat是精简版只含有限的时区timezlrg_35.dat是大文件版19c 默认用的是后者。3.3 datapatch 跑一遍的意义与启动顺序前面说过时区补丁不带 SQL 脚本但datapatch我还是会跑一次目的不是打补丁是确认没有遗留的 SQL 补丁没应用——有时候机器上前一次 RU 打了一半没跑datapatch趁重启一起收掉。# 先把库启到 open 状态datapatch 需要实例可连 srvctl start database -d ORCL # RAC # 或单实例 sqlplus / as sysdba EOF startup; exit EOF lsnrctl start # 跑 datapatch看输出里 Applied 数量和 Errors 数量 $ORACLE_HOME/OPatch/datapatch -verbose时区补丁场景下正常输出里SQL Patching部分应该是 0 个补丁被应用Errors为 0。如果Errors大于 0先别急着往下走时区升级datapatch的日志在$ORACLE_BASE/cfgtoollogs/sqlpatch/下面按时间戳找最新的那个目录里面有具体报错。CDB 环境下datapatch会自动处理所有 PDB但输出里每个 PDB 都会单独列一行要逐个看有没有失败。我见过一次PDB$SEED报错导致整个datapatch中断后面的 PDB 全没跑Errors只显示 1很容易漏看。到这一步补丁在文件层面和注册层面都已经到位但数据库的时区版本还停在老档。真正的重头戏在下一章。4. 升级时区文件DBMS_DST 从旧版本走到 35 的完整流程DBMS_DST这套流程分三段探测、升级、收尾。探测阶段不改任何业务数据只统计哪些行会被时区偏移影响升级阶段才是真正动数据。中间那张错误表是整件事的黑匣子探测和升级都要靠它定位问题行。4.1 先探测哪些数据会被时区升级碰到探测前先确认当前版本BEGIN_PREPARE的参数必须是目标版本 35写错了会创建一个目标不对的升级窗口后面再执行就得先清理再重来。-- 记录基线 select version from v$timezone_file; -- 开启探测窗口参数是目标时区版本 exec dbms_dst.begin_prepare(35);begin_prepare会创建几张内部表其中sys.dst$error_table用来记录升级时会出问题的行。接着调探测接口declare n number; begin dbms_dst.find_affected_tstz(affected_rows n); dbms_output.put_line(受影响行数: || n); end; / -- 探测结束关掉准备窗口 exec dbms_dst.end_prepare;find_affected_tstz只统计TIMESTAMP WITH TIME ZONE和TIMESTAMP WITH LOCAL TIME ZONE两类列里、转换后偏移量会变的行。affected_rows输出大于 0 是正常的不必紧张——只要这些行转换后是“正确的”就只是展示值变化。真正要关注的是那些本身就存了错时区的行它们才是业务口径对不上的源头。如果想知道具体是哪些表哪些行查错误表select * from sys.dst$error_table where rownum 20;这个表里有OWNER、TABLE_NAME、COLUMN_NAME、ROWID这些信息可以直接拿ROWID回原表定位。探测阶段没写进错误表的行升级时也不会写所以这一步的结果就是后续核对的清单。注意BEGIN_PREPARE之后必须END_PREPARE否则会留下半开的升级窗口下次再执行BEGIN_UPGRADE会报 ORA-56930 之类的错得先手工清理。4.2 正式升级startup upgrade 到 end_upgrade 的完整顺序正式升级要重启到 upgrade 模式这一点和普通补丁流程不一样容易漏。顺序错一步BEGIN_UPGRADE会报“数据库未处于可升级状态”。-- 1) 关库 shutdown immediate; -- 2) 以 upgrade 模式启动 startup upgrade; -- 3) 开启升级窗口参数是目标版本 35 exec dbms_dst.begin_upgrade(35);begin_upgrade会把数据库切到受限状态只有SYSDBA能连业务连接会被挡在外面。这也是为什么时区升级必须约窗口——它不是 online 操作。-- 4) 执行实际的数据升级耗时取决于带时区数据的量 exec dbms_dst.upgrade_database;upgrade_database这一步会遍历所有带时区列的表把旧时区规则下的存储值重新计算一遍。表多、行多的时候这一步可能跑几十分钟不要中途CtrlC中断后恢复的成本很高。-- 5) 结束升级写回数据字典 exec dbms_dst.end_upgrade; -- 6) 重启到正常模式 shutdown immediate; startup;end_upgrade做完之后V$TIMEZONE_FILE里的VERSION会变成 35。如果还是旧数字只有两种可能补丁文件没铺进去或者升级流程没走完。前者回第 3 章查timezlrg_35.dat是否存在后者查sys.dst$upgrade_history里有没有对应的升级记录。如果探测阶段发现受影响行数很大、升级窗口不够可以分批处理先用DBMS_DST.UPGRADE_DATABASE里的parallel参数部分版本支持提高并发或者按 schema 分批。19c 上更常见的做法是把窗口拉长一次性做完因为分批升级会反复创建和关闭窗口出错概率反而高。4.3 PDB 与 Data Pump多租户下要单独走一遍CDB 环境下的时区升级不是一条命令搞定。CDB$ROOT和每个 PDB 都要走同样的流程而且顺序有讲究先CDB$ROOT再各个PDBPDB$SEED不能升级——它是模板版本跟着新创建的 PDB 走。-- 先升根容器 alter session set container CDB$ROOT; exec dbms_dst.begin_upgrade(35); exec dbms_dst.upgrade_database; exec dbms_dst.end_upgrade; -- 再逐个 PDB注意每次都要 switch container alter session set container PDB1; exec dbms_dst.begin_upgrade(35); exec dbms_dst.upgrade_database; exec dbms_dst.end_upgrade;每个 PDB 的执行必须在SYSDBA连到对应容器下进行alter session set container之后要重新确认当前容器是不是对的。曾经有人在CDB$ROOT里连续执行了三次begin_upgrade以为升了三个 PDB结果只在根容器上重复开窗PDB 一个没动后面数据泵导入直接撞上 ORA-39405。Data Pump 这条线必须单独提19c 的expdp/impdp在导出时会把源库的时区版本一起记进 dmp 文件导入到目标库时如果目标库时区版本低于源库直接报 ORA-39405 拒绝导入。解决方式只有两种——把目标库升到同版本或更高或者用impdp的ignore参数不推荐数据口径会歪。所以如果这套库是某个数据流转链路的目标端升级时区不是选择题是前置条件。5. 避坑与排查时区补丁最常见的几处翻车下面这几条是按报错出现频率排的从补丁应用阶段到业务暴露阶段都有。每条按现象、原因、解决三段写照着对号入座就行。5.1 补丁应用阶段的三个坑坑一补丁应用成功但V$TIMEZONE_FILE没变。现象opatch lspatches能看到 31335037timezlrg_35.dat也在目录里但查V$TIMEZONE_FILE还是旧版本。原因补丁只负责铺文件数据库内部版本要在DBMS_DST升级后才更新这两件事是分开的。解决确认timezlrg_35.dat存在后按第 4 章的流程走一遍begin_upgrade到end_upgrade重启后再查。坑二opatch apply报Patch 31335037 is not applicable to the current OH。现象补丁包明明是对着 19.0.0 下载的apply 时却报不适用。原因通常是三个$ORACLE_HOME指向了别的版本OPatch 版本太低识别不了补丁元数据补丁包下载或解压时损坏。解决先echo $ORACLE_HOME确认路径再opatch version确认版本最后拿unzip -t校验压缩包完整性。三个都正常还报错去看README.txt里的Prerequisites有些补丁要求先装某个前置补丁。坑三补丁回滚后实例起不来。现象opatch rollback -id 31335037执行成功但startup报文件缺失。原因回滚把timezlrg_35.dat删了但数据库的时区版本已经被DBMS_DST改到 35启动时找不到对应的.dat文件。解决时区升级之后想回滚补丁必须先恢复数据字典到旧版本——实际做法是用 2.3 里的 RMAN 备份整库恢复单独 rollback 补丁是不够的。这也是我强调时区升级前必须整库备份的原因。5.2 时区升级阶段的坑坑四DBMS_DST.FIND_AFFECTED_TSTZ报 ORA-56930 或找不到错误表。现象执行探测时报“升级窗口已打开”或“错误表不存在”。原因上一次BEGIN_PREPARE没正常结束留下了半开的窗口或者sys.dst$error_table被手工删过。解决先查select * from sys.dst$upgrade_history确认有没有残留记录有的话执行exec dbms_dst.end_prepare关掉窗口再重新begin_prepare。错误表被删的情况只能重建建议直接用begin_prepare让系统自己建。坑五升级过程中报 ORA-01805提示数据库时区文件版本不一致。现象upgrade_database执行到中途报 ORA-01805或者完成后部分查询继续报。原因ORA-01805 的意思是客户端、数据库、时区文件三者版本对不上通常发生在升级过程中数据库已经切到 v35、但客户端还在用旧版本的tzdata。解决先确认V$TIMEZONE_FILE已经是 35再更新应用服务器的时区库如果是 JDBC 客户端检查驱动版本和oracle.jdbc.timezoneAsRegion参数。5.3 业务暴露阶段的坑坑六升级后报表时间整体偏了半小时。现象升级完成后某些报表的时间列显示比预期早或晚 30 分钟。原因这些列存的TIMESTAMP WITH LOCAL TIME ZONE值在写入时就没按规范传时区数据库按会话时区做了隐式转换升级后规则变了旧值的解释跟着变。解决用 4.1 探测阶段留下的sys.dst$error_table定位具体表和行逐个核对业务语义该修数据的修数据该改应用写法的改写法。这类问题不是补丁造成的是原来就埋着的升级只是把它翻出来了。坑七数据泵导入报 ORA-39405目标库拒绝接收。现象impdp一开始就失败提示源库的 TSTZ 版本高于目标库。原因迁移链路里源端已经升到 v35目标端还在 v32 或更低。解决把目标库也升到 v35或者先从源端导出时用expdp的version参数降级只能降到数据库版本支持的最低值时区版本管不了。实际做法是两端对齐别指望绕过。6. 装完怎么验证三条 SQL 加一次时间穿越测试时区补丁的“装完”不能只看 OPatch 的输出得让数据库自己证明它在用新规则。我固定用下面这组检查前后不到两分钟但能覆盖版本、转换、边界三件事。-- 1) 时区文件版本必须等于 35 select version from v$timezone_file; -- 2) 当前会话的数据库时区确认没被应用层改歪 select dbtimezone, sessiontimezone from dual; -- 3) 一次跨时区转换看结果是否与预期偏移一致 select from_tz(timestamp 2021-07-01 12:00:00, Asia/Shanghai) at time zone America/New_York as ny_time from dual;第 3 条的结果应该是纽约当天 00:00:00夏令时期间 UTC-4。如果算出来是 23:00 或 01:00说明还在用旧时区规则回头查V$TIMEZONE_FILE。光有常规转换还不够真正能验证 DST 规则是否正确的是“时间穿越”——挑一个夏令时切换的边界时刻做转换。美国 2021 年 3 月 14 日凌晨 2 点直接跳到 3 点这个不存在的时刻是检验时区文件版本的最好样本-- 不存在的本地时刻新版本会按规则做偏移处理 select from_tz(timestamp 2021-03-14 02:30:00, America/New_York) at time zone UTC as utc_time from dual; -- 对照系统时间确认服务器时区库与数据库一致验证项检查手段期望结果补丁注册opatch lspatches | grep 31335037有记录文件落盘ls $ORACLE_HOME/oracore/zoneinfo/timezlrg_35.dat文件存在数据库版本select version from v$timezone_file35常规转换上海 12:00 转纽约00:00夏令时边界转换纽约 02:30 转 UTC不报错按规则偏移数据泵兼容目标库V$TIMEZONE_FILE不低于源库最后一条容易被忽略如果这套库是数据流转链路的一环验完自己还得去看一眼上下游的时区版本。某次我这边升完 v35第二天上游推过来的 dmp 就导不进去了查下来是上游还在 v32对方的补丁窗口排在两周后。从那以后我每次升时区都会先把链路两端select version from v$timezone_file的结果截个图发到变更群里确认对端也排上了窗口才动手。这套 p31335037 的 Linux x86-64 包我一般和README.txt、补丁号对照表放在一个目录里下次再遇到 19c 的时区问题按文件名p31335037_190000_Linux-x86-64.zip找过去就能直接开工希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询