ARTICLE DETAIL

资讯详情

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

达梦数据库从DM7升级到DM8全流程实战与踩坑记录

达梦数据库从DM7升级到DM8全流程实战与踩坑记录 说来有点不好意思接手公司达梦数据库版本升级这个任务的时候我对达梦的全部认知基本停留在“听说过、没见过”。在那之前我主要搞的是MySQL和Oracle那一套对于国产数据库的升级更是从来没实操过。等到真正动手才发现这根本不是“下载个新安装包覆盖一下”那么简单光是在升级路径选型上我就纠结了很久中间还出现过备份集认不出来、导入中文乱码、存储过程编译直接报错这种让人脑壳疼的问题。前前后后折腾了两三天才算是把测试环境的库平稳切过去。这篇东西就是我当时完整的学习过程和踩坑记录适合刚接触达梦数据库、或者正准备做达梦版本升级的运维和开发同学拿来当一份避坑参考。1. 先搞清楚达梦的版本家底才不会选错升级目标1.1 达梦不是只有一种版本先认认门牌号达梦数据库这些年迭代下来市面上能见到的主要就是DM6、DM7和DM8这几代。DM6算是老古董了现在正经生产环境里已经很难见到DM7是前些年的主力版本有不少存量系统还在跑DM8是当前的主推版本无论性能、安全性还是兼容性都比前代有明显提升。我这次要升级的就是一套跑在DM7上的业务系统。说实话DM7在功能上并不弱它继承了Oracle那一套的编程习惯存储过程、触发器、物化视图这些东西都用得很顺手。但问题在于DM7对新的SQL标准支持比较有限而且随着甲方对安全性和性能的要求越来越高底层版本的缺陷修复也得跟着新版走所以升级到DM8是迟早的事。这里想提醒一个更容易被忽略的点DM8内部也分了不少小版本。不是说安装了DM8就一劳永逸了在后续使用过程中官方会发布补丁版本。如果你手里的DM8版本很老应用里用了某些新特性或者遇到了一些已修复的Bug可能还需要在DM8这个大版本内再往上打补丁。所以做“版本升级”这件事之前第一步是搞清楚当前版本和目的版本分别是什么别把所有升级都当成“从DM7到DM8”这一个跨度。1.2 升级的目标版本不是越新越好很多刚接触达梦的朋友会有一个惯性思维升级嘛肯定要升到最新版。但我这次实际对比下来发现版本选择的逻辑应该是**“匹配你的应用而不是匹配你的好奇心”**。举个例子如果你的应用还在用比较老的JDBC驱动或者中间件版本本身不高那升到最新的DM8小版本未必是最优解。因为你不仅要考虑数据库本身的兼容性还要考虑下游驱动、连接池、ORM框架这些环节。我那会儿就差点踩了坑公司的Java应用还在用比较老的DmJdbcDriver后来升级到新版DM8之后连接直接报协议不匹配最后是把驱动jar包一起升上去才解决。所以我的建议是升级前先列一个清单把数据库版本、JDBC驱动版本、连接池版本、ORM框架版本这些全部登记一遍再统一评估目标版本。别光看数据库侧的热闹应用侧的配套版本跟不上升级完之后照样跑不了。2. 升级前的准备工作不把家底摸清楚后面全白干2.1 一条SQL先确认当前版本在做任何备份和迁移操作之前第一步永远是确认当前数据库到底是什么版本。这个操作在达梦上非常简单用disql或者图形化管理工具跑一条SQL就行SELECT * FROM v$version;查询结果会直接显示类似“DM Database Server x64 V7”或者“DM Database Server x64 V8”这样的版本标识。如果你还想看实例级别的基本信息比如实例名、端口号、启动时间这些可以接着查SELECT * FROM v$instance;我习惯把这两个查询结果都记录到升级文档里因为后续无论是写备份脚本还是做恢复都需要用到实例名和数据文件路径这些基础信息。另外也可以通过达梦自带的“DM管理工具”在界面左下方的数据库属性里看版本信息适合不习惯命令行的同学。2.2 备份是升级的唯一兜底方案这句话我想放在最前面说在达梦版本升级这种操作上备份永远是你最后的安全网。我在这次升级前做的第一件事就是触发一次完整的物理备份而不是只导出一两个业务表。当时我的备份思路是这样的用达梦自带的备份管理工具先做一次全库备份再用逻辑导出工具dexp把核心业务模式单独导了一份防止物理备份万一读取失败的时候还能拿逻辑备份“手动重建表”。可能有人会觉得做两份备份有点浪费时间但我的真实感受是升级这种操作一旦出现意外返工成本远高于备份成本。尤其是跨大版本升级的情况下物理备份集的一致性、逻辑导出文件的完整性都有可能成为最后的救命稻草。这里顺带提一下备份文件一定要放到数据库服务器本地磁盘之外的位置最理想是拷贝到另一台机器或者对象存储上。我当时就把备份文件放到了本机临时目录里结果后面安装新版本时一不小心初始化了新实例差点把临时目录覆盖掉想起来有点后怕。2.3 兼容性评估要覆盖四个维度别只盯着表结构升级前除了备份还要做一轮兼容性摸底。不要以为数据能导进去就算完事还要考虑里面的对象、语法和参数在新的数据库版本里是否仍然有效。我这次重点检查了四个方面第一个维度是表结构。看旧库中有没有用到新版本已经废弃或者改名了的数据类型。比如某些字符集相关类型、特殊的大对象类型在新老版本之间的处理逻辑会有差异。最稳妥的办法是把所有表的DDL导出来挨个扫一遍不常用类型。第二个维度是存储过程、函数和触发器。这是最容易被坑的地方。达梦的PL/SQL语法整体上兼容Oracle但DM7和DM8之间在某些内置包、系统函数名称上可能有细微变化。我后面遇到存储过程编译报错问题就出在这里。第三个维度是初始化参数。旧实例的dm.ini里配置的参数有些在新版本中可能已经不生效或者默认值变了。如果你升级完发现系统性能变化很大先回来看参数文件。第四个维度是字符集。这个是最容易引发“升级完中文全是乱码”的元凶。升级前务必确认旧库是什么字符集新库初始化时也选一样的。我后面会专门展开说这个坑。3. 三种升级路径我对比后的取舍逻辑3.1 图形化DTS迁移工具上手最快但限制不少达梦自带一个数据迁移工具DTS支持从Oracle、MySQL、SQL Server以及达梦旧版本往达梦新版本迁。这个工具的优点是界面化操作勾选源库和目标库的表、视图、存储过程就可以直接迁移对命令行不熟的同学比较友好。我在测试环境里先用DTS跑了一遍全库迁移发现在十万行级别的小表上速度不错迁移过程也很直观。但它的缺点是对于超大库、分区表特别多、或者存储过程和序列特别复杂的场景一旦中途报错很难从断点继续往往只能修完重来。而且DTS在批量迁移大数据量表时效率和带宽利用一般纯跑一个几千万行的核心流水表会明显感觉到速度变慢。3.2 命令行dexp/dimp最灵活但要自己写清参数第二种路径是经典的逻辑导出导入方案用达梦自带的dexp导出再用dimp导入。这个方案跟Oracle的exp/imp大同小异只要掌握参数逻辑就行。举例来说导出整个数据库dexp USERIDSYSDBA/SYSDBAlocalhost:5236 FILE/dm/backup/exp.dmp FULLY LOG/dm/backup/exp.log导入到新库dimp USERIDSYSDBA/SYSDBAlocalhost:5237 FILE/dm/backup/exp.dmp FULLY LOG/dm/backup/imp.log这套方案最大的优势是可控性强你可以指定模式、指定表甚至指定查询条件导出。而且因为是中间文本逻辑格式对不同字符集之间的转换处理更灵活。缺点则是恢复时需要重建表、重建索引、重放数据速度天然慢不适合特别大的库。另外跨版本升级时如果源库中有新版本不认识的对象类型或语法导出和导入过程中可能产生兼容性告警。3.3 物理备份恢复dmrman大库首选但版本匹配要小心第三种路径是用物理备份工具dmrman做备份恢复。这个方案最接近“复制文件”的思路速度最快对数据一致性保障也最到位适合数据量以T为单位的重型场景。dmrman备份数据库的命令大致如下RMAN BACKUP DATABASE /dm/data/DMSERVER/dm.ini FULL BACKUPSET /dm/backup/dm7_bak;恢复时再执行RMAN RESTORE DATABASE /dm/data/DMSERVER/dm.ini FROM BACKUPSET /dm/backup/dm7_bak; RMAN RECOVER DATABASE /dm/data/DMSERVER/dm.ini FROM BACKUPSET /dm/backup/dm7_bak;但有一点务必记住dmrman跨大版本恢复不是你想当然的“直接认”。我用DM8版本的dmrman尝试恢复DM7的备份集结果就遇到了“备份集格式不兼容”的报错。因为DM7和DM8的内核数据格式不一样物理备份文件无法直接跨大版本复用。这种情况下通常需要先用DM7的dmrman把备份集处理好再配合官方的升级迁移工具来衔接而不是直接用新版去还原旧版备份。3.4 三条路径怎么选一张表说清楚方案工具类型适用规模跨大版本兼容性上手难度我的评价DTS迁移工具图形化中小型库一般报错难续传低适合初次接触达梦的迁移场景dexp/dimp命令行中小型库较好可指定对象中最稳妥的通用方案我最终选用它dmrman备份恢复命令行大型库差物理格式绑定版本中高适合同版本补丁升级或同大版本内恢复结合我这次的情况数据量不算特别大但对象的复杂度高存储过程多、触发器多而且涉及跨版本升级。综合考虑后我最终选择用dexp/dimp做逻辑迁移作为主线再用DTS作为对比校验手段。这样的组合一方面保证了迁移对象的完整性另一方面也能在导入后用DTS做一些增量校验。4. 实操记录从备份恢复到应用切换的完整链路4.1 升级前的数据库备份与环境准备先说环境。我准备了两个达梦实例的机器一台跑旧的DM7端口5236另一台规划安装新的DM8端口5237。这样在迁移期间两个库可以并存应用什么时候切连接我们自己说了算而不是被停机时间逼着走。在旧库上执行逻辑导出dexp USERIDSYSDBA/SYSDBAlocalhost:5236 FILE/dm/backup/dm7_export.dmp FULLY LOG/dm/backup/dm7_export.log因为业务里存在好几个模式我在导出时直接用了FULLY把整库都导出来。这里要提醒一句导出前最好确认一下SYSDBA账号有没有目录写权限。我当时导出的目标目录权限不对dexp直接报错退出排查了好一会儿才发现是权限问题白白浪费了时间。4.2 安装新版DM8并初始化实例接着开始装DM8。新版安装包我在达梦官网下载解压后执行安装向导一路默认配置基本就能完成。不过安装完成后还有一个关键的步骤初始化实例。初始化实例使用的是dminit命令我需要手动指定数据文件路径、实例名、端口号和字符集。命令大致长这样./dminit PATH/dm/data DM8 INSTANCE_NAMEDMSERVER PORT_NUM5237 CHARSET1这里CHARSET参数特别关键。我用的是1代表GBK字符集跟源库保持一致。如果这里填错了后面导入数据很可能会导致中文乱码。如果你不确定源库到底是什么字符集可以在旧库上执行SELECT * FROM v$nls_parameters;查一下NLS字符集相关的参数再去初始化新实例。这一步看起来不起眼但真的决定后面导入数据的“脸色”。初始化完成之后通过前台方式或注册系统服务方式启动新的实例./dmserver /dm/data/DMSERVER/dm.ini启动日志里出现“SYSTEM IS READY”之类的字样就说明实例起来了。这个阶段先不要急着停旧库让新旧两个实例并行跑着后面的迁移才有缓冲余地。4.3 数据导入与对象重建接下来就是在DM8实例上执行逻辑导入dimp USERIDSYSDBA/SYSDBAlocalhost:5237 FILE/dm/backup/dm7_export.dmp FULLY LOG/dm/backup/dm8_import.logdimp执行的时间比dexp长不少因为需要重建表、索引、约束和存储过程这些对象。导入过程中我特别注意日志里有没有出现错误行。实际操作中确实有几处ERROR多数是存储过程的PL/SQL语法在新版里不兼容还有个别表因为字符集转换导致数据长度溢出。后面第6章我会专门展开这两类问题。导入完成后还要做一次“二轮导入”。什么意思呢就是说第一次导入如果有部分对象失败你不会希望重新整库再来一遍。这时候可以先用dimp的日志筛选出失败对象单独针对失败的模式或表重新导入而不是动不动就全量重来。4.4 应用侧切换与驱动更新数据导入完成后就不是“数据库自己跑起来”这么简单了。应用侧的连接要跟着切换同时要核对JDBC驱动。我们这里的Java应用使用的是SpringBootDruid连接池数据源配置差不多长这样spring: datasource: driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://192.168.1.20:5237/DMSERVER username: SYSTEM password: 123456这里ip地址和端口要改成新实例的地址。如果你之前用的是旧版DmJdbcDriver强烈建议同步升级到与新库版本匹配的驱动jar。升级驱动后还要确认Druid连接池的配置项没有变化。我曾经遇到过一种情况驱动换了新版本之后Druid在连接初始化时执行了一个旧驱动不支持的SQL导致启动报错。所以切换完应用一定要第一时间看启动日志而不是只看看数据库连接池监控面板。另外如果你习惯用Navicat这类可视化工具连接达梦升级后也要确认客户端对话框里选择的数据库版本信息是否匹配必要时升级Navicat本身。这个点看着小但对频繁用GUI调试的同学来说体验差异很大。5. 升级验收清单数据对得上业务才敢放行5.1 数据一致性验证不只是行数相等升级完最需要回答的问题是旧库的数据到底有没有一笔不差地搬过来我验证的时候没有只统计表行数因为行数一样不代表数据内容完全一致。我的做法分三步第一步对比每张核心表的count(*)确认总行数一致第二步对比若干个有代表性的字段的汇总值比如金额字段求和、日期字段的最大最小值第三步做抽样明细比对随机拉几条主键记录在旧库和新库里分别跑同一条件查询肉眼比一下结果。这一步不能图省事。我当时就遇到一张日志表的行数完全一致但其中几个长文本字段因为字符集转换被截断的情况如果不做字段级的抽样比对很难发现。5.2 存储过程和作业的自检数据对完了接下来要验证的是“数据库里的行为逻辑”。我写了一个简单的验证脚本把核心的存储过程挨个执行一遍看看有没有编译错误。达梦的存储过程在创建时不会立刻报错很多问题要到真正调用时才暴露出来所以务必逐个调用测试。另外还要检查数据库作业。旧库上如果有定时作业比如每天凌晨的清分任务这些作业在逻辑导出导入后可能不会完整迁移过来需要在新库中手工重建。我记得当时有一个日终调度作业导入后作业是出现了但对应的调度器状态不对导致任务根本没有触发这个如果上线前不检查后续要等业务方反馈才会发现就很被动了。5.3 性能对比不能升完级反而变慢数据和应用层面都验证完之后还有一道大关是性能。我的做法是挑出业务里最常用的几条SQL分别放到旧库和新库上跑看执行计划和耗时。在新库上如果发现执行计划走了索引但代价计算明显不合理可以尝试用达梦的SP_REFRESH_OPT_ENTRY这类系统包来刷新统计信息。这里也有一个经验升级后等待统计信息自动收集的时间可能比较长我当时是在导入完成后主动手工执行了统计信息更新让优化器有更准确的基数和直方图这样后续业务方点开报表就不会出现“为什么升级后SQL变慢”这种尴尬问题。6. 我在这次升级中踩过的坑和排查记录6.1 备份集跨大版本不认别用DM8恢复DM7的物理备份这是我最早踩的坑。一开始我图省事想直接用DM8的dmrman去恢复DM7的物理备份结果报错提示备份集无法识别大致意思是版本不匹配。那一刻我才意识到物理备份和逻辑备份的定位完全不同物理备份的格式深度绑定版本和内核结构跨大版本直接恢复是行不通的。如果一定要走物理备份恢复路线那就要清楚它更适合什么场景相同大版本内的小版本升级比如DM8的一个补丁版本升到另一个补丁版本。而跨大版本升级老老实实走逻辑导出导入或者利用官方提供的迁移评估工具反而更稳妥。6.2 中文乱码根因在字符集设置导入过程中我最头疼的是乱码问题。有个别字段导入进去之后中文变成了一串问号“?????”。一开始我以为是导入命令参数的问题反复调整dimp的字符集参数发现没用。后来回头查旧库字符集才意识到源库本身就是GBK而新库初始化时如果不小心把CHARSET设成了别的值导入时就会出现转码异常。这个问题的坑在于它不是全局性报错而是“部分字段坏了部分字段正常”很容易让人误以为是随机数据损坏。后来我把新实例初始化时的字符集和源库对齐重新导了一遍乱码问题就消失了。6.3 存储过程编译报错注意内置函数差异存储过程是这次升级里数量最多的失败对象。报错信息大多指向某些内置函数在新版中不存在或者函数签名发生了变化。比如项目中用到的一个处理金额格式的函数在DM7里能直接用但在DM8里需要用另一个系统包来替代。排查这类问题我的做法是先把导入日志中所有ERROR信息按对象名字归类然后逐个打开旧库和新库的对象定义做对比确认差异点后手工修改。这个步骤没有捷径只能耐心。如果你的项目里存储过程特别多建议在升级前就对这些对象做一次静态扫描把可能不兼容的函数全列出来提前改好要比导入后一个一个排查高效得多。6.4 应用连接被拒端口和加密协议都要看升级后第一次用Navicat连接新库时我遇到了“连接被拒绝”的情况。排查一想发现是新实例的端口号配置不是默认的5236而是我自定的5237所以客户端默认连5236端口自然进不去。这个点很基础但在紧急时刻确实容易忽略。还有一个隐蔽的问题新版本默认开启了更严格的通信加密要求某些旧版本的客户端或驱动连接时会因为加密协议不匹配被拒。如果碰到这类问题可以在dm.ini中检查通信加密相关参数再结合客户端的版本考虑是否需要升级。6.5 通用排查思路先看日志再查版本最后复现经历过这一圈坑我总结出来的排查顺序基本稳定成一套第一步先看数据库实例的日志文件。达梦的日志一般在安装目录的log子目录下文件名形如“dm_DMSERVER_YYYYMM.log”。很多看似莫名其妙的问题日志里已经写得很直白。第二步确认所有环节的版本是否在同一频道上。数据库版本、驱动版本、客户端版本、初始化参数版本一个都不能漏。第三步用手工操作复现问题。比如单独执行那条失败的SQL或者单独调用那个失败的存储过程通过最小化复现缩小排查范围。这套思路帮我在后面处理其他数据库问题时也省了不少力。最后再说句掏心窝的话达梦数据库版本升级这回事听着像是个安装活儿实际上更像是一部“数据搬运和验证”的连续剧。你花在备份和验证上的时间永远要比实际操作的时间多得多。我当时就是因为前期备份和兼容性评估做得足够细才敢在正式切换的时候底气比较足。希望你也能在动手之前先把上面这几个环节挨个过一遍。升级顺利跑通之后再去回想整个过程你会发现自己对达梦数据库的理解已经不是“会不会连库”的程度了而是真的摸到了它的脾气。
返回列表