
点击上方蓝字关注我们,文末有惊喜~

大家好,做下自我介绍~“rescureora”是一批Oracle技术的爱好者和实践者,我们热衷于技术原创和技术分享。我们的文章会在微信公众号“Oracle恢复实录”和博客网站“rescureora.com” 同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
在上一篇《TRUNCATE TABLE恢复系列一:深层剖析内部原理》(点击标题可直达原文)中说道,truncate table 操作的内部原理和特征,因其执行的高效性,常被开发和运维人员用于清理表的数据。常在河边走,哪有不湿鞋。如果truncate table 误操作后,想要恢复表的数据不是一件简单的技术活(如使用闪回查询恢复DML修改的数据)。
就如第一章中说的,truncate table 操作只是将空间标记为free space,未真实的清理数据。所以此时我们可以通过工具直接读取块中的内容。目前市场上类似的工具也非常多,如Oracle公司推出的dul,熊军先生写的odu等都可以实现truncate table的数据恢复。但是这些都属于收费工具,并且价格也不便宜。当然大家都想要免费的午餐,但天下哪有免费的午餐~不是九眼桥一躺那么的简单(´▽`)。在强大的Oracle世界里面,虽然没有“九眼桥一躺”那么简单,但是也有“变个招式”的方法。
Oracle已经提供了类似的工具可以直接从块中读取数据:基于rowid的方式(此方法常常被用于坏块数据的恢复),只是需要稍稍的变通一下就可以利用此方法来恢复truncate表数据的恢复。下面我们将一步一步通过实现来证明怎么通过rowid来直接恢复被truncate的数据,也会给大家提供PL/SQL恢复代码,只需要替换变量就可以用于自己环境中进行恢复。
千里之行始于足下,没有强大的理论知识,是很难在Oracle恢复的道路上走得很远、飞得很高的。我们先来回顾几个知识点:
1.truncate操作不修改表的数据块,只是通过字典基表以及段头和位图块的修改来实现快速清空表数据,释放的空间可以通过dba_free_space查询到(第一个extent不会释放)。
2.通过rowid访问数据是不需要读取表的位图信息和段头,只通过读取基表信息完成解析,就可以直接访问rowid指定块的内容。
3.rowid可以通过data_object_id,rfile_id,block_id和函数dbms_rowid.rowid_create来创建,关于该函数的参数,请参考Oracle官方文档。
4.rfile_id,block_id可以通过dba_free_space获取,data_object_id可以通过logmnr挖掘日志得到。
5.truncate表释放的空间很有可能会被分配出去,强烈建议在truncate操作后,将表空间或者数据库置于read only,如果空间已经分配给其它对象,并且也已经被格式化,此时任何工具都不可以通过扫描块来恢复。当然如果已经分配给对象,但是还没有被格式化的块是可以恢复的,此案例中也已经充分考虑到这种情况。
思路是技术人的灵魂,方案是思路的呈现,操作是方案的落地。没有思路的故障处理,就如没有灵魂的爱情,注定就是失败。
我们来看下恢复的主要思路:
1.通过logmnr找到被truncate表上一次的data_object_id。有一种特殊情况:如果表只被truncate一次,那么上次的data_object_id和object_id是一致的。
2.通过dba_free_space获取所有free block。
3.通过dbms_rowid.rowid_create来创建rowid。
4.利用rowid来抽取数据。
重头戏来了,我们来具体看下恢复的操作过程:

设置表空间为read only,避免数据被覆盖。

使用logmnr来分析归档日志,定位上一次的data_object_id号。(logmnr不是本次的重点,所以此处略。)
需要提醒的是:由于表可能会被truncate过多次,原dataobj#不一定就等于obj#,所以需要通过redo来确认。如果最小补充日志没有打开,logminer可能会有遗漏,如果遗漏则需要使用redodump来寻找。
如下图所示,dataobj#从87903被更新成了87904 :

由于释放的块中存放的data_object_id为上一次的值,所以此时需要将对象当前的data_object_id修改为上一次的值。
修改完成后需要flush shared_pool。

需要考虑三个部分块的信息,当前表分配的第一个extent,当前表空间未分配的所有块,当前表空间已经分配但是未被格式化的块(LHWM-HHWM之间,必然在最后一个分区)。

dbms_rowid.rowid_create 参数解释如下:

示例:
select * from RESCUREORA.RESCUREORA_TABLE
where rowid='xxx';
这时,我们运行已经封装好的PL/SQL代码,来还原数据。

手动划重点!!!!
我们首次公开分享该PL/SQL代码,请扫码图片上面二维码关注我们的公众号,并在后台回复关键词:“plsql恢复代码”,你便可以得到PL/SQL恢复代码的全部内容!
现在,我们便可以发现数据已经恢复!(恢复之后的表放在sys 用户下):

还原最初修改的data_object_id:

通过存储过程恢复被truncate表的方法非常简单,并且使用的技术也都是Oracle数据库自带的技术,只是稍微做一定的修改。
但是,通过PL/SQL 恢复也有一定的局限性:
1.暂不支持分区表
本篇为truncate table 恢复系列的第二篇,我们接下来将会推出通过bbed修改段头块和odu/dul的方法来恢复被truncate的表,敬请期待!
Oracle恢复实录
rescureora.com
欢迎扫码关注





