故障007:dexp导数莫名中断

DM技术交流QQ群:940124259

1. 问题描述

某单位现场的乙方实施人员,近期一直被dexp导出数据过程中反复出现“Code:-70037 字符串不完整”的错误所困惑,每次那两张始终导出失败,持续两个月找不到错误的关键点和突破口。按常理来说,数据导出是多么简单的事儿,恰好相反,往往越简单的事越让你怀疑人生,也是前期做事马虎导致今日的结局。

好,本人不再卖关子啦!造成此次导不出数据的原因,其一dexp在导出数据过程中会对里面的数据进行校验,字符缺失断码,会无情地中断导出,连个商量的余地没得(请不要吐槽,微笑面对人生^_^);其二表中某些行的数据确实存在不合法的字符,即字符乱码,诱发前因,是他们原先从MySQL迁移数据时,未严格检查数据,很多字符串被截断。

提前告知问题出现的原因,有点让大伙儿读不下去的感觉,认为了解即完毕。可否认真读完本人的辛苦之作,实实在在了解问题的来龙去脉,掌握到分析问题和解决问题的思路。谦虚使人进步,切记!!!现场见过太多自以为是DBA,或开发人员,总觉得自己很牛B.A.I,而实际面对问题时,挠脑袋,学了这么多方法,看了这么多书,为何用不上呢。

上菜,截图
他尝试管理工具右键导出,又尝试过dexp命令行导出,二者皆抛错中断后续的导出操作。

在这里插入图片描述
在这里插入图片描述


2. 见招拆招

2.1 抽样精准定位错误行

尽量缩小数据导出报错的范围,剔出行为特征明显的报错的第一行(首次触发报错的行位置)。得到这一行的位置,接下来排查更容易。
思路:

  1. 综合分析表中比较有特征的数据内容,比如这里按日期时间恒定常量值分组,观察数据分布,依次从小数据量中抽取异常内容记录行。
  2. 逐步限定数据行范围导出,直到从中取出第一次出现数据中断导出的位置,于是在管理工具中通过分页查询方式,定位查询出相应行记录。
-- 1. 通过自己的经验,选出具备特征的分组列,首先了解表中的数据分布情况(此处截图省略,懂核心思想即可)
select to_char(trunc(ds_create_time)), count(*) 
from "YJSCP"."graduate_recruit_enroll_resume"
group by to_char(trunc(ds_create_time))
order by 1 desc;


-- 2. 专门挑2022-03-31那天的数据(4百多条)导出测试
-- rownum<=100 rownum<=80 rownum<=70 rownum<=73 逐步接近目标真相(当然也可以编写脚本弄,这里出错的表不多,所以没必要浪费时间写脚本自动抓出)
./dexp "YJSCP"/'"xxxxxxxx"'@LOCALHOST:5237 DIRECTORY=/tmp \
   FILE=res5.dmp feedback=1 \
   TABLES="\"YJSCP\""."\"graduate_recruit_enroll_resume\"" \
   QUERY="WHERE to_char(trunc(ds_create_time))='2022-03-31' and rownum<=80" LOG=exp_2022_07_27_10_58_09.log \
   LOG_WRITE=N

-- 当时已定位到73-74行,进入下一步细致的内容分析

在这里插入图片描述


2.2 大胆推测、与人交流

观察某一条错误行的数据内容特征,专门找字符类型的字段,特别检查是否有特殊字符(XML格式/HTML格式/类似C编程语言),属于首当其冲的观察点。
和懂业务表设计的实施人员沟通,了解一些字段的含义,如果有字段注释的话,另当别论,或者字段名称易读懂的,都可以推测哪些字段可能存在数据内容异常。
为啥强调试着了解表中各字段的含义?假如一张表一百多个字段,很多列是字符文本类型,人工慢慢排查,时间太长,效率极低。能短时间内快速排查定位某些字段,岂不是很爽呢。
所以说做技术的人,不要光埋头苦干的研究(有些情况可能被理解为瞎琢磨),也要学会人与人之间的沟通,技术交流。

-- 1. 通过分页查询定位到出错行的范围
select top 73,2
from "YJSCP"."graduate_recruit_enroll_resume"
where to_char(trunc("ds_create_time")) = '2022-03-31'


-- 2.焦点移到字符类型较长的字段内容(此次案例:jcqk)
-- 其他内容已做胶敏处理。发现jcqk文本内容末尾有一个乱码的字符。

-- 3.进一步确认乱码的规律
-- 普通人可能想用like '%乱码符号',这个是不行的。
-- 这个忘截图,结论是:乱码的字符规律的是以EF或EFBF编码的字符出现,我们应当转成二进制观察。
SELECT *FROM (
SELECT
	"graduate_recruit_enroll_resume_id",
	"ds_create_user_name",
	ds_create_time,
	RIGHTSTR(jcqk, 4) linestr, -- 取后4个字符
	RAWTOHEX (rightstr(jcqk, 1)) bytestr, -- 取最后一个字符的二进制编码
	ROWNUM rn  -- 记录行号
FROM
	SYSDBA."graduate_recruit_enroll_resume"
WHERE
	trunc("ds_create_time", 'DD') = date'2022-03-31'
 ) WHERE rn IN (74, 311, 381); -- 取报错行,观察字符编码规律
 
-- 4. 核查夹杂在文本中的乱码字字符
/**
严谨的操作,是应该继续检查文本中间部分是否存在乱码。
事实上,当时场景,没往后续进行下去,针对以上末尾乱码已做修正三处问题后,再次dexp导出2022-03-31的数据不再报错,问题基本得到了解决。
特别提示:最好备份一下原表,用备份的那张表做测试修正。不要想当然在生产库的业务表上乱搞。
**/

在这里插入图片描述

在这里插入图片描述

给小伙伴们更自信的辨别,关于EF BF编码对应的各种字符集下的字符描述。
参考网址: https://www.haomeili.net/Code/DeCoding?bytes=EFBF&isHex=True

在这里插入图片描述
在这里插入图片描述

2.3 DTS迁移备份原表

不管你用什么样的方式备份表都可以,目的是保证数据的安全性。我的另一目的,通过DTS工具迁移一次表作为备份表,看DTS工具能否自动处理掉乱码的字符,省得后面手工核对和修复数据。当时蹿出这一想法,少做事且干得好,何乐而不为?可惜通过本人的验证,DTS迁移备份方案行不通,只得手工找出问题的数据行,修复乱码的字段。
第二个目的虽然未达到我的预期效果,但第一目的肯定达到的,保护原数据,测试修复备份表数据。
当时将该表迁移备份到SYSDBA用户模式下,进行全表的定位跟踪,筛选问题行。

SELECT *FROM (
SELECT
	"graduate_recruit_enroll_resume_id",
	"ds_create_user_name",
	ds_create_time,
	RIGHTSTR(jcqk, 4) linestr,
	RAWTOHEX (rightstr(jcqk, 1)) bytestr,
	ROWNUM rn  -- 这个行号比较准确的,因为未走任何索引扫描输出,是以rowid形式的聚焦表。(小伙伴细节都要考虑哟,写得每种SQL一定要符合当时场景)
FROM
	SYSDBA."graduate_recruit_enroll_resume"
WHERE
--	trunc("ds_create_time", 'DD') = date'2022-03-14'
 ) 
 WHERE bytestr IN ( 'EF', 'EFBF');

DBvear客户端管理工具,检索问题数据行截图

在这里插入图片描述

2.4 了解错误产生的逻辑(可选)

验证导出时,每一个错误输出是否跟行记录有关,即有几行存在异常数据,则打印多少次同样的错误。(可选内容)
本人喜欢研究得更透一点,多增加一节对数据报错的验证和猜想。
举例:拿2022-03-31一天的数据导出观察,报错三次字符不完整,符合本人的预想结果。这个结论对以后你处理类似的报错信息,有着一个大概的信息掌控。

./dexp "YJSCP"/'"xxxxxxxx"'@LOCALHOST:5237 DIRECTORY=/tmp \
   FILE=res5.dmp feedback=1 \
   TABLES="\"YJSCP\""."\"graduate_recruit_enroll_resume\"" \
   QUERY="WHERE to_char(trunc(ds_create_time))='2022-03-31'" LOG=exp_2022_07_27_10_58_09.log \
   LOG_WRITE=N

2.5 修复数据再验证导出

既然符合起初有多少次报错就会有多少行的数据错误问题的推断,2.4小节查询结果共有34处字符乱码,在之前乙方的导出日志中比较后,是符合结论的,那么就尝试修复问题行数据。
修复后再尝试导出整张表,如果不再报错,已经完成我们此次的修复目标,否则继续深挖文本中间的乱码。

-- 1. 修复乱码行
update SYSDBA."graduate_recruit_enroll_resume" a
SET jcqk = leftstr(jcqk, LENGTH(jcqk) - 1)
WHERE RAWTOHEX (rightstr(jcqk, 1)) IN ('EF', 'EFBF');

COMMIT;


-- 2. 尝试导出整张表
./dexp "SYSDBA"/'"xxxxxx"'@LOCALHOST:5237 DIRECTORY=/tmp  \
    FILE=res5.dmp feedback=1 TABLES="\"SYSDBA\""."\"graduate_recruit_enroll_resume\""  \
     LOG=exp_2022_07_27_10_58_09.log LOG_WRITE=N

#

2.6 生产库的数据修复任务

数据修复整个前沿操作全部弄完,至于生产库上业务表这个事,得让他们自己协调找个时间做数据修复 。
方法和步骤都教给他们,千叮咛万嘱咐,一定要事先做好备份再操作。
备份:可以整库备份,可以表物理备份,可以表复制一份,可以DTS迁移备份到其他模式下等等。。。。。


3. 心得分享

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值