2010-03-01 15 views
7

Necesito ejecutar un montón de (hasta ~ 1000000) sentencias sql en una base de datos Oracle. Estas declaraciones deberían dar como resultado un estado referencialmente consistente al final, y todas las declaraciones deberían revertirse si ocurre un error. Estas declaraciones no vienen en un orden referencial. Por lo tanto, si las restricciones de clave externa están habilitadas, una de las sentencias puede causar una violación de clave externa, aunque esta violación se solucionará con una sentencia que se ejecutará más adelante.Oracle DDL en transacción autónoma

He intentado desactivar primero las claves foráneas y habilitarlas después de que se hayan ejecutado todas las instrucciones. Pensé que sería capaz de retroceder cuando haya una violación real de clave externa. Aunque me equivoqué, descubrí que cada declaración DDL en Oracle comenzaba con una confirmación, por lo que no había forma de deshacer las declaraciones de esta manera. Aquí está mi script para desactivar las claves externas:

begin 
    for i in (select constraint_name, table_name from user_constraints 
      where constraint_type ='R' and status = 'ENABLED') 
    LOOP execute immediate 'alter table '||i.table_name||' disable constraint 
          '||i.constraint_name||''; 
    end loop; 
end; 

Después de algunas investigaciones, descubrí que se recomendó para ejecutar sentencias DDL, como en este caso, en una transacción autónoma. Así que traté de ejecutar sentencias DDL en una transacción autónoma. Esto dio como resultado el siguiente error:

ORA-00054: El recurso ocupado y adquirir con NOWAIT especificado

estoy conjeturando que esto es debido a que la transacción principal todavía tiene bloqueo DDL en las mesas.

¿Estoy haciendo algo mal aquí, o hay alguna otra forma de hacer que este escenario funcione?

Respuesta

8

Hay varios enfoques posibles.

Lo primero que debe tener en cuenta es que haga lo que haga en el nivel de la tabla se aplicará a todas las sesiones que utilicen dicha tabla. Si no tiene acceso exclusivo a esa tabla, probablemente no desee eliminar/recrear restricciones, ni desactivarlas/habilitarlas.

Lo segundo a tener en cuenta es que probablemente no desee estar en la posición de deshacer un millón de insertos/actualizaciones. El retroceso puede ser LENTO.

Generalmente me gustaría cargar en una tabla temporal. Luego, haga un único INSERT de la tabla temporal en la tabla de destino. Como una declaración única, Oracle aplicará todas las restricciones de verificación al final.

Si no puede acceder a una tabla temporal (por ejemplo, actualizaciones de datos existentes), antes de comenzar, realice las restricciones deferrable initially immediate. Luego, dentro de su sesión,

SET CONSTRAINTS emp_job_nn, emp_salary_min DEFERRED; 

Puede aplicar los cambios y, cuando confirme, las restricciones se validarán.

Debería personalizarse con DML error logging, ya que puede ayudar a identificar las filas que causan infracciones.

+0

Acabo de enterarme del truco "ESTABLECER LIMITACIONES" y vine a responder mi propia pregunta y vi su respuesta :). Gracias. – swamplord

Cuestiones relacionadas