2

(背景:我们正在运行一个使用 Oracle Warehouse Builder 构建的数据仓库。最近,我们开始收到很多“ORA-02049:distributed transaction timeout while waiting for lock”错误。原因是我们正在运行几个并行的 ETL 作业,这些作业中的每一个都对INSERT /*+APPEND PARALLEL*/我们的 staging 表执行操作。此 staging 表由源系统 ID 分区。)

我想知道是否可以在运行时为 INSERT 指定分区键。假设我有一张桌子

create table tmp_loading_table (
  etl_source_system_fk number not null enable,
  object_id number not null enable,
  object_name varchar2(30) not null enable
)
  PARTITION BY LIST ("ETL_SOURCE_SYSTEM_FK") 
 (PARTITION "ESS1"  VALUES (1), 
 PARTITION "ESS2"  VALUES (2)  
);

然后我可以使用插入特定分区

insert  /*+ APPEND PARALLEL("TMP_LOADING_TABLE") */     
into tmp_loading_table partition(ESS1) (
  etl_source_system_fk, object_id, object_name)
(select 1 etl_source_system_fk, object_id, object_name from user_objects);

但这需要我对分区名称进行硬编码。

由于我们的 OWB 映射是通用的(它们将源系统 ID 作为参数获取),我想在运行时提供分区名称,例如

insert  /*+ APPEND PARALLEL("TMP_LOADING_TABLE") */     
into tmp_loading_table partition(:partition_name) (
  etl_source_system_fk, object_id, object_name)
(select 1 etl_source_system_fk, object_id, object_name from user_objects);

这可能吗?如果没有,是否有另一种方法可以使用 Oracle Warehouse Builder 实现这一目标?

4

1 回答 1

2

PARTITION FOR语法和动态 SQL 可以提供帮助。

理想情况下,它会很简单:

declare
    v_partition_value number := 1;
begin
    insert  /*+ APPEND PARALLEL("TMP_LOADING_TABLE") */     
    into tmp_loading_table partition for (v_partition_value) (
      etl_source_system_fk, object_id, object_name)
    (select 1 etl_source_system_fk, object_id, object_name from user_objects);
end;
/

不幸的是,上面的代码失败了ORA-14108: illegal partition-extended table name syntax。这很奇怪,因为这似乎是该语法的明显用途。

添加动态 SQL 可消除错误。

declare
    v_partition_value number := 1;
begin
    execute immediate '
    insert  /*+ APPEND PARALLEL("TMP_LOADING_TABLE") */     
    into tmp_loading_table partition for ('||v_partition_value||') (
      etl_source_system_fk, object_id, object_name)
    (select 1 etl_source_system_fk, object_id, object_name from user_objects)';
end;
/

我不熟悉 Oracle Warehouse Builder,也不知道该解决方案是否适用于该环境。我假设在数据仓库中 SQL 注入不是问题。


在运行时指定分区名称的另一种方法是使用系统分区DATAOBJ_TO_PARTITION

create table tmp_loading_table (
  etl_source_system_fk number not null enable,
  object_id number not null enable,
  object_name varchar2(30) not null enable
)
PARTITION BY SYSTEM
(
  PARTITION ess1,
  PARTITION ess2
);

declare
    v_object_id number;
begin
    select object_id
    into v_object_id
    from dba_objects
    where object_name = 'TMP_LOADING_TABLE'
        and subobject_name = 'ESS1';

    insert into tmp_loading_table
    partition (dataobj_to_partition (tmp_loading_table, v_object_id))
    values (1, 2, 'A');
end;
/

这种方法的巨大缺点是每个 DML 都必须引用分区:

insert into tmp_loading_table
values (1, 2, 'A');

ORA-14701: partition-extended name or bind variable must be used for DMLs on tables partitioned by the System method

我从未听说过有人使用此功能。并且根据我的经验,Oracle 数据磁带有问题。那个动态 SQL 现在看起来怎么样?:)

于 2013-10-17T04:19:37.840 回答