基于本周二发的文章《TRUNCATE恢复-bbed》(详戳),有些朋友或许对块结构和bbed不熟悉,且bbed的方法也较为复杂,那么大家也可以尝试使用本文的方法来修复。

结合truncate系列一的原理《TRUNCATE TABLE原理解析》(详戳),再加上truncate table还有一个特点,就是所释放的空间会变成free space,这就给没有备份的情况下恢复表数据提供了另外一种思路。

恢复思路如下:

  • 通过LogMiner或者redodump找到dataobj#的变化(用于update obj$里的dataobj#)。

  • 使用dbms_rowid.rowid_create抽取该表空间匹配truncate前dataobj#的block里的数据。

抽取的范围也有两种思路:

  • truncate bbed修复中介绍的redodump找出的extent map里的block(本文的PL/SQL不采用此方式)。

  • 该表的第一个extent、该表空间的free space、该表空间所有segment的最后一个extent(因为truncate的空间可能已经被其他segment使用,可以抽取LHWM-HHWM之间还未格式化的block)。

环境构造:

SQL> create table rescureora.rescureora_table as select * from dba_objects;
Table created.
SQL> select count(*) from rescureora.rescureora_table;COUNT(*)
----------86877
SQL> truncate table rescureora.rescureora_table;
Table truncated.

1.通过LogMiner或者redodump找到dataobj#的变化。

因为表可能会truncate过多次,原dataobj#不一定就等于obj#,所以需要通过redo来确认,如果最小补充日志没有打开,LogMiner可能会有遗漏。如果遗漏则使用redodump来寻找。

SQL> select obj#,dataobj# from obj$ where name='RESCUREORA_TABLE'; OBJ#   DATAOBJ#
---------- ----------87903      87904
SQL> select SQL_REDO from V$LOGMNR_CONTENTS where table_name='OBJ$' and SQL_REDO LIKE '%87903%';
SQL_REDO
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
update "SYS"."OBJ$" set "OBJ#" = '87903', "DATAOBJ#" = '87904', "TYPE#" = '2', "CTIME" = TO_DATE('01-DEC-19', 'DD-MON-RR'), "MTIME" = TO_DATE('01-DEC-19', 'DD-MON-RR'), "STIME" = TO_DATE('01-DEC-19',
'DD-MON-RR'), "STATUS" = '1', "FLAGS" = '0', "OID$" = NULL, "SPARE1" = '6', "SPARE2" = '1' where "OBJ#" = '87903' and "DATAOBJ#" = '87903' and "TYPE#" = '2' and "CTIME" = TO_DATE('01-DEC-19', 'DD-MON-
RR') and "MTIME" = TO_DATE('01-DEC-19', 'DD-MON-RR') and "STIME" = TO_DATE('01-DEC-19', 'DD-MON-RR') and "STATUS" = '1' and "FLAGS" = '0' and "OID$" IS NULL and "SPARE1" = '6' and "SPARE2" = '1' and R
OWID = 'AAAAASAABAAAVKtAAE';

dataobj#从87903变成了87904。

2.遍历表所在tablespace的free block和该表的第一个extent,以及该表空间所有segment的最后一个extent,使用dbms_rowid.rowid_create抽取数据。

dbms_rowid.rowid_create参数解释如下:

由于需要根据dataobj#去匹配,所以需要修改obj$,修改完成之后需要flush shared_pool
注意:如果有lob,truncate不会更改lob index的dataobj#,只需要修改lob的dataobj#即可SQL> update obj$ set dataobj#=87903 where obj#=87903;
1 row updated.
SQL> commit;
Commit complete.
SQL> alter system flush shared_pool;
System altered.设置表空间为read only,避免数据被覆盖
SQL> alter tablespace users read only;
Tablespace altered.具体抽取脚本如下:
注意:恢复的表需要在重新指定一个表空间,避免覆盖数据。本脚本示例将表恢复到了system表空间。declarev_fno number;v_s_bno number;v_e_bno number;v_rowid rowid;nrows number;v_owner varchar2(100):='RESCUREORA';v_table varchar2(100):='RESCUREORA_TABLE';v_o_owner varchar2(100):='SYS';v_o_table varchar2(100):='RESCUREORA_TABLE';v_dataobj number;v_sql varchar2(4000);v_tablespace varchar2(100);
beginselect data_object_id into v_dataobj from dba_objects where owner=v_owner and object_name=v_table;select tablespace_name into v_tablespace from dba_tables where owner=v_owner and table_name=v_table;for i in (select relative_fno,block_id,blocksfrom dba_extentswhere owner=v_owner and segment_name=v_table and extent_id=0union allselect relative_fno,block_id,blocksfrom dba_free_spacewhere tablespace_name=v_tablespaceunion allselect relative_fno,block_id,blocks from (select relative_fno,block_id,blocks,row_number()over(partition by owner,segment_name,partition_name order by extent_id desc) rnfrom dba_extentswhere tablespace_name=v_tablespace and extent_id>0) where rn=1) loopv_fno:=i.relative_fno;v_s_bno:=i.block_id;v_e_bno:=i.block_id+i.blocks-1;for j in v_s_bno .. v_e_bno loopbeginfor x in 0 .. 999 loopv_rowid:=dbms_rowid.rowid_create(1,v_dataobj,v_fno,j,x);v_sql:='insert into '||v_o_owner||'.'||v_o_table||' select * from '||v_owner||'.'||v_table||' where rowid=:1';execute immediate v_sql using v_rowid;end loop;exceptionwhen others thennull;end;commit;end loop;   end loop;
end;
/SQL> select count(*) from sys.rescureora_table;COUNT(*)
----------86877SQL> update obj$ set dataobj#=87904 where obj#=87903; 1 row updated.
SQL> commit;
Commit complete. SQL> alter system flush shared_pool;
SQL> alter system flush buffer_cache;

至此,该方法在无数据覆盖的情况下实现了完全恢复。

关于作者

李翔宇,云和恩墨西区交付技术顾问,长期服务移动运营商行业客户,熟悉Oracle性能优化,故障诊断,特殊恢复。

今年的数据技术嘉年华大会上,李翔宇老师将带来题为《在通过案例深入解析Oracle内部原理》的演讲,与大家一起探索CBO和ASM rebalance的一些内部机制,精彩不容错过!

更多数据库行业相关内容,欢迎光临 2021 数据技术嘉年华 :https://www.modb.pro/dtc2021(扫描下方二维码免费领取大会门票)

END

推荐阅读:267页!2020年度数据库技术年刊

推荐下载:2020数据技术嘉年华PPT下载

2020数据技术嘉年华近50个PPT下载、视频回放已上传墨天轮平台,可在“数据和云”公众号回复关键词“2020DTC”获得!

你知道吗?我们的视频号里已经发布了很多精彩的内容,快去看看吧!↓↓↓

点击下图查看更多 ↓

云和恩墨大讲堂 | 一个分享交流的地方

长按,识别二维码,加入万人交流社群

请备注:云和恩墨大讲堂

  点个“在看”

你的喜欢会被看到❤

TRUNCATE TABLE恢复-脚本相关推荐

  1. Oracle 数据库误truncate table恢复过程

    北京某国企客户 Oracle 11g R2 数据库误truncate table CM_CHECK_ITEM_HIS,表数据丢失,业务查询到该表时报错,此时发现数据库的备份不能用,表数据无法查询. 客 ...

  2. oracle对查询结果求和_某国企Oracle数据库误truncate table恢复案例

    [故障情况概述] 北京某国企客户 Oracle 11g R2 数据库误truncate table CM_CHECK_ITEM_HIS,表数据丢失,业务查询到该表时报错,此时发现数据库的备份不能用,表 ...

  3. 深入解析:TRUNCATE TABLE 的内部原理解析与恢复思路

    摘要 众所周知,truncate table 是一种快速清空表内数据的一种方式,与 delete 方式不同,truncate 只产生非常少的 redo 和 undo,就实现了清空表数据并降低表 HWM ...

  4. oracle表还原truncate,Oracle数据库执行truncate table操作后如何逆向恢复之前的状态...

    概述:北京某国企客户 Oracle 11g R2 数据库误truncate table CM_CHECK_ITEM_HIS,表数据丢失,业务查询到该表时报错,此时发现数据库的备份不能用,表数据无法查询 ...

  5. 深入解析TRUNCATE TABLE – 手工修复和验证过程

    关注我们获得更多精彩 作者 | 李翔宇,云和恩墨西区交付技术顾问,长期服务移动运营商行业客户,精通 oracle 性能优化,故障诊断,特殊恢复领域. 摘要 众所周知,truncate table 是一 ...

  6. MySql清空表的方法介绍 : truncate table 表名

    清空某个mysql表中所有内容 delete from 表名; truncate table 表名; 不带where参数的delete语句可以删除mysql表中所有内容,使用truncate tabl ...

  7. truncate table语句和delete table语句的区别

    truncate table 表名 ; delete from 表名; 都是用来删除表中所有的记录,前者删除数据后表的标识列会重新开始编号,它比delete语句使用的系统资源和事务日志资源更少,但是表 ...

  8. TRUNCATE TABLE原理解析

    众所周知,TRUNCATE TABLE是一种快速清空表内数据的一种方式,与delete方式不同,truncate只产生非常少的redo和undo,就实现了清空表数据并降低表HWM的功能.本文主要围绕T ...

  9. delete table 和 truncate table

    使用delete语句删除数据的一般语法格式: delete [from] {table_name.view_name} [where<search_condition>] 将XS表中的所有 ...

最新文章

  1. 单域名多php,php多域名单站点路由
  2. 数学建模学习笔记——主成分分析
  3. AbstractQueuedSynchronizer 原理分析 - 独占/共享模式
  4. Grafana+Prometheus系统监控之MySql
  5. anguler 画面布局适应屏幕大小_前端开发常见的五大布局模式,绝对不要错过这篇分享!...
  6. 云服务器mqtt协议,云服务器mqtt协议
  7. 从单体到Flink:一文读懂数据架构的演变
  8. jenkins远程构建job_jenkins分布式构建job
  9. layui循环遍历数据_Layui之动态循环遍历出的富文本编辑器显示
  10. [傅里叶变换及其应用学习笔记] 十五. 傅里叶变换在衍射上的应用
  11. selenium问题记录
  12. 短视频去水印解析二次运用--全网短视频解析去水印软件
  13. 基于libmodbus库实现modbus TCP/RTU通信
  14. 阿里云服务器搭建以及简易的WEB项目部署过程
  15. 动易html在线编辑器,动易CMS静态页调用FCK编辑器的代码
  16. html注册cab包,OCX控件打包成CAB并实现数字签名过程
  17. html毛玻璃背景代码,css毛玻璃背景的制作
  18. 机器学习笔记 十七:基于Gini Importance、Permutation Importance、Boruta的随机森林模型重要性评估的比较
  19. 重庆大学计算机类专业分数线,重庆大学录取分数线 2019年重庆大学各专业录取分数线...
  20. Kubernetes-调度、节点亲和反亲和、pod亲和反亲和、Taints污点的处理

热门文章

  1. cesium学习笔记(问题记录)——以cesium1.77版本为例
  2. keil5建立工程步骤_5个步骤建立实践社区
  3. 容器映像_构建微小的容器映像
  4. 不使用机器学习的机器视觉_使用机器学习为卡通着色
  5. jQuery源码分析 整体框架部分及部分常用方法
  6. 每日面试之Java集合
  7. 记一次 React 组件无法更新状态值的问题分析与解决
  8. es6 super关键字
  9. 不能在计算机网络上共享的打印机驱动程序,打印机已经共享,可是当别的电脑安装共享的打印机驱动程序时提示 windows 没法连接到打印机。拒绝访问??...
  10. php实现数字英文验证码,PHP英文数字验证码生成类