2012-05-10 1 views
2

Похоже, что существует ограничение реализации, которое запрещает использование forall .. insert для Oracle при использовании по ссылке базы данных. Это простой пример, чтобы продемонстрировать:Преодоление ограничения на объемные вставки по ссылке базы данных

connect schema/[email protected] 

create table tmp_ben_test (
    a number 
, b number 
, c date 
, constraint pk_tmp_ben_test primary key (a, b) 
    ); 

Table created. 

connect schema/[email protected] 
Connected. 

declare 

    type r_test is record (a number, b number, c date); 
    type t__test is table of r_test index by binary_integer; 
    t_test t__test; 

    cursor c_test is 
    select 1, level, sysdate 
     from dual 
    connect by level <= 10 
      ; 

begin 

    open c_test; 
    fetch c_test bulk collect into t_test; 

    forall i in t_test.first .. t_test.last 
    insert into [email protected] 
    values t_test(i) 
      ; 

    close c_test; 

end; 
/

Очень смешения это терпит неудачу в 9i со следующей ошибкой:

ERROR at line 1: ORA-01400: cannot insert NULL into ("SCHEMA"."TMP_BEN_TEST"."A") ORA-02063: preceding line from DB1 ORA-06512: at line 18

Если было только после проверки в 11g, что я понял, что это было ограничение реализации ,

ERROR at line 18: ORA-06550: line 18, column 4: PLS-00739: FORALL INSERT/UPDATE/DELETE not supported on remote tables

Действительно очевидный способ обойти это изменить forall .. к:

for i in t_test.first .. t_test.last loop 
    insert into [email protected] 
    values t_test(i); 
end loop; 

, но я предпочел бы держать его в одной вставке, если это вообще возможно. Tom Kyte suggests the use of a global temporary table. Вставка данных в GTT, а затем через ссылку DB кажется массивным избыточным количеством для набора данных, который уже находится в пользовательском типе.

Для уточнения этого примера чрезвычайно упрощен по сравнению с тем, что на самом деле происходит. Мы не сможем сделать простой insert into, и не все операции можно выполнить на GTT. Большие части кода должны выполняться в пользовательском типе.

Есть ли другой, более простой или менее DMLy, путь вокруг этого ограничения?

+0

Вы пробовали идеал GTT? Сравните производительность в 11g. Я думаю, это не перебор, а быстрый способ перемещения дат. –

+0

Нет, я не пробовал. Очевидно, если нет другого выбора. Кажется странным взять что-то из памяти; переместите его в другую память, затем выполните некоторые DML. Я надеялся на более упрощенное решение. Если он существует. – Ben

+0

Подумайте немного об этом. Часть GTT - чистый SQL, и она будет быстрой (с dblink штрафом). Медленная часть ps/sql с массивами ... –

ответ

2

С какими ограничениями вы сталкиваетесь в удаленной базе данных? Если вы можете создавать объекты там, у вас есть обходное решение: в удаленной базе данных создайте тип коллекции и процедуру, которая берет коллекцию в качестве параметра и выполняет оператор FORALL.

+0

У меня нет никаких ограничений; это просто обработка БД и не связанная с внешним миром. Мне потребовалось несколько секунд, чтобы понять, что вы имеете в виду; выполните процедуру на 'db1' из db2', которая принимает тип как параметр и делает ли вставка для меня? – Ben

1

Если вы создаете тип t__test/r_test в db2, а затем создаете для них общий синоним на db1, тогда вы сможете вызывать процедуру из db1 в db2, заполняя t_table и возвращаясь к db1. Затем вы сможете вставить в свою локальную таблицу.

Я предполагаю, что вы использовали бы упакованные типы и процедуры в реальном мире, а не анонимные блоки.

Кроме того, это не было бы идеальным решением для больших наборов данных, тогда GTT или подобное было бы лучше.

 Смежные вопросы

  • Нет связанных вопросов^_^