1.还是一样,首先来梳理相关工作原理,我们都做过使用purge从回收站中删除表或索引,并释放与对象关联的所有空间,或删除整个回收站,或从回收站中删除掉的所有表空间的一部分,但是我们真的理解Oracle后台的操作吗,真的理解工作原理吗?不见得,下面我们通过几个案例来帮大家更深入的理解和运用此功能
1.1我们能不能回滚一个purge语句,能不能在purge后恢复一个对象?
1.1.1显然,答案是不能,但为什么不能,Recycle Bin在oracle中究竟扮演什么角色,我们不得而知,因为我们只会用。
1.2我们来描述一下该Recycle Bin的具体内容:
1.2.1首先我们要明确,当我们删除表时,oracle不会立即删除与表关联的空间。oracle会重命名表,并将其和任何关联的对象放在回收站中,如果表在
回收站中出现错误,则可以在稍后恢复该表。这个特性称为闪回删除,闪回表语句用于恢复表。在讨论如何使用闪回表语句实现此目的之前,了解回收站的工作原理以及如何管理其内容是非常重要的
1.3究竟什么是recycle bin ?
1.3.1回收站实际上是一个包含被丢弃对象信息的数据字典表。删除的表和任何相关对象(如索引、约束、嵌套的表和类似的对象)不会被删除,仍然占用空间。
它们将继续计算用户空间配额,直到从回收站清除,或者由于表空间限制而必须由数据库清除这些配额。
1.3.2可以认为每个用户都有自己的回收站,因为除非用户具有SYSDBA权限,否则用户在回收站中只能访问用户拥有的对象。我们可以使用以下语句查看回收站中的对象:
SELECT * FROM RECYCLEBIN;
1.4当删除包含表空间内容的表空间时,表空间中的对象不会放在回收站中,数据库会清除回收站中位于表空间中的对象的任何条目。当删除表空间(不包括内容)时,数据库还清除表空间中对象的回收站选项,否则表空间为空。同样的道理:
1.4.1当删除用户时,属于用户的任何对象都不会被放入回收站,回收站中的任何对象都将被清除
1.4.2当删除一个集群时,它的成员表不会放在回收站中,并且回收站中的任何以前的成员表都会被清除
1.4.3当删除一个类型时,任何依赖对象(例如子类型)都不会放在回收站中,并且回收站中任何以前依赖的对象都将被清除
1.5在回收站中命名对象
1.5.1当删除的表被移动到回收站时,表及其关联对象将被赋予系统生成的名称。这对于避免多个表具有相同名称时可能出现的名称冲突是必要的。
在下列情况下可能发生这种情况:
1.5.2用户删除一个表,以相同的名称重新创建它,然后再次删除它。
1.5.2两个用户拥有同名的表,并且都删除了表
1.6对于BIN$表的命名规则为:oracle官方管它叫unique_id,这个unuque_id是一个26个字符组成的全局惟一标识符,这使得回收站名称在所有数据库中都是惟一的,那么版本是数据库分配的版本号决定的。
1.7如何启动或者禁用回收站?
1.7.1可以使用retriclebin初始化参数启用和禁用回收站。启用回收站后,被丢弃的表及其依赖对象将被放置在回收站中。当回收站被禁用时,被丢弃的表及其依赖对象不会被放置在回收站中;它们只是被删除,我们必须使用其他方法来恢复它们(例如从备份中恢复等等)
1.8禁用回收站很简单:ALTER SESSION SET recyclebin = OFF; 或者ALTER SYSTEM SET recyclebin = OFF;
1.9启动也很简单:ALTER SESSION SET recyclebin = ON; 或者ALTER SYSTEM SET recyclebin = ON;
注意:
1.使用ALTER系统或ALTER SESSION语句启用和禁用回收站立即生效。禁用回收站不会清除或影响已经在回收站中的对象。
2.与任何其他初始化参数一样,我们可以在文本初始化文件initSID.ora中设置recycling bin参数的初始值
1.20如果我们决定永远不会从回收站恢复,那么可以使用清除语句从回收站删除及其关联对象,并释放它们的存储空间。注意需要与删除项目相同的权限:
注意:
1.当我们使用清除语句清除表时,可以使用在回收站中已知的表名或表的原始名称。可以从DBA_或user_recycling bin视图中获取回收站名称,如回收站中
查看和查询对象所示。
2.下面的假设示例清除表scott.t_600_demo,当表被放入回收站时,表被重命名为BIN$jsleilx392mk2=293$0:
3.那么我们可以PURGE TABLE BIN$jsleilx392mk2=293$0;还可以PURGE TABLE scott.t_600_demo;
4.当然,还可以使用清除语句清除回收站中来自指定表空间或仅属于指定用户的表空间对象的所有对象,例如如下脚本:
PURGE TABLESPACE tbs_oracle;
PURGE TABLESPACE tbs_oracle USER scott;
5.我们可以使用以下语句清除自己的对象的回收站,以及对象的释放空间:PURGE RECYCLEBIN;
6.如果我们具有SYSDBA权限,那么可以通过指定dba_recycling bin来清除整个回收站,而不是在前面的语句中指定recycling bin。 还可以使用清除语句从回收站清除索引或从回收站清除指定表空间中的所有对象。
2.案例1:为什么我清空了分区表子分区,同时清空了回收站,但空间没有被释放?
2.1我们尝试查询回收站,但没有任何数据返回
2.2我们查询数据字典基表看到了回收站信息内容,及其对应的子分区
2.3我们尝试查询物理段分配情况,看到对应的分区内容;
2.4在oracle 10gR2到11gR2版本中,未发布的Bug 6450822: recycling:已删除的分区表显示在dba_tab_partition中
注意:recycling bin特性对于非分区表是透明的,但是对于分区表则不是透明的。此Bug还在开发中,官方还没有解决
2.5为了避免这个bug我们可以通过如下方式:
3.案例2:ORA-00600 [12855] Error When Dropping A BIN$... Table的报错信息:
3.1此报错经常在10g版本数据库看到,以前做数据中心,我都已经见怪不怪了,具体操作是我们尝试删除回收站BIN$表时直接报ORA-00600错误。
3.2trace文件里的current sql可能是这种语句:drop table "SCOTT"."BIN$a+9ya5Oz0p7gQAB/AQBMOg==$0" purge;
3.3对应call stack堆践调用情况,可能是如下两种,不一定哈,有可能:
3.3.1... kkdcdac <- opiexe <- opiall0 <- opikpr <- opiodr <- skgmstack <- rpidru <- rpiswu2 ...etc.
3.3.2... kkdcdac <- dtbdrp <- dtbdrv <- opiexe <- opiosq0 <- opiall0 <- opikpr <- opiodr <- rpidrus <- skgmstack <- rpidru <- rpiswu2
<- kprball <- kdpurtab <- kdpurts <- kdpursp <- ktsx_purge_bin <- ktsxssr_sadd <- ktrsexec <- ktelwbl <- kdilflle <- kdilinle <- qerliRop
<- qersoFetch <- qerliFetch <- kdicrws <- kdicdrv <- opiexe <- opiosq0 <- kpooprx
3.4这个问题被记录在Bug中:8288371 - ORA-600[12855]中,有10g遇到了,感兴趣可以去看看
3.5 purge table scott.t_600_demo去试试
3.6或者关注BUG:8288371 - ORA-600[12855] WHEN 'PURGE TABLE BIN$'
4.案例3:数据库中存在一个名为BIN$的无效触发器,表明它存在于recyclebin中。但是在查询回收站数据字典时,我们没有得到任何结果,咋回事?
4.1具体情况类似如下代码显示:
4.2当删除一个表并将其移动到回收站时,将使用系统生成的名称来标识表和依赖项,表现形式我们知道了,类似于“bin $xxxx”。当从回收站恢复表时,我们将
恢复表,并使用表的原始名称重命名表。甚至依赖对象,如索引、约束或触发器也恢复了,但是它们的原始名称没有恢复,这意味着它们的名称仍然看起来
像“BIN$xxxx”。一旦恢复操作完成,数据库中就无法获得这些依赖对象的原始名称。
4.3我们需要确保记住他们的原始名称,并使用RENAME选项运行相关的ALTER命令,以便将原始名称传递给依赖者。当引用依赖项的原始名称时,我们可能还会看到一些错误。
4.4我们来看一个例子:
注意:与表关联的触发器的名称发生了更改以“BIN$xxx”表示,而不是“test”(如在删除表之前)。但触发器仍然还在工作,正如之前我们通过工作原理解释的
4.5我们在来看一个例子;
注意:一样的工作原理,换到索引上仍然也是这种情况对吧。
4.6在删除DEMO_TABLE并将其从回收站恢复之前,运行以下查询
4.7通过如下方式恢复:
4.8恢复原来的名字:
注意:如果在上面的场景中我们有多个触发器,或者需要删除对象(不再需要),那么可以使用drop命令和系统生成的名称一起使用
5.通过expdp/impdp导入导出的时候怎么排除回收站对象?
5.1很简单,加个exclude参数即可,例如下面的例子:
5.1.1exclude=table:"like 'BIN$%'"
5.1.2exclude=sequence:"like 'BIN$%'"
5.1.3exclude=view:"like 'BIN$%'"
5.1.4exclude=type:"like 'BIN$%'"
6.最后一个案例,我们执行create table as select' (CTAS)时,即使没有尝试删除任何索引,但还是报了一个错误:
ORA-02429: cannot drop index used for enforcement of unique/primary key
6.1当我们为特定的表运行DDL语句时,有一个递归sql触发,它试图从回收站删除一个不存在的索引。
这个时候我们需要通过为ORA-02429启用错误堆栈跟踪来验证。为了启用错误堆栈跟踪,所以为大家推荐一下排查问题的方法:
6.1.1 alter session set max_dump_file_size=unlimited;
6.1.2 alter session set events '2429 trace name ERRORSTACK level 3';
6.1.3在做一次ctas那个脚本
6.1.4 alter session set events '2429 trace name ERRORSTACK off';
6.2大多数情况,清空回收站ctas都能好使,但对于专业DBA来讲,我们要更深入了解oracle工作原理,凡事都要为一个为什么,尝试使用errorstack去 定位问题,是DBA的基本功,活学活用很重要。今天的分享就到这里
<点亮梦想.拒绝平庸>
600团队(qq群:851604218)