2010-03-17 45 views
7

estoy teniendo un poco de problemas con un selecto en el inserto a través de un dblink en el oráculo 10. Estoy utilizando la siguiente declaración:Seleccionar e insertar a través de dblink

INSERT INTO LOCAL.TABLE_1 (COL1, COL2) 
SELECT COL1, COL2 
FROM [email protected] s 
WHERE COL1 IN (SELECT COL1 FROM WORKING_TABLE) 

Cuando ejecuta la instrucción que sigue es lo se ejecute en el servidor remoto en el DB Link:

SELECT /*+ OPAQUE_TRANSFORM */ "COL1", "COL2" 
FROM "REMOTE"."TABLE1" "S" 

Si me quedo sólo el selecto y no hago el inserto en que se ejecute el siguiente:

SELECT /*+ */ "A1"."COL1" 
    , "A1"."COL2" 
    FROM "REMOTE"."TABLE1" "A1" 
WHERE "A1"."COL1" = 
    ANY (SELECT "A2"."COL1" 
     FROM "LOCAL"."TABLE1"@! "A2") 

El problema está en el caso de insertar la tabla de entrada que se arrastra a través del dblink y luego se limita localmente, lo que toma un poco de tiempo dado el tamaño de la tabla. ¿Hay alguna razón para agregar que el inserto cambiaría el comportamiento de esta manera?

Respuesta

3

Es posible que desee utilizar la sugerencia de driving_site. Hay una buena explicación aquí: http://www.dba-oracle.com/t_sql_dblink_performance.htm

+0

He intentado agregar la siguiente sugerencia a la consulta inicial antes de publicar pero obtuve los mismos resultados. /* + DRIVING_SITE (s) */ Eso sería insinuar que conducir en el lado de dblink correcto? – Domtar

2

Aprovechando la cláusula WITH podría optimizar su recuperación de su conjunto de trabajo:

WITH remote_rows AS 
    (SELECT /*+DRIVING_SITE(s)*/COL1, COL2 
     FROM [email protected] s 
     WHERE COL1 IN (SELECT COL1 FROM WORKING_TABLE)) 
INSERT INTO LOCAL.TABLE_1 (COL1, COL2) 
SELECT COL1, COL2 
FROM remote_rows 
+0

[Esta respuesta] (http://stackoverflow.com/questions/5885154/oracle-sql-insert-into-with-with-clause#5885845) muestra que su sintaxis aquí no es correcta. – Alfabravo

3

Cuando se trata de DML, Oracle opta por ignorar cualquier indicio driving_site y ejecuta la sentencia en el sitio de destino Por lo tanto, dudo que pueda cambiar eso (incluso usando el enfoque CON descrito anteriormente). Una posible solución es que puede crear un sinónimo para LOCAL.TABLE1 en la base de datos remota y usar el mismo en su instrucción INSERT.

0

¿Qué tan grande es WORKING_TABLE? Si es lo suficientemente pequeño, podría intentar seleccionar de work_table en una colección, y luego pasar los elementos de esa recopilación como elementos en una lista IN.

declare 
    TYPE t_type IS TABLE OF VARCHAR2(60); 
    v_coll t_type; 
begin 
    dbms_application_info.set_module('TEST','TEST'); 
    -- 
    select distinct object_type 
    bulk collect into v_coll 
    from user_objects; 
    -- 
    IF v_coll.count > 20 THEN 
    raise_application_error(-20001,'You need '||v_coll.count||' elements in the IN list'); 
    ELSE 
    v_coll.extend(20); 
    END IF; 
    insert into abc (object_type, object_name) 
    select object_type, object_name 
    from [email protected] 
    where object_type in 
      (v_coll(1), v_coll(2), v_coll(3), v_coll(4), v_coll(5), 
      v_coll(6), v_coll(7), v_coll(8), v_coll(9), v_coll(10), 
      v_coll(11), v_coll(12), v_coll(13), v_coll(14), v_coll(15), 
      v_coll(16), v_coll(17), v_coll(18), v_coll(19), v_coll(20) 
      ); 
    -- 
    dbms_output.put_line(sql%rowcount); 
end; 
/
+0

Ese fue mi enfoque inicial, pero puede haber más de 1000 elementos en la tabla de trabajo. Creo que tendré que dividir el procesamiento por grupos de 1000 para permanecer dentro de los límites. – Domtar

+0

¿Puede crear una tabla temporal global en el lado remoto del enlace? Podrías insertar eso desde la mesa de trabajo, luego la unión estaría en el lado remoto. –

0

Insertar en pista zith cardinalidad parece funcionar en 11,2

INSERT /*+ append */ 
     INTO MIG_CGD30_TEST  
       SELECT /*+ cardinality(ZFD 400000) cardinality(CGD 60000000)*/ 
      TRIM (CGD.NUMCPT) AS NUMCPT, TRIM (ZFD.NUMBDC_NEW) AS NUMBDC 
       FROM [email protected]_MIG_THALER CGD, 
        [email protected]_MIG_THALER ZFD, 
        EVD01_ADS_DR3W2 EVD 
1

Oracle ignorará la pista driving_site para instrucciones de inserción, como DML siempre se ejecuta localmente. La forma de hacerlo es crear un cursor con la sugerencia del sitio de conducción, y luego recorrer el cursor con un bulkcollect/forall e insertarlo en la tabla local de destino.

Cuestiones relacionadas