深入解析:由expdp遇到ORA-7445问题的深入展开

李真旭(Roger)

ACOUG 核心专家,Oracle ACE,云和恩墨技术专家

编辑手记:由一个问题入手,深入其根本原因,层层递进,细致分析,由点及面,这是DBA进阶的捷径之一。

某客户说一套数据库由于非正常关机重启之后,进行数据导出发现报错,expdp 无法正常工作,报错之后直接退出:

而检查此时的 alert log 可以发现有如下类似的错误:

从上面的信息我们可以得到如下几个结论:

1、expdp 的写进程报错,因为日志产生是 dw 进程。

2、dw进程报错的原因是遭遇了 ora-07445 [klufprd()+321] 错误。

3、对于 [klufprd()+321] 这个函数,非常少见,但是从前面2点我们可以知道这肯定与 buffer cache 有关系。

所以要临时解决这个问题也很简单。通过 alter system flush buffer_cache 刷新缓存之后,再次进行 expdp 操作。

后续客户尝试了之后,发现 expdp 操作虽然仍然会报错,但是 expdp 不会异常终止,会继续完成后面其他对象的导出。

进一步分析报错的信息可以看到,有如下这样的提示:

很明显,这里提到这个这个表,恰好就是 expdp 报错所遇到的表,只不过我们刷新 buffer cache 之后,expdp 可以跳过这个表继续完成其他对象的导出。

从上述的信息来看,这里存在错误。客户也意识到,通过 dbv 对数据文件进行检查,但是发现文件并没有损坏。

这里我们要注意,dbv 同时是检查物理坏块,对于逻辑坏块通常无能为力,当然块内的逻辑错误,这类型的块 dbv 是可以检查出来的。

但是从这里的信息来看,Oracle 发现所需要的这行记录 row 01808438.0 应该在 file 6 block 33784 中找到,但是却并没有发现。

注意,这里的 file 6 block 33784 本身是完好的。

那么这里的 row 01808438.0 表示什么含义呢? 其实这是表示的 nrid;这可以理解为一直指针;其中前面一部分是表现 rdba 地址,后面表现行编号。

如果要进一步分析为什么会这个错误,我们怎么办呢? 很简单,分别将 block 33784以及rdba 01808438(16进制) 进行 dump。 如下是转换的脚本:

日志报错中提到的是 row 01808438.0 ,那么我们首先来分析 file 6 block 33848的dump:

上述类似表示的是 rdba 地址 01808438 的第0行,也就是我们大家所理解的第一行。我们可以发现这行记录中,行头存在一个nrid地址。

说到 nrid 地址,这通常是针对行链接,行迁移才会遇到的一种情况。那么这里为什么会出现呢?

行迁移几种,最常见的一种其实是 block 内的。一个 block 中单条记录的最大列数是255列,当一行记录的列超过255时,其他的列数据库会被 oracle 分成另外一个 row piece 存在同一个 block 中(当然也有可能存到其他 block)。

也就是说超过255列的行数据,会被分成多个 row piece;而当我们读取这个行数据时,怎么知道是一个完整的整体呢?

答案就是 nrid,oracle 通过 nrid 来将这多个 row piece 串在一起,组成一个完整的行数据。

想到这一点,那么我们再回头去看下前面的错误。row 01808438.0 表示这个 block 的第0行,而该 block 的第0行所存在的 nrid 地址是:0x018083f8.e

那么我们进一步到 block 0x018083f8 中去寻找第e行记录,发现结果是这样的:

上述类似表示的是 rdba 地址01808438的第0行,也就是我们大家所理解的第一行。我们可以发现这行记录中,行头存在一个 nrid 地址。

说到 nrid 地址,这通常是针对行链接,行迁移才会遇到的一种情况。那么这里为什么会出现呢?

行迁移几种,最常见的一种其实是 block 内的。一个 block 中单条记录的最大列数是255列,当一行记录的列超过255时,其他的列数据库会被oracle 分成另外一个 row piece 存在同一个 block 中(当然也有可能存到其他 block)。

也就是说超过255列的行数据,会被分成多个 row piece;而当我们读取这个行数据时,怎么知道是一个完整的整体呢?

答案就是 nrid,oracle 通过nrid来将这多个 row piece 串在一起,组成一个完整的行数据。

想到这一点,那么我们再回头去看下前面的错误。row 01808438.0 表示这个 block 的第0行,而该 block 的第0行所存在的 nrid 地址是:0x018083f8.e

那么我们进一步到 block 0x018083f8 中去寻找第e行记录,发现结果是这样的:

我们可以看到这里对应的记录根本就没有。因为该 block 最后一条记录是 row 13,也就是第14行,也是一个 row piece,而且存在一个 nrid.

该 nrid 是 0x018083f8.c,这表示该 block 33784 第12行记录。跟 row 13 是组合成一条完整行记录的。

换句话说,我们前面报错的那条记录,应该有2个 row piece,其中一个 row piece 是存在的,其中一个 row piece 本应该存在在 33784 block 中。

但是由于找不到该 row piece,因此 oracle 报了上述的错误。

实际上该错误遇到之后,我们通常以为是 index 的问题,通过 drop 重建可以解决,然而这里的问题比较特殊,据说是表的数据有问题。

所以这就是为什么客户重建 index 会报错的原因:

最后,我们清楚了所有原因,那么要解决该问题很简单。通过 rowid 的方式跳过这行有问题的记录,将其他数据取出,重建表即可。

原文发布于微信公众号 - 数据和云(OraNews)

原文发表时间:2016-06-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏更流畅、简洁的软件开发方式

【自然框架】稳定版beta1——源码下载,Demo说明

在线演示:http://demo.naturefw.com/ 开源协议   一直想说来着,可是总忘。开源协议采用 BSD开源协议。   一直在说开源,但只是把源...

2065
来自专栏情情说

RabbitMQ实战:性能和安全

前两篇介绍了RabbitMQ在可用性、监控方面的考虑,这是基础保障,因为在某些场景下是不容许丢失消息的,但它和性能往往是对立的,需要根据业务场景做取舍。

5898
来自专栏有趣的Python

13- vue django restful framework 打造生鲜超市 -drf的权限验证Vue+Django REST framework实战

Vue+Django REST framework实战 使用Python3.6与Django2.0.2(Django-rest-framework)以及前端v...

3679
来自专栏Python爬虫与算法进阶

强大的异步爬虫 with aiohttp

看到现在网络上大多讲的都是requests、scrapy,却没有说到爬虫中的神器:aiohttp

842
来自专栏张善友的专栏

微软开源 C++ REST SDK

微软的代号为Casablanca的C++ REST SDK已经基于Apache许可证开源。它被描述为“微软为了以原生代码支持基于云的客户端/服务器通信所做的努力...

23010
来自专栏性能与架构

mysql分布式前端代理 - Amoeba

image.png Amoeba是一个开源项目,致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当SQL路由器功能,具有负载均衡...

3365
来自专栏为数不多的Android技巧

如何调试Android Framework?

Linus有一句名言广为人知:Read the fucking source code. 但其实,要深入理解某个软件、框架或者系统的工作原理,仅仅「看」代码是远...

701
来自专栏小白安全

FreeBuf发布某CMS注入分析及注入点总结

Bluecms是一个地方网站的开源的cms,在很多地方性的网站上应用还是不少的,今天在逛seebug的时候看到了一个漏洞的公告。 ? 有公告但是这里还没...

3518
来自专栏iKcamp

iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 错误处理

沪江CCtalk视频地址:https://www.cctalk.com/v/15114923887518 处理错误请求 爱能遮掩一切过错。 当我们在访问一个站...

3706
来自专栏about云

Kafka权威指南 —— 1.2 初识Kafka

什么是Kafka Apache Kafka是一个基于分布式日志提交机制设计的发布订阅系统。数据在kafka中持久化,用户可以随时按需读取。另外数据以分布式的方...

3906

扫码关注云+社区