Oracle ROLLBACK 与 TRUNCATE TABLE

Oracle ROLLBACK versus TRUNCATE TABLE

我有两个临时 tables,第一级 JOIN 跨越 5 tables 和几十万行向下到 table 有 6 列和更少的东西超过 10k 行。由于一个会话中的用户使用过滤器,我有第二个临时 table 包含过滤结果,这些过滤器根据最终用户的心血来潮而改变。

每次过滤器更改时,我都需要截断过滤后的 table 并从第一个 table 重新创建它。

本质上,我受权限约束,DBA 不想给我 TEMPORARY TABLE.

的 TRUNCATE 权限
DELETE FROM table WHERE 1=1;

只是错误的方法(尽管有效,诚然)。关闭并打开一个新会话让我失去了第一个 table,为第二个打开第二个会话 table 让我无法访问第一个。

使用SQL Developer,DELETE 和ROLLBACK 看起来花费的时间大致相同,也许ROLLBACK 略占优势。

一般的问题是,

What do you recommend? Am I wrong in my understanding of some of this?

具体问题:

Which is better, ROLLBACK or DELETE (on a temporary table)?

Are the roles so narrowly controlled/defined in Oracle that we need to restrict TRUNCATE on a temporary table?

顺便说一句:这是一个 PeopleSoft 系统,因此涉及的每个人都对权限和角色非常敏感

DBA 不授予您 TRUNCATE 权限是对的。原因?虽然您使用的方法对于 可能不 理想,但它确实允许您完成任务 而无需授予您不必要的权限。许多组织都遵守 Principle of Least Privilege,如果您的组织是众多遵守的组织之一,那么 DBA 只是在做他们的工作。

此外,截断、回滚和删除是对数据库的不同操作。例如,当您删除一条记录时,数据库会从相关的 table 中删除该记录,并且还会生成回滚段。当您截断 table 时,不再生成回滚,这会阻止您在发生故障时恢复数据,这可能会违反您组织的保留策略。同样,执行回滚不只是更改临时 table - it also generates redo information 中的数据。如果您无法确定这些差异,DBA 为什么要授予您这些权限?

一般来说,最好的方法会因很多变量而异 - 您的恢复保留策略是什么?您的组织是否磁盘不足 space,使 DBA 厌倦了生成过多的日志信息?是否有需要达到的绩效目标?影响因素有很多。

在 11.2.0.4 上测试:

create global temporary table gtt (id number) on commit preserve rows;

insert into gtt42 select level from dual connect by level <= 100000;

prompt rollback
set timing on
rollback;
set timing off;

insert into gtt select level from dual connect by level <= 100000;

prompt delete
set timing on
delete from gtt;
set timing off;

insert into gtt select level from dual connect by level <= 100000;

prompt truncate
set timing on
truncate table gtt;
set timing off;

rollback
Elapsed: 00:00:00.049
delete
Elapsed: 00:00:01.036
truncate
Elapsed: 00:00:00.052

Rollback 和truncate 差不多,都比delete 快很多。逻辑上截断和回滚做的事情几乎是一样的。

对于您的场景,您似乎只需要将插入提交到第一个 GTT,然后重复回滚并插入到第二个:

create global temporary table gtt1 (id number) on commit preserve rows;
create global temporary table gtt2 (id number) on commit preserve rows;

insert into gtt1 (id) select level from dual connect by level <= 100;
commit;

insert into gtt2 (id) select id from gtt1 where mod(id, 2) = 0;

select count(*), min(id), max(id) from gtt2;

  COUNT(*)    MIN(ID)    MAX(ID)
---------- ---------- ----------
        50          2        100

rollback;

insert into gtt2 (id) select id from gtt1 where mod(id, 3) = 0;

select count(*), min(id), max(id) from gtt2;

  COUNT(*)    MIN(ID)    MAX(ID)
---------- ---------- ----------
        33          3         99

commit保留第一个GTT中的行;然后 rollback 只会影响第二个 GTT 中的数据,不会影响第一个。


至于特权,from the documentation for truncate:

To truncate a table, the table must be in your schema or you must have the DROP ANY TABLE system privilege.

由于您无法截断 table,因此可能不在您的架构中;并且您可以理解为什么您的 DBA 不想给您非常强大和危险的 drop any table 特权。您不能授予仅允许在另一个架构中截断特定 table 的权限。

当您定义第一个临时文件 table 时,您可以添加 ON COMMIT 子句并指示应在整个会话期间维护数据。对于第二个临时 table 默认值(即 DELETE ROWS 子句)应该是在提交每个事务时截断。

因此,当用户更改搜索条件时,提交先前的搜索事务以截断数据。我相当确定 Oracle 会截断数据而不是删除单个行。

使用 VBA 时,请注意解决方案。 ADO 对象自动提交所有事务,这会使此处显示的所有逻辑无效。

作为解决方法,我们需要 .BeginTrans 和 .CommitTrans

myConnection.BeginTrans:

myConnection.CommitTrans:

我们打算回滚的事务之前和之后(分别)。