2009-06-12 30 views
22

¿Cuál sería una mejor opción para la inserción masiva en una base de datos Oracle? un bucle cursor comoInserción masiva en la base de datos Oracle: ¿Qué es mejor: para Cursor loop o simplemente Select?

DECLARE 
    CURSOR C1 IS SELECT * FROM FOO; 
BEGIN 
    FOR C1_REC IN C1 LOOP 
    INSERT INTO BAR(A, 
       B, 
       C) 
      VALUES(C1.A, 
       C1.B, 
       C1.C); 
    END LOOP; 
END 

o una simple selección, como:

INSERT INTO BAR(A, 
       B, 
       C) 
     (SELECT A, 
       B, 
       C 
     FROM FOO); 

algún motivo específico o bien uno podría ser mejor?

+2

FYI, no debe referirse a esto como una 'inserción masiva'. Si bien puede insertar grandes cantidades de datos, hay una función PL/SQL llamada Operaciones masivas (Inserciones masivas, Recopilación masiva), etc. – moleboy

+0

Y para agregar a la referencia de operaciones masivas, debe considerar eso arriba de las otras dos para operaciones de datos grandes o en curso, operaciones de inserción regulares. Las inserciones masivas pueden producir tremendas mejoras en el rendimiento sobre inserciones simples en los ejemplos dados. – DCookie

Respuesta

25

Recomendaría la opción Seleccionar porque los cursores tardan más.
también mediante el Select es mucho más fácil de entender para cualquier persona que tenga que modificar su consulta

+6

+1. La segunda opción también es más concisa y no requiere la compilación/ejecución de un bloque PL/SQL. –

5

Si su segmento de rollback/undo segmento puede acomodar el tamaño de la transacción después la opción 2 es mejor. La opción 1 es útil si no tiene la capacidad de reversión necesaria y tiene que dividir la inserción grande en confirmaciones más pequeñas para que no obtenga errores demasiado pequeños del segmento de deshacer/deshacer.

5

Un simple insertar/seleccionar como su segunda opción es preferible. Para cada inserción en la primera opción necesita un cambio de contexto de pl/sql a sql. Ejecute cada uno con trace/tkprof y examine los resultados.

Si, como menciona Michael, su reversión no puede manejar la declaración, haga que su dba le proporcione más. El disco es barato, mientras que los resultados parciales que provienen de insertar sus datos en múltiples pases son potencialmente bastante costosos. (Casi no hay deshacer asociado a un inserto).

21

La regla general es que, si puede hacerlo utilizando una única instrucción de SQL en lugar de usar PL/SQL, debería hacerlo. Por lo general será más eficiente.

Sin embargo, si necesita agregar más lógica de procedimiento (por alguna razón), puede necesitar usar PL/SQL, pero debe usar operaciones masivas en lugar de procesamiento de fila por fila. (Nota: en Oracle 10g y posterior, su bucle FOR utilizará automáticamente BULK COLLECT para buscar 100 filas a la vez; sin embargo, su instrucción de inserción se seguirá haciendo fila por fila).

p. Ej.

DECLARE 
    TYPE tA IS TABLE OF FOO.A%TYPE INDEX BY PLS_INTEGER; 
    TYPE tB IS TABLE OF FOO.B%TYPE INDEX BY PLS_INTEGER; 
    TYPE tC IS TABLE OF FOO.C%TYPE INDEX BY PLS_INTEGER; 
    rA tA; 
    rB tB; 
    rC tC; 
BEGIN 
    SELECT * BULK COLLECT INTO rA, rB, rC FROM FOO; 
    -- (do some procedural logic on the data?) 
    FORALL i IN rA.FIRST..rA.LAST 
     INSERT INTO BAR(A, 
         B, 
         C) 
     VALUES(rA(i), 
      rB(i), 
      rC(i)); 
END; 

Lo anterior tiene la ventaja de minimizar los cambios de contexto entre SQL y PL/SQL. Oracle 11g también tiene un mejor soporte para tablas de registros para que no tenga que tener una tabla PL/SQL separada para cada columna.

Además, si el volumen de datos es muy grande, es posible cambiar el código para procesar los datos en lotes.

3

Creo que en esta pregunta falta una información importante.

¿Cuántos registros va a insertar?

  1. If from 1 to cca. 10.000, entonces debería usar la declaración de SQL (como dijeron que es fácil de entender y que es fácil de escribir).
  2. Si de cca. 10.000 a cca. 100.000 entonces debería usar el cursor, pero debe agregar lógica para confirmar cada 10.000 registros.
  3. Si de cca. 100.000 a millones, entonces debe usar la recolección masiva para un mejor rendimiento.
2

Como puede ver al leer las otras respuestas, hay muchas opciones disponibles. Si solo está haciendo < 10k filas, debería ir con la segunda opción.

En resumen, por aproximadamente> 10k hasta el final para decir < 100k. Es una especie de área gris. Muchos de los viejos genios ladrarán en grandes segmentos de retroceso. Pero, honestamente, el hardware y el software han logrado un progreso increíble en el que puede obtener la opción 2 para muchos registros si solo ejecuta el código varias veces. De lo contrario, probablemente debería cometer cada 1k-10k o menos filas. Aquí hay un fragmento que uso. Me gusta porque es corto y no tengo que declarar un cursor. Además, tiene los beneficios de recolectar y recolectar a granel.

begin 
    for r in (select rownum rn, t.* from foo t) loop 
     insert into bar (A,B,C) values (r.A,r.B,r.C); 
     if mod(rn,1000)=0 then 
      commit; 
     end if; 
    end; 
    commit; 
end; 

yo encontramos este link desde el sitio de Oracle que ilustra las opciones con más detalle.

+0

gracias por la información! – Sathya

0

que puede utilizar:

granel recoger junto con por todo lo que se llama Bulk binding.

Porque el operador PL/SQL forall acelera 30 veces más rápido para las inserciones simples de la mesa.

BULK_COLLECT y Oracle FORALL juntas estas dos funciones se conocen como Bulk Binding. Los enlaces masivos son una técnica PL/SQL donde, en lugar de múltiples instrucciones individuales SELECT, INSERT, UPDATE o DELETE se ejecutan para recuperar o almacenar datos en la tabla, todas las operaciones se llevan a cabo a la vez, a granel. Esto evita el cambio de contexto que se produce cuando el motor PL/SQL debe pasar al motor SQL, luego al motor PL/SQL, y así sucesivamente, cuando accede individualmente a las filas de a una por vez. Para hacer enlaces masivos con INSERT, UPDATE y DELETE declaraciones, encierra la instrucción SQL dentro de una declaración PL/SQL FORALL. Para hacer enlaces masivos con declaraciones SELECT, debe incluir la cláusula BULK COLLECT en la instrucción SELECT en lugar de usar INTO.

Mejora el rendimiento.

Cuestiones relacionadas