资讯详情

资讯详情

Oracle时区升级实战:DBMS_DST分步脚本与避坑指南

简介面向需要维护 Oracle 数据库时区版本的 DBA 与运维人员这份脚本工具包用于将数据库时区版本调整至较新状态通常配合时区补丁使用适合版本升级、补丁实施前后的核查与变更场景。压缩包共 4 个 SQL 文件整体约 16KB体积轻量包含时区版本检查、统计信息核查及升级应用等脚本脚本内附有使用说明便于按流程完成变更前确认与变更执行。目前已有 1693 人学习下载说明其在 Oracle 时区维护场景中具有一定参考价值。读者可获得一套可直接用于时区版本核查与调整的脚本集合借助检查脚本了解当前时区状态再通过应用脚本完成调整同时结合统计信息相关脚本辅助验证减少手工编写 SQL 的成本也为补丁配合、问题排查和变更记录提供可复用的操作依据。1. 时区版本落后的隐性代价一次 TSTZ 数据错位引发的排查某次季度对账业务方拿着两张报表找过来同一批订单在源库和报表库里差了整整一个小时而且只发生在某一段日期。查到最后不是 ETL 的锅是数据库的时区文件版本还停在旧版本——那段时间某地区的夏令时规则已经变了TIMESTAMP WITH TIME ZONE列写进去时用的换算规则和现在读出来用的不是同一套。DBMS_DST 这套系统包就是拿来把数据库的时区版本往前推的但它步骤多、状态机强、中途失败代价高照着文档手敲一遍在生产上基本等于走钢丝。这份 DBMS_DST_scriptsV1.9.zip 做的事是把「检查基线 → 探路预检 → 正式升级 → 重算历史数据 → 收尾校验」拆成可以分步执行、分步重跑的脚本集合中间任何一步翻车都能停下来看清状态再决定往哪走。它适合手里攥着 Oracle 库、版本不算太新、又不敢直接在生产上照着文档敲命令的 DBA 和运维开发不太适合想一键无脑升级的人因为时区这事的代价只有事后才知道。2. 脚本包结构DBMS_DST 的状态机被拆成了八段 SQL2.1 目录结构与各文件职责拿到包先别急着解压执行先看结构。这个包的组织方式很朴素bin放 shell 入口sql放 SQL 片段conf放变量logs放执行日志没有编译产物也没有外部依赖解压就能读。这是我比较喜欢的一类运维脚本包——你可以在执行前把每一行都读一遍。DBMS_DST_scriptsV1.9/ ├── bin/ │ ├── dst_exec.sh # 统一入口按子命令分发 │ ├── dst_check.sh # 只读体检不动数据 │ └── dst_verify.sh # 升级后的独立校验入口 ├── sql/ │ ├── 00_env.sql # 版本、状态、TSTZ 列规模基线 │ ├── 01_prepare.sql # BEGIN_PREPARE 探路 │ ├── 02_affected.sql # 读取受影响表与错误表 │ ├── 03_end_prepare.sql # END_PREPARE 收探路 │ ├── 04_upgrade.sql # BEGIN_UPGRADE 进入升级态 │ ├── 05_tz_tables.sql # UPGRADE_TZ_TABLES 重算历史数据 │ ├── 06_end_upgrade.sql # END_UPGRADE 收尾 │ └── 07_verify.sql # 升级后一致性校验 ├── conf/ │ └── dst.conf # 连接串、日志目录、并行度、干跑开关 ├── logs/ └── README.md为什么是八段而不是一个大 SQL因为 DBMS_DST 本质上是个三态机PROPS$里的DST_UPGRADE_STATE在NONE、PREPARE、UPGRADE之间切换每一步失败后的恢复动作完全不同。拆成独立文件你才能在05_tz_tables.sql跑到一半因 UNDO 不足挂掉时单独把这一段拉起来重跑而不必从头再来一遍探路扫描。顺带一提文件命名里的数字前缀。这种写法看着土但在窗口期手忙脚乱的时候很救命——按ls的默认排序就是执行顺序不会出现先跑end_upgrade再跑begin_upgrade这种血泪事故。2.2 技术栈与运行前提这个包用到的技术栈很窄几乎全是数据库自带的组件作用备注Bash 4入口脚本与日志封装用到[[ ]]、set -euo pipefailSQL*Plus执行 SQL 片段不需要额外客户端DBMS_DST时区升级核心包数据库自带需要 EXECUTE 权限PROPS$ / DST$*状态与结果视图只读为主别手工改运行前提比技术栈重要得多这几条缺一条都不该开始新的时区文件必须已经随补丁落到了数据库主机的oracore/zoneinfo目录下否则BEGIN_UPGRADE之后拿不到目标版本必须有完整的物理备份因为 DBMS_DST 没有官方回退过程所谓回退就是恢复备份必须有停机窗口UPGRADE_TZ_TABLES期间对含 TSTZ 列的表是重活还有归档空间和 UNDO 表空间的余量这两项是最常见的翻车点后面单独讲。判断目标时区文件在不在最直接的办法是看目录里有没有对应版本的文件再和V$TIMEZONE_FILE的VERSION列对比。如果目录里的最高版本和视图里的版本一样说明补丁根本没打上这时候跑脚本只是白跑一遍探路。常见做法是先在一套同版本的测试库上完整走一遍把每个阶段的耗时记下来再按比例推算生产窗口。我一般会把这个耗时表写进变更单比任何口头保证都有说服力。2.3 配置文件与日志约定conf/dst.conf是整个包唯一的可变量入口改这里就够了不要动 SQL。典型的配置长这样# dst.conf —— 所有脚本共享的变量集中在这里 DB_CONN/ as sysdba # 本地实例用操作系统认证最省事 SQL_DIR./sql LOG_DIR./logs DRY_RUN1 # 1只检查不执行0真正执行 TZ_ATTACH_ID1 # prepare 与 upgrade 的批次标识 BATCH_COMMIT1 # 重算阶段是否单表提交几个参数值得单独说。DB_CONN之所以写/ as sysdba是因为BEGIN_PREPARE和BEGIN_UPGRADE都要求 SYSDBA 权限普通 DBA 角色在这两个过程上会直接报权限不足远程执行的话需要密码文件并且remote_login_passwordfile是EXCLUSIVE否则连不上。DRY_RUN是这个包里比较贴心的设计置 1 时入口脚本只跑00_env.sql和02_affected.sql这类只读片段把所有会改状态的调用挡在门外适合第一次上手时先看个究竟。TZ_ATTACH_ID是传给BEGIN_PREPARE和BEGIN_UPGRADE的批次号探路阶段产生的错误记录会带上这个号。脚本默认给 1如果同一套库要反复探路比如先处理掉一批函数索引再重来把它改成 2、3 递增能避免读到上一轮的残留结果。日志方面每个 SQL 片段执行时都会 tee 一份到logs/下文件名带时间戳。这个约定看起来无所谓真出问题时是黑匣子——05_tz_tables.sql的执行日志里能看到每张表处理到哪个时间点配合归档日志能算出准确的重算速率。3. 核心链路拆解从探路到收尾的四段执行逻辑3.1 阶段一环境与版本基线检查00_env.sql是整条链路里唯一的纯只读片段作用是把「现在长什么样」记录下来。很多人跳过这一步直接 prepare结果升级完发现版本号没变回头一查是补丁压根没打。代码不长但每一句都有用-- 00_env.sql升级前的只读基线不修改任何数据 SET LINESIZE 200 PAGESIZE 100 COLUMN FILENAME FORMAT A40 -- 1. 当前实例实际加载的时区文件版本 SELECT FILENAME, VERSION FROM V$TIMEZONE_FILE; -- 2. 数据库版本与是否为容器库决定要不要进 PDB 再走一遍 SELECT BANNER FROM V$VERSION WHERE ROWNUM 1; SELECT CDB FROM V$DATABASE; -- 3. 升级状态只有 NONE 才允许开始 SELECT DST_UPGRADE_STATE FROM PROPS$; -- 4. 含 TSTZ 列的列数量用来估算重算窗口 SELECT COUNT(*) AS tstz_columns FROM DBA_TAB_COLUMNS WHERE DATA_TYPE LIKE TIMESTAMP%WITH TIME ZONE;第一条查出来的VERSION是判断能不能开始的关键。如果它已经是补丁目录里的最高版本说明这库不需要升级脚本跑到01_prepare.sql会因为状态冲突直接退出这是正常的保护行为不是脚本坏了。第二条的CDB列如果是YES意味着后面每个 PDB 都要单独走一遍完整流程容器库的时区版本是按容器维护的不是全局一份。第四条那个计数是估算窗口用的经验值。列数本身不代表数据量但配合DBA_TAB_COLUMNS和DBA_TABLES.NUM_ROWS做一次关联粗估哪些表是大头比拍脑袋定停机时长靠谱得多。我一般会把这条查询的结果导出来按行数倒序排前几张表单独确认能不能接受全表扫描的代价。3.2 阶段二探路与错误表解读探路阶段是整个流程里性价比最高的一步。BEGIN_PREPARE会扫描所有含 TSTZ 列的表把每一行数据用新时区规则重新换算一遍但不写回磁盘只把换算失败的记录丢进SYS.DST$ERROR_TABLE。换句话说它是一次不动刀的预演。-- 01_prepare.sql开启探路阶段只读扫描不改数据 SET SERVEROUTPUT ON SIZE UNLIMITED DECLARE v_state VARCHAR2(30); BEGIN -- 先确认状态干净避免重复 prepare 导致 attach_id 混乱 SELECT DST_UPGRADE_STATE INTO v_state FROM PROPS$; IF v_state NONE THEN RAISE_APPLICATION_ERROR(-20001, 当前状态为 || v_state || 请先处理残留状态); END IF; -- 1 为本次探路的批次标识后续错误记录按它归类 DBMS_DST.BEGIN_PREPARE(1); DBMS_OUTPUT.PUT_LINE(prepare 已开启attach_id1); END; /这里的RAISE_APPLICATION_ERROR是脚本作者加的保护。BEGIN_PREPARE本身并不禁止重复调用但重复调用会产生多批错误记录混在一起就分不清哪条是哪轮的。用-20001这个自定义错误号快速失败比让你在错误表里考古要人道得多。探路跑完接着读结果-- 02_affected.sql读取探路结果 COLUMN OWNER FORMAT A20 COLUMN TABLE_NAME FORMAT A32 COLUMN COLUMN_NAME FORMAT A30 -- 受影响的表与列清单重算阶段按这个范围走 SELECT OWNER, TABLE_NAME, COLUMN_NAME FROM SYS.DST$AFFECTED_TABLES ORDER BY OWNER, TABLE_NAME; -- 无法自动重算的记录必须人工处理完才能继续 SELECT * FROM SYS.DST$ERROR_TABLE;DST$AFFECTED_TABLES给出的是「有哪些列需要重算」这个数量直接决定05_tz_tables.sql的耗时。DST$ERROR_TABLE才是重头戏——每一行代表一条数据在新规则下算不出来常见原因是这行数据本身就非法比如手写进去的时区名在新版本里被删了或者列上挂了函数索引导致表达式求值失败。这两张表的关系要理清受影响的表不等于出错的表前者是范围后者是障碍。探路阶段的价值就是让你在动数据之前先把障碍列出来。如果错误表为空说明这次升级大概率顺风顺水如果错误表里有几百条那就得逐条判断是修数据还是改结构。3.3 阶段三进入升级态与历史数据重算BEGIN_UPGRADE之后数据库进入升级态这期间不建议做任何 DDL也不该让业务大批量写入。它和探路的区别在于探路只是算升级态是准备真的改。-- 04_upgrade.sql正式切入升级态 SET SERVEROUTPUT ON SIZE UNLIMITED DECLARE v_state VARCHAR2(30); BEGIN SELECT DST_UPGRADE_STATE INTO v_state FROM PROPS$; IF v_state NONE THEN -- 跳过探路直接升级是允许的但等于放弃了预检不建议 DBMS_OUTPUT.PUT_LINE(警告未做 prepare 直接升级); END IF; DBMS_DST.BEGIN_UPGRADE(1); END; /跳过探路在语法上可行但等于闭着眼睛开车。脚本里保留了这条分支并打了个警告属于「留门但提醒」的做法实际执行时我不建议走这条路。真正的重活是下面这段-- 05_tz_tables.sql重算所有 TSTZ 列的历史数据 SET TIMING ON BEGIN -- 过程内部按表逐个处理耗时与含 TSTZ 列的数据量成正比 DBMS_DST.UPGRADE_TZ_TABLES; COMMIT; END; /这段 SQL 只有三行但它是整个流程里最长的一步也是最容易把库跑挂的一步。UPGRADE_TZ_TABLES会把每一行 TSTZ 数据的内部表示按新规则重写过程中产生大量 UNDO 和 REDO。一张千万行的宽表跑到一半把 UNDO 表空间撑爆现象是 ORA-30036 然后会话卡死属于经典事故。关于分批这里有个坑要提前说清不同数据库版本的UPGRADE_TZ_TABLES签名不完全一样有的版本支持传入并行度参数有的不支持。网上流传的一些带参数脚本直接抄过来会报 PLS-00306 参数个数或类型错误。稳妥做法是先DESC DBMS_DST看一眼本机签名再决定怎么调包里的05_tz_tables.sql用的是无参调用兼容性最好但速度慢量大时靠窗口时长硬扛。如果实在扛不住常见做法是在BEGIN_UPGRADE之后、重算之前用DST$AFFECTED_TABLES把行数最大的几张表挑出来单独评估是否可以先停业务、单独处理或者把整个重算拆成两个窗口分两次跑。注意重算是可以只跑一部分的——DST$AFFECTED_TABLES里已处理完的表会从清单里消失这就是断点续跑的天然依据。3.4 阶段四收尾与重启验证-- 06_end_upgrade.sql收尾执行后必须重启实例 BEGIN DBMS_DST.END_UPGRADE; END; / -- 07_verify.sql升级后校验 SELECT FILENAME, VERSION FROM V$TIMEZONE_FILE; -- 应为空非空说明还有表没重算完 SELECT OWNER, TABLE_NAME, COLUMN_NAME FROM SYS.DST$AFFECTED_TABLES; -- 状态应回到 NONE SELECT DST_UPGRADE_STATE FROM PROPS$; -- 抽查当前会话时区下的偏移是否正常 SELECT TZ_OFFSET(SESSIONTIMEZONE) AS cur_offset FROM DUAL;END_UPGRADE之后数据字典里的时区版本才算落实但内存里已加载的规则不会立刻全部刷新所以必须重启实例。这一步经常被省略现象是库里版本号看着变了、应用查出来的时间还是老样子然后开始怀疑数据没重算。重启后的校验顺序也有讲究先看V$TIMEZONE_FILE的VERSION有没有变成目标值这是硬指标再看DST$AFFECTED_TABLES是不是空的非空说明有表漏了最后看PROPS$状态回到NONE保证下次还能正常走流程。三条都对上才轮到业务侧抽查数据。4. 跑起来部署、干跑与正式执行的完整命令序列4.1 部署与连接配置解压不需要额外依赖注意别解到业务目录下找个独立的运维目录放着# 解压到独立目录避免和业务文件混在一起 mkdir -p /opt/dba cd /opt/dba unzip DBMS_DST_scriptsV1.9.zip # 脚本需要可执行权限 chmod x DBMS_DST_scriptsV1.9/bin/*.sh接着改conf/dst.conf。本地执行时DB_CONN保持/ as sysdba就行这是操作系统认证不用输密码也不会有密码写进日志的风险。如果必须在跳板机上远程执行改写成sys/passwordPRODDB as sysdba同时确认目标库的密码文件参数是EXCLUSIVE否则 SYSDBA 远程登录会被拒。环境变量这块有个小细节脚本里调sqlplus如果服务器上有多个数据库软件目录一定要先把ORACLE_HOME和PATH指向目标实例那一套ORACLE_SID也显式导出。我见过在同一台机器上ORACLE_SID指错、结果对着另一个实例跑完整个流程的案例事后对账才发现升错了库。4.2 干跑先把影响面看清楚DRY_RUN1的时候入口脚本只跑只读片段这是第一次上手该做的事# 只读体检不改变任何状态 cd /opt/dba/DBMS_DST_scriptsV1.9 ./bin/dst_exec.sh check输出会落到logs/下带时间戳的文件里。重点看三样东西V$TIMEZONE_FILE的当前版本tstz_columns的数量以及PROPS$的状态。如果状态不是NONE说明这套库之前有人跑过一半没收拾干净这时候别急着重跑先搞清楚残留状态是哪来的。干跑阶段还可以顺手做个只读的BEGIN_PREPARE吗不行BEGIN_PREPARE会改状态不属于只读。真想预检受影响的表范围用DBA_TAB_COLUMNS自己筛一遍就够了误差不大。4.3 正式执行与过程监控确认基线没问题把DRY_RUN改成 0然后按阶段推进。入口脚本的逻辑大致是这样#!/usr/bin/env bash # dst_exec.sh统一入口按子命令分发到对应 SQL set -euo pipefail BASE_DIR$(cd $(dirname ${BASH_SOURCE[0]})/.. pwd) SQL_DIR${BASE_DIR}/sql LOG_DIR${BASE_DIR}/logs source ${BASE_DIR}/conf/dst.conf mkdir -p ${LOG_DIR} TS$(date %Y%m%d_%H%M%S) run_sql() { local script$1 local log${LOG_DIR}/${script%.sql}_${TS}.log # -S 静默 bannerWHENEVER SQLERROR 保证 SQL 失败时 shell 拿到非零退出码 sqlplus -S ${DB_CONN} EOF | tee ${log} WHENEVER SQLERROR EXIT 3 SET SERVEROUTPUT ON SIZE UNLIMITED SET TIMING ON ${SQL_DIR}/${script} EXIT EOF } case ${1:-} in check) run_sql 00_env.sql ;; prepare) run_sql 01_prepare.sql; run_sql 02_affected.sql ;; upgrade) run_sql 04_upgrade.sql; run_sql 05_tz_tables.sql; run_sql 06_end_upgrade.sql ;; verify) run_sql 07_verify.sql ;; *) echo 用法: $0 {check|prepare|upgrade|verify}; exit 1 ;; esacset -euo pipefail和WHENEVER SQLERROR EXIT 3是这套脚本能放心用的关键。前者保证 shell 在任意一步失败时立刻停住不会出现「prepare 失败了还接着跑 upgrade」的连锁事故后者保证sqlplus把 SQL 层的错误翻译成进程退出码让 shell 能识别。两句话加起来等于给流程上了一道不用盯着的保险。正式跑05_tz_tables.sql这一段时别在前台干等用nohup挂后台并盯日志# 重算阶段耗时不可控挂后台并实时看进度 nohup ./bin/dst_exec.sh upgrade upgrade.out 21 # 另开一个会话看日志尾部 tail -f logs/05_tz_tables_*.log4.4 执行后校验与记录跑完upgrade子命令后先重启实例再执行verify# 重启实例让新时区规则完全生效 sqlplus -S / as sysdba EOF SHUTDOWN IMMEDIATE; STARTUP; EXIT; EOF # 校验版本、残留表与状态 ./bin/dst_exec.sh verify校验结果建议和干跑阶段的基线日志一起归档。这不是形式主义——过几个月再有人问「这个库的时区版本是什么时候升的、升之前是什么版本」翻日志比翻记忆靠谱。我一般会把00_env.sql和07_verify.sql的输出并排放在同一个变更记录里前后对照一目了然。5. 避坑与排查五类高频失败的现象、原因与解决5.1 权限不足导致探路直接失败现象执行01_prepare.sql时报 ORA-01031 或 DBMS_DST 提示权限不足脚本以退出码 3 结束。原因BEGIN_PREPARE、BEGIN_UPGRADE、END_UPGRADE这几个过程要求 SYSDBA普通 DBA 角色或者只授予了EXECUTE ON DBMS_DST的账号都不够。远程连接时还多一层密码文件参数不是EXCLUSIVESYSDBA 根本连不进来。解决本地一律走操作系统认证/ as sysdba远程先改remote_login_passwordfileEXCLUSIVE并重启再用带as sysdba的连接串。改完先在00_env.sql那条只读查询上验证连接身份别等到 prepare 阶段才发现连错账号。5.2 容器库只升了根容器现象根容器里V$TIMEZONE_FILE的版本已经是新的切到某个 PDB 里一查还是旧版本业务报表照旧差一小时。原因时区文件版本是按容器各自维护的根容器升完不等于 PDB 升完。脚本在根容器里跑完一整套很容易误以为大功告成。解决升级前先用SELECT CDB FROM V$DATABASE确认是不是容器库是的话根容器走完流程后对每个 PDB 执行ALTER SESSION SET CONTAINER pdb_name;再完整走一遍。清单可以在00_env.sql里补一条SELECT NAME, CON_ID FROM V$CONTAINERS把要处理的容器一次列全。5.3 重算阶段把 UNDO 或归档打爆现象05_tz_tables.sql跑到一半报 ORA-30036无法扩展 UNDO 段或者实例因为归档空间写满而挂起业务连接全部阻塞。原因UPGRADE_TZ_TABLES对每一行 TSTZ 数据都是先删后插的等效操作UNDO 和 REDO 的产生量远大于普通查询。千万行级别的表跑起来几 GB 的 UNDO 表空间十几分钟就没了。解决执行前按受影响表的行数估一次量UNDO 表空间临时扩到平时的三到五倍确认归档路径余量足够必要时把DB_RECOVERY_FILE_DEST_SIZE一起放大。窗口实在不够就拆批按 schema 或者按大表分两次跑靠DST$AFFECTED_TABLES的剩余清单续跑。5.4 函数索引与物化视图阻塞重算现象探路阶段DST$ERROR_TABLE里出现一批记录错误号是 ORA-00604 或 ORA-01858对应的表都建了函数索引或物化视图。原因重算过程中需要对这些表达式重新求值如果表达式里引用了已被废弃的时区名或者函数索引的表达式不可重入整张表的重算就会中断。解决升级前把 TSTZ 列上的函数索引、依赖它的物化视图先记下来重算前 drop 掉重算完再重建。别在重算过程中边跑边改结构那会让错误表的内容变得没法判断。处理完一批就重跑一次探路直到错误表清空为止。5.5 升级完业务侧还是旧时间现象库里版本号已经变了DST$AFFECTED_TABLES也空了但应用查出来的时间仍然差一小时。原因两种可能。一是应用连接池里缓存着升级前建立的旧连接会话时区还是老的二是客户端自己设置SESSION_TIMEZONE覆盖了服务端的默认规则。解决先重启连接池让所有连接重建这一步能解决大部分情况。还不对就抓一条会话看SESSIONTIMEZONE的实际值和应用配置里的时区设置对照。注意这类问题和数据本身无关别回头又去重算一遍数据那是白费窗口。6. 二次开发把单库脚本改成可巡检、可批量执行的运维工具单库跑通之后这套脚本真正的价值在于改造。一个人管几十套库的时候逐台解压、逐台改配置、逐台盯日志是不现实的得让它能接进已有的巡检体系。我的做法是先给入口脚本加一个只读的「快照」子命令升级前自动把状态导出成结构化文本。这一步的意义在于DBMS_DST 没有官方回退过程所谓回退就是恢复备份而恢复之后你要能说清「升级前到底是什么状态」否则事后没法验证恢复是否彻底。# 在 dst_exec.sh 的 case 里加一个 snapshot 分支 snapshot) # 把当前时区版本、升级状态、受影响列数导出成一行 JSON 风格的记录 sqlplus -S ${DB_CONN} EOF | tee ${LOG_DIR}/snapshot_${TS}.txt SET HEADING OFF FEEDBACK OFF PAGESIZE 0 SELECT {tz_version: || MAX(VERSION) || } FROM V$TIMEZONE_FILE; SELECT {dst_state: || DST_UPGRADE_STATE || } FROM PROPS$; SELECT {tstz_cols: || COUNT(*) || } FROM DBA_TAB_COLUMNS WHERE DATA_TYPE LIKE TIMESTAMP%WITH TIME ZONE; EXIT EOF ;;这段 SQL 刻意只输出三行机器可读的键值不输出表格。原因是后面要拿它做对比——升级前后各跑一次两个文件 diff 一下就知道版本有没有真的变、状态有没有干净收尾。比人工看日志靠谱得多。再往下就是批量化的部分。改造点大致三个收益和风险我列在下面改造点做法收益风险清单驱动用一份实例清单循环调dst_exec.sh check一口气摸清所有库的版本分布连接串集中存放权限要收紧阶段门禁上一步日志里出现错误就跳过后续子命令避免连锁失败需要约定统一的错误标记结果归档每次执行后把 snapshot 推到集中存储版本演进有据可查多一个存储依赖三个里面最值得先做的是阶段门禁。批量跑最怕的不是单个库失败而是失败之后脚本还在往下走把可以停下来的小问题拖成必须恢复备份的大问题。门禁的做法很简单在run_sql之后加一句grep -q ORA- ${log} exit 4粗暴但有效——反正升级窗口里没人会嫌脚本太保守。还有一个坑我踩过批量脚本里如果把DB_CONN写死成/ as sysdba在跳板机上根本连不到远端库得允许按实例覆盖连接串。我现在的写法是在清单里放两列一列 SID、一列连接串循环时把连接串作为环境变量传给子 shell覆盖dst.conf里的默认值。这样既能本地跑也能远程跑配置还集中在一处。从那以后我每次动时区版本都强制先在一套和主库同版本的空库上把 04 到 06 完整走一遍哪怕它看起来只是几个 SQL——时区这东西的代价从来不在执行那几分钟而在事后对不上账的那几个小时。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →