Oracle压缩表中的drop drop - 在幕后"设置未使用的"

时间:2017-07-10 16:34:51

标签: oracle compression

使用Oracle 11.2.0.4.0并尝试从多个OLTP压缩表中删除列,期望获得ORA-39726: unsupported add/drop column operation on compressed tables。但是,运行时没有错误,但未使用列

我想知道是否可以避免这种行为 - 我希望得到错误,以避免混淆(人们在不知情的情况下将未使用的列留在原地)。

我找不到对此的引用,需要提高我的搜索技巧。在文档中我只看到:

  

您可以从使用COMPRESS BASIC的表中设置未使用的列,但是   你不能放弃列。但是,所有条款   drop_column_clause对使用COMPRESS FOR OLTP的表有效。   有关更多信息,请参阅table_compression的语义。   http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_3001.htm#i2103683

请您知道以任何方式配置它以引发错误吗? 场景:

create table test_radu_a(col1 number, col2 number) compress for oltp;
alter table test_radu_a drop (col2);
select * from user_unused_col_tabs where table_name = 'TEST_RADU_A';

1 个答案:

答案 0 :(得分:1)

这似乎是预期的行为;来自MOS Doc ID 1068820.1:

  

在11g中允许从压缩表中删除列IF兼容性设置为11.1或更高并且使用“压缩所有OLTP”选项创建表但是即使在这种情况下也没有真正的丢弃但在数据库内部设置UNUSED列以避免长时间运行的解压缩和重新压缩操作。

另见文件1223705.1,2171802.1等。真正删除列的唯一方法似乎是解压缩和重新压缩,如文档1987500.1所示,但这就是上面引用中要避免的内容。

似乎没有任何方法可以解决您期望的错误。

我认为你能得到的最接近的是DDL触发器:

create or replace trigger radu_trigger
before alter
on schema
declare
  l_compress_for user_tables.compress_for%type;
begin
  select max(compress_for) into l_compress_for
  from user_tables
  where ora_dict_obj_type = 'TABLE' and table_name = ora_dict_obj_name;

  if l_compress_for is null or l_compress_for != 'OLTP' then
    return;
  end if;

  for r in (
    select column_name from user_tab_columns
    where table_name = ora_dict_obj_name
  )
  loop
    if ora_is_drop_column(r.column_name) then
      raise_application_error(-20001,
        'Do not drop columns from an OLTP-compressed table');
    end if;
  end loop;
end radu_trigger;
/

然后,当您尝试在任何OLTP压缩表上删除列时 - 在该架构中 - 您将收到错误:

alter table test_radu_a drop (col2);

alter table test_radu_a drop (col2)
Error report -
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: Do not drop columns from an OLTP-compressed table
ORA-06512: at line 18
...

当然,如果您不想检查所有压缩表,可以查找特定的ora_dict_obj_name值。

可以模仿真正的例外:

create or replace trigger radu_trigger
before alter
on schema
declare
  l_compress_for user_tables.compress_for%type;
  l_exception exception;
  pragma exception_init (l_exception, -39726);
begin
...
  loop
    if ora_is_drop_column(r.column_name) then
      raise l_exception;
    end if;
  end loop;
end radu_trigger;
/

alter table test_radu_a drop (col2);

Error report -
ORA-00604: error occurred at recursive SQL level 1
ORA-39726: unsupported add/drop column operation on compressed tables
ORA-06512: at line 20
...

但我认为这会让人感到困惑,因为这个消息并不真实。提出自己的定制例外可能更安全,更清洁。