ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Oracle 10g跨平台迁移实战:从Unix到Linux的完整指南

Oracle 10g跨平台迁移实战:从Unix到Linux的完整指南 说实话前阵子刚做完一个让我印象特别深的迁移项目一套跑了快十年的 Oracle 10g 库从 Unix 平台整体搬到 Linux。这类任务在 DBA 眼里属于“看着简单、做起来处处是坑”的典型。数据文件不能直接拷环境变量要重新配字符集转不好就是一片乱码就连最基础的 exp/imp 都可能因为版本差异给你弄出点意外。这篇文章就从我这次实战的完整路线出发把 Oracle 10g 跨平台迁移从方案选型、目标端 Linux 环境准备、逻辑导出的实操细节到上线后的校验与回退策略一层层拆开讲清楚。如果你手头也有一套老库要从 Unix 迁到 Linux或者正在评估这类迁移的可行性这篇文章可以作为你的第一份参考清单。1. 跨平台迁移难在哪先搞懂平台差异与字节序1.1 为什么 Unix 平台的数据文件不能直接拷到 Linux很多人的第一反应是把 Oracle 的数据文件、控制文件、日志文件用 scp 直接拷到 Linux 上然后改个参数路径不就能启动了吗这个想法在跨平台场景下基本行不通。原因在于 Oracle 数据文件并不是普通的文本文件它内部存储的数据块格式与操作系统的字节序息息相关。早期 Unix 服务器比如 HP-UXPA-RISC、IBM AIX、Solaris SPARC采用的都是大端Big Endian字节序而 Linux 跑在 x86/x64 架构上采用小端Little Endian字节序。大端和小端在内存里的字节排列顺序是相反的Oracle 数据文件里的数据块一旦跨字节序拷贝数据库读取时完全无法解析直接启动会报错或者出现莫名其妙的 ORA-600 内部错误。你可以通过下面这条 SQL 查看所有平台的字节序信息SELECT PLATFORM_ID, PLATFORM_NAME, ENDIAN_FORMAT FROM V$TRANSPORTABLE_PLATFORM ORDER BY PLATFORM_ID;这个视图最后会派上大用场因为它也给出了目标平台对应的 GUID 信息这是后文提到 RMAN Convert 时要用到的关键参数。换句话说跨平台迁移第一件事不是打开迁移工具而是先确认源库这个平台能不能静态复制不能就老老实实走逻辑迁移或转换工具。1.2 迁移方案选型逻辑导出、RMAN Convert、DG 三选一Oracle 10g 场景下跨平台迁移的可行方案大体有三种逻辑导出exp/imp 或 expdp/impdp、RMAN Convert Database、以及 Data Guard 跨平台搭建。三者的定位完全不同适用条件也不一样。我整理了一下对比方案实现方式优点缺点适用场景exp/imp逻辑数据导出再导入跨平台、跨版本通用对象覆盖全面字符集可转换速度慢停机窗口大10g 对大库不友好数据量中等、停机时间充裕的库expdp/impdp数据泵方式逻辑迁移并发高速度快支持重映射表空间性能远优于传统 exp需要创建 Directory 对象10g 起才支持10.2.0 以上版本、数据量大、对象结构复杂RMAN Convert Database数据文件格式转换不改变数据直接转换字节序速度快10g 限制多字符集要求一致参数复杂实施难度大同字节序平台或特殊场景Data Guard 跨平台逻辑 Standby / 跨平台 DG停机时间极短在线迁移搭建复杂度高逻辑 DG 同步受限对停机窗口要求极高且团队能力较强从实际操作经验看Oracle 10g 的 RMAN Convert Database 功能还很初级不像 11g 之后的版本那么成熟。Convert 命令需要目标平台 GUID而且要求源库和目标库的字符集完全一致一旦源库字符集需要调整RMAN 方式就彻底走不通。因此绝大多数普通项目都选择了逻辑导出这条路。最后的选型其实取决于三个因素数据量有多大、停机窗口是多少、源库和目标库字符集要不要变。如果这三样都不确定优先考虑 exp/imp因为兼容性最强出错后也更容易排查。1.3 版本与字符集摸底的三个必查命令跨平台迁移前对源环境的“体检”比想象中重要。我曾经见过有同事迁移到一半发现源库版本是 10.1.0.2而目标端直接装了 10.2.0.4逻辑导出工具直接报版本不兼容。所以第一步永远是确认版本和字符集。下面是迁移前我必跑的三类基础 SQL-- 查看数据库版本和补丁 SELECT * FROM V$VERSION; -- 查看字符集、国家字符集 SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER IN (NLS_CHARACTERSET, NLS_LANGUAGE, NLS_TERRITORY); -- 查看数据库平台和 endian 格式 SELECT PLATFORM_NAME, ENDIAN_FORMAT FROM V$TRANSPORTABLE_PLATFORM WHERE PLATFORM_NAME (SELECT PLATFORM_NAME FROM V$DATABASE);字符集摸底尤其关键。源库如果是典型的 WE8ISO8859P1 或 ZHS16GBK而目标端计划建 AL32UTF8那就意味着导入过程中会发生字符集转换一个汉字在源库可能占 2 个字节转换到 AL32UTF8 后会占 3 个字节原有 VARCHAR2 字段长度很可能不够用导入时报 ORA-12899 是家常便饭。除此之外还要检查源库有没有特殊对象比如大对象、分区表、XMLType、物化视图以及用到的序列数量。这些对象在 exp/imp 里的处理方式各不相同有些是直接创建失败需要手工补。总的来说迁移方案不是在脑子里拍板的而是先摸清楚这些底数再动手。2. 目标端Linux环境准备从OS层到实例参数2.1 文件系统、目录与系统权限规划Unix 环境里文件系统类型五花八门比如 AIX 的 JFS2、HP-UX 的 VxFS而 Linux 这边主流是 XFS 和 ext4。Oracle 10g 那个年代部署时大多用 ext3但现在新服务器基本都用 XFS稳定性更好对大数据文件的并发读写也更有优势。挂载时建议加上 rw、noatime、nodiratime 选项避免不必要的元数据更新拖累 I/O。目录规划方面建议把软件和数据分开ORACLE_BASE/u01/app/oracle ORACLE_HOME/u01/app/oracle/product/10.2.0/db_1 DATA_DIR/db/oradata/orcl ARCHIVE_DIR/db/archive目录权限不要偷懒直接给 755 加上属主 oracle:oinstall。很多新手习惯用 root 跑 Oracle 安装程序这在 10g 时代虽然能装成功但后续维护极其折磨。正确的做法是新建专用账号groupadd dba groupadd oinstall useradd -g oinstall -G dba -m oracle对比一下源端 Unix 的账号规划尽量保持目标端账号名、组名、用户 ID 一致。应用层代码里如果写死了操作系统账号路径不一致的地方会悄悄溜到下一个环节。2.2 Oracle 10g在Linux上的安装要点Oracle 10g 在 Linux 上安装的坑主要集中在内核参数和依赖包上这两块搞定了安装过程基本顺风顺水。内核参数是最常见的启动失败源头比如 SGA 分配不上、信号量不足等。我常用的参数参考如下参数示例值作用kernel.shmmax2147483648单个共享内存段最大字节数kernel.shmall2097152共享内存页总数kernel.sem250 32000 100 128信号量配置SEMMSL/SEMMNS/SEMOPM/SEMMNIfs.file-max65536文件句柄上限net.ipv4.ip_local_port_range1024 65000本地端口范围连接池时很关键设置完执行 sysctl -p 生效。依赖包方面10.2.0.4 在 RHEL 5 上比较省心需要 binutils、compat-libstdc-33、libaio-devel 等安装介质里的对应说明写得很清楚。如果在 RHEL 6 上装过程会多一些补丁不建议新手尝试。还有一个小细节值得单独提源端 Unix 环境变量里 NLS_LANG 通常已经设置例如 NLS_LANGAMERICAN_AMERICA.ZHS16GBK。迁移到 Linux 后如果目标库字符集变了NLS_LANG 要跟着调整否则客户端连上新库会出现乱码。2.3 数据库参数与表空间预建的关键配置目标端建库时有几个参数必须与源库保持一致或明确评估后再变化。首当其冲的是 DB_BLOCK_SIZE如果源库默认 8K目标端也必须是 8K逻辑迁移虽然不涉及数据文件物理格式但建库时一旦定了 16K后续导入时会因为块大小不一致产生额外适配问题。其次是 SGA_TARGET 和 PGA_AGGREGATE_TARGET。源库的 SGA 是几十 GB不代表目标端 Linux 上也能直接配一样大因为 Linux 的共享内存管理方式和 Unix 的 SysV 信号量机制有差异同时还得看物理内存和 hugepages 配置。我一般建议先按源库 buffer cache 与 shared pool 之和设置 SGA_TARGET观察运行后再动态调整。表空间预建是迁移成功与否的隐形因素。传统 imp 工具不支持表空间重映射如果源库表空间叫 TS_DATA目标端也必须建一个同名表空间否则会在 CREATE TABLE 阶段失败。expdp/impdp 就灵活一些可以加 REMAP_TABLESPACE 参数映射到不同名字。但无论如何建议在导入前先把以下内容建好CREATE TABLESPACE TS_DATA DATAFILE /db/oradata/orcl/ts_data01.dbf SIZE 10G AUTOEXTEND ON; CREATE TEMPORARY TABLESPACE TEMP TEMPFILE /db/oradata/orcl/temp01.dbf SIZE 5G; ALTER DATABASE DEFAULT TABLESPACE TS_DATA; ALTER DATABASE DEFAULT TEMPORARY TABLESPACE TEMP;另外不要忘了用户和默认表空间。迁移过程中最常见的报错之一就是 ORA-01950原因是用户没有目标表空间的使用配额。导入前最好对每一个要导入的 schema 执行一遍ALTER USER SCOTT QUOTA UNLIMITED ON TS_DATA;这一步成本极低却能省掉大量导入中断后的排查时间。3. 全库逻辑导出10g环境下最稳妥的迁移动作3.1 exp/imp 与 expdp/impdp 的选择依据如果源库是 10.1.0.2那基本只有 exp/imp 一条路因为 Data Pump 是 10.2.0 才引入的功能。如果源端是 10.2.0.4并且停机窗口允许我更推荐 expdp/impdp尤其在处理大表时并行度带来的提速非常明显。两者的核心差异我列了个表对比维度exp/impexpdp/impdp速度单进程慢可并行快目录对象无需必须创建 Directory字符集转换支持支持大字段处理较繁琐更稳定表空间重映射不支持支持 REMAP_TABLESPACE2GB dump 文件需分卷 FILE 参数通过 FILESIZE 控制版本要求10g 全版本可用10.2.0 起如果库比较大比如超过 500GB用 exp/imp 可能要跑十几个小时而 expdp 在 parallel4 的情况下通常能压缩到三分之一左右的时间。当然前提是源库的 I/O 和 CPU 余量允许。3.2 导出端的注意事项导出前最重要的一个动作是确定一致性策略。Oracle 10g 的 exp 工具是基于 undo 实现读一致性如果业务没有停跑大表很容易触发 ORA-01555 snapshot too old。最省心的做法是直接停应用再进行导出虽然停机时间看着长了点但能保证导出的数据在时间点上是一致的。exp 的命令可以参考这样写exp system/passwordsource_db \ file/backup/exp_2024.dmp \ log/backup/exp.log \ buffer10485760 \ statisticsnone \ grantsy \ consistenty如果对一致性要求更高并且源库是 10.2.0 且开了闪回特性可以考虑 expdp 结合 FLASHBACK_SCN 参数绑定到一个稳定的 SCN 上导出。不过要注意这依赖系统 undo 保留时间保留不够还是会出现快照过旧。expdp 的导出命令示例expdp system/passwordsource_db \ directoryDMP_DIR \ dumpfilefull_%U.dmp \ logfileexpdp.log \ parallel4 \ job_namefull_expdp导出前不要忘记清理回收站。源库里如果回收站攒了太多 drop 过的对象会白白增加导出体积。另外我建议先查一下 dba_segments 里最大的几张表确认它们在目标端临时表空间有足够的空间否则导入阶段会因为排序空间不足失败。3.3 导入端的常见报错与规避导入过程是我这次迁移里花时间最多的地方。10g 的 imp 对异常处理相对粗糙经常导入到一半报错但日志里只给一句话真正的根因要翻到前面几万行找。最常见的错误就是 ORA-12899导入时目标端字段长度不够。前面提到的字符集转换比如 WE8ISO8859P1 到 AL32UTF8源库里 VARCHAR2(20) 字段存 20 个字符转换后需要的字节数可能变成 60字段定义仍然是 20 字节直接失败了。解决思路是在字符集转换场景下导入前先对相关表执行字段扩展导入稳定后再视情况改回去。第二个高频问题是 ORA-01950也就是没有表空间配额。前文已经提过提前给所有账号分配配额即可。第三个问题是权限相关对象没有完全导入比如 dblink、public synonym。exp 默认导用户下的对象但 public synonym 需要以 SYSTEM 或具备相应权限的账号导出才会覆盖。导入后一定要重新检查一遍SELECT OWNER, SYNONYM_NAME, TABLE_OWNER, TABLE_NAME FROM ALL_SYNONYMS WHERE OWNER PUBLIC;最后是序列问题。imp 导入序列时会把序列重新创建注意它并不会保留源库的当前值而是按照序列的初始值重新开始。如果业务已经跑到了几百万而导入后的序列从 1 开始应用一插入就必然主键冲突。所以迁移前一定要记录源库的序列当前值导入后手动跳变到目标值。这个场景下由于 Oracle 10g 的 ALTER SEQUENCE 不支持直接 RESTART我用的经典方案是ALTER SEQUENCE SEQ_ORDER_ID INCREMENT BY GAP_VALUE; SELECT SEQ_ORDER_ID.NEXTVAL FROM DUAL; ALTER SEQUENCE SEQ_ORDER_ID INCREMENT BY 1;这样通过一次临时增量跳变把序列值推到安全区间。4. 对象与数据的校验数据库搬过去了不代表业务能跑4.1 数据一致性验证组合导入完成不等于迁移成功。我见过太多案例导入后 count 行数都对得上但一查具体某张业务主表发现分区丢失、索引失效、触发器状态不对。所以数据校验要做组合式检查。第一层是对象数量对比。用脚本在源库和目标库分别执行SELECT OWNER, OBJECT_TYPE, COUNT(*) FROM DBA_OBJECTS GROUP BY OWNER, OBJECT_TYPE ORDER BY OWNER, OBJECT_TYPE;对比两边输出结果差异一目了然。如果目标端少了某个类型比如少了 20 个 SEQUENCE那就知道是序列没有导入完全。第二层是行数对比。对核心业务表迁移前用脚本批量生成 count 语句迁移后在目标端逐表执行输出到一个结果文件再用 diff 对比。10g 没有 11g 以后的并行 COUNT 工具但可以把大表按主键范围拆成多个 count 并行跑效率会高不少。第三层是约束和触发器状态。检查目标端的 FK、CHECK、触发器等是否处于 ENABLED 状态导入时如果因为表顺序问题导致外键创建失败需要手工重新启用。4.2 应用连接与权限核对清单数据库层校验通过了应用能不能连上来就是另一回事。跨平台迁移最容易忽略的就是 TNS 和 JDBC 连接串的变更。源端如果是 HP-UXtnsnames.ora 里可能这样写ORCL (DESCRIPTION (ADDRESS (PROTOCOL TCP)(HOST old_host)(PORT 1521)) (CONNECT_DATA (SERVER DEDICATED)(SERVICE_NAME ORCL)) )迁到 Linux 后主机名和 IP 变了连接串必须整体更新。还有一种是应用用 SID 直连10g 里面 SID 和 service_name 的区别容易混淆如果连接串里写 SID目标端 listener.ora 里必须正确配置静态注册 SID_LIST_LISTENER。权限核对建议做这几个查询-- 用户的默认表空间和临时表空间 SELECT USERNAME, DEFAULT_TABLESPACE, TEMPORARY_TABLESPACE FROM DBA_USERS; -- 系统权限 SELECT GRANTEE, PRIVILEGE FROM DBA_SYS_PRIVS WHERE GRANTEE IN (SCOTT,APP_USER); -- 角色权限 SELECT GRANTEE, GRANTED_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTEE IN (SCOTT,APP_USER);最后别忘了 dblink。如果目标库里有指向其他库的 database link导入后对方地址或账号没有变化还好一旦有变化应用连上触发远程表查询时就会立刻报错。4.3 通过应用回归测试暴露的隐藏差异数据校验和对象校验做得再细也只是静态层面。真正隐藏的差异通常在应用跑起来之后才暴露。我这次项目里就碰到一个典型的隐藏差异源库 NLS_SORT 是 BINARY目标库改成了 AL32UTF8 后应用里一条按中文排序的 SQL 返回顺序完全变了从业务角度看就是列表顺序不对。这个问题的根源不是数据迁移错了而是字符集和排序规则的连带变化。还有一个是基于 VARCHAR2 字节长度的隐性问题。源库字符集 ZHS16GBK 下 VARCHAR2(100) 可以存 100 个汉字迁移到 AL32UTF8 后同样字段如果是按默认 BYTE 语义就只能存大约 33 个汉字。应用中如果提交超过限制的中文内容就会收到 ORA-12899而这个问题在源库里根本不存在。所以应用回归测试不能只测增删改查主流程还需要覆盖排序、中文检索、超长文本提交、时区显示这几类边界场景。跨平台迁移的掌握度其实就是在这些边界场景里体现出来的。5. 上线的最后一公里开箱验证与回退预案5.1 切换流程与时间轴控制对付跨平台迁移我最喜欢用的是“事前多演练事中守节奏”的方式。切换当天的时间轴要提前排好每一项任务后面都要留缓冲时间。下面是一个参考时间轴基于我这次项目 800GB 左右的数据量时间任务预估耗时T-7 天完成全流程演练修正导入脚本1 天T-1 天停止应用写入断开连接30 分钟T-1 天最终一致性导出2~3 小时T-1 天传输 dump 文件到目标端1 小时T-0 天目标端导入4~6 小时T-0 天对象编译与数据校验1.5 小时T-0 天应用连接切换30 分钟T0~2 周线上观察期保留源端环境持续时间轴上最容易失控的是目标端导入环节尤其是没提前演练过的库。所以 T-7 天那次演练不是走过场而是要把整个导入流程在准生产环境完整跑一遍记录各阶段耗时才能在切换当天给出可靠的时间预估。5.2 回退策略跨平台迁移最大的安全感来自原环境没有被破坏。我的策略是切换期间源端 Unix 数据库保持 shutdown 状态但环境原封不动目标端 Linux 库上线后如果业务出现短期内无法修复的严重问题直接把源端数据库启动恢复监听应用改一下连接指向就能回到旧环境。这里要强调一点回退只解决“新库不可用”的问题不负责把切换期间目标库新增的数据反向搬回到源库。所以在切换前就明确规则源库停机后不再接受任何写入应用侧只允许目标库接收新数据。这样回退逻辑才干净。如果做好了这个约束回退就是几行命令的事# 源端 Unix 库 sqlplus / as sysdba startup # 确认监听状态 lsnrctl start反过来如果目标库跑了一两周发现数据有问题而源端环境还保留着也可以继续在源库做增量导出再补丁方式导入目标库。不过这种情况较少见大多数问题在切入前就能通过演练发现。5.3 我踩过的坑和最终建议最后分享几个这次迁移中真实踩过的坑希望后来者能绕开。第一个坑是源库是 10.1.0.2最开始直接用了 expdp结果连工具都不存在报“unknown command”。后来才意识到 Data Pump 从 10.2.0 才开始有。版本确认一定放到第一步不要假设。第二个坑是字符集没做充分样例测试。源库 ZHS16GBK目标库 AL32UTF8我以为 exp/imp 会自动处理结果导进去后一张业务大表的几个 VARCHAR2 字段频繁报 ORA-12899最后只能反复查日志定位到具体表临时加长字段再重导。这个教训让我养成了新习惯任何涉及字符集变化的迁移先抽几张具有代表性的表做小规模导入测试确认字符转换行为后再全量执行。第三个坑是目标库忘了创建 Directory 对象就急着跑 expdp报 ORA-39002典型的低级错误。像这种固定动作建议写进迁移 checklist迁移前逐项打勾。第四个坑是序列跳变没有在停业务期间做。当时我在目标库导入完成后直接启动了应用结果插入业务表时主键冲突排查了半天才发现是新库序列值还是旧的 start with 值。后来重建序列并做了 increment 跳变问题才解决。我个人在实际操作中的体会是Oracle 10g 跨平台迁移本身不是技术门槛多高的任务但它的链条很长每一步都有可能出现环境层面的差异。把源端数据搬过去只是第一步真正考验人的是对字符集、权限、连接、序列、统计信息这些细枝末节的把控。用一份经过演练的操作清单严格按时间轴推进把这些细节都钉死迁移这件事就不会翻车。
返回列表