2009-06-11 43 views
6

Tenemos una aplicación de base de datos Oracle madura (en producción durante más de 10 años), y durante ese tiempo, hemos estado utilizando scripts de nuestra propia invención para eliminar datos antiguos que ya no se necesitan . Funcionan emitiendo instrucciones de eliminación en las tablas apropiadas, en un ciclo con confirmaciones frecuentes, para evitar sobrecargar el sistema con E/S o utilizar demasiado espacio de deshacer.Técnicas para eliminar datos antiguos en bases de datos Oracle

Funcionan bien, en su mayor parte. Se ejecutan a diario, y se tarda aproximadamente una hora para eliminar los datos del sistema de los días más antiguos. Las principales inquietudes que tengo son los efectos en las tablas y los índices que puede tener toda esta eliminación, y el hecho de que aunque no carguen demasiado el sistema, eliminar el valor de un día en ese corto tiempo tiene el efecto de soplar fuera de la caché del búfer de instancias, lo que resulta en consultas posteriores que se ejecutan un poco más lento durante las próximas horas a medida que la memoria caché se restaura gradualmente.

Durante años hemos estado considerando mejores métodos. En el pasado, había escuchado que la gente usaba tablas particionadas para administrar la recolección de datos antiguos, por ejemplo, un mes por partición y descartando la partición más antigua mensualmente. El principal inconveniente de este enfoque es que nuestras reglas de cosecha van más allá de "eliminar el mes X". Los usuarios pueden especificar cuánto tiempo deben permanecer en el sistema los datos, en función de los valores clave (por ejemplo, en una tabla de facturas, la cuenta foo puede eliminarse después de 3 meses, pero la barra de cuenta puede permanecer durante 2 años).

También existe la cuestión de la integridad referencial; La documentación de Oracle habla sobre el uso de particiones para purgar datos principalmente en el contexto de almacenes de datos, donde las tablas tienden a ser hipercubos. La nuestra está más cerca del final OLTP de las cosas, y es común que los datos en el mes X tengan relaciones con los datos en el mes Y. Crear las claves de particionamiento adecuadas para estas tablas sería, en el mejor de los casos, algo delicado.

En cuanto a los reventones de caché, he leído un poco sobre la configuración de cachés de búfer dedicados, pero parece que es más por cada tabla, en lugar de por usuario o por transacción. Para preservar el caché, realmente me gustaría que el trabajo de cosecha solo guarde el valor de una transacción en el caché en cualquier momento, ya que no hay necesidad de mantener los datos una vez eliminados.

¿Estamos atascados usando eliminaciones en el futuro previsible, o hay otras formas más inteligentes de manejar la cosecha?

+0

+1 buena pregunta, desearía tener una solución inteligente, porque yo podría utilizar yo mismo ;-) – DCookie

+0

es mantener el los datos no son una opción? es decir, podría filtrar registros antiguos en sus consultas (por ejemplo, utilizando predicados VPD) y simplemente no devolver los registros anteriores. Solo digo que si eliminar las filas está causando un problema de rendimiento, al menos consideraría la posibilidad de que mantenerlas no necesariamente sea una situación peor. –

Respuesta

4

En su mayor parte, creo que está atascado haciendo eliminaciones.

Sus comentarios sobre la dificultad de utilizar particiones en su caso probablemente impidan su uso eficaz (se usan diferentes fechas de eliminación dependiendo del tipo de registro) pero es posible que pueda crear una columna "borrar fecha" en los registros en los que puedes particionar? Tendría la desventaja de hacer las actualizaciones bastante caras, ya que un cambio en la fecha de eliminación podría causar una migración de fila, por lo que su actualización realmente se implementaría como una eliminación e inserción.

Podría ser que incluso entonces no puede usar las operaciones de partición DDL para eliminar los datos antiguos debido a los problemas de integridad referencial, pero el particionamiento todavía podría servir para aglutinar físicamente las filas que se eliminarán, por lo que se deben modificar menos bloques para eliminarlos, mitigando el impacto en la memoria caché del búfer.

0

Las eliminaciones no son tan malas, siempre que reconstruya sus índices. Oracle recuperará las páginas que ya no contienen datos.

Sin embargo, como de 8i (y muy probablemente aún), no recuperaría correctamente las páginas de índice que ya no contenían referencias válidas. Peor aún, dado que las hojas del índice estaban encadenadas, podría entrar en una situación en la que comenzaría a caminar por los nódulos de las hojas para encontrar una fila.Esto causaría una caída bastante significativa en el rendimiento: las consultas que normalmente tomarían segundos podrían llevar minutos. La caída también fue muy repentina: un día estaría bien, al día siguiente no sería así.

Descubrí este comportamiento (había un error de Oracle para que otras personas también lo hicieran) con una aplicación que usaba claves crecientes y datos eliminados con regularidad. Nuestra solución fue invertir porciones de la clave, pero eso no te ayudará con las fechas.

+0

Si todas las entradas se eliminan del bloque de hoja, se ordena bien. Si deja uno o dos, puede ser torpe. Los índices de clave inversa serían tan efectivos para las fechas como cualquier otro tipo de datos, pero tienen el efecto de hacer que los escaneos de rango no sean prácticos. Las eliminaciones grandes pueden hacer que valga la pena reconstruir ALGUNOS índices, pero medir y probar para asegurarse de que vale la pena. –

+0

Supongo que es un empleado de Oracle y se refiere a las ediciones posteriores al 8i; como dije, como-de 8i era un error conocido, sin ningún plan para arreglarlo. Al invertir las teclas, supongo que debería haber sido más claro acerca de por qué no te ayudará. – kdgregory

0

¿Qué sucede si desactiva temporalmente los índices, realiza las eliminaciones y luego los reconstruye? ¿Mejorará el rendimiento de tus eliminaciones? Por supuesto, en este caso, debe asegurarse de que los scripts sean correctos y garantizar el orden correcto de eliminación y la integridad referencial.

0

Tenemos el mismo problema, usando la misma estrategia. Si la situación se vuelve realmente mala (asignación muy fragmentada de índices, tablas, ...), tratamos de aplicar acciones de recuperación de espacio.

Las tablas tienen que permitir el movimiento de la fila (como para el retroceso): alter table TTT enable movement row; alter table TTT shrink space; y luego reconstruir todos los índices.

No sé cómo está usted con las ventanas de mantenimiento, si la aplicación tiene que ser utilizable todo el tiempo, es más difícil, si no, puede hacer un "reenvasado" cuando está fuera de línea. "alter table TTT move tablespace SSSS" hace mucho trabajo limpiando el desorden a medida que se reescribe la tabla. También puede especificar nuevos parámetros de almacenamiento, como administración de extensiones, tamaños, ... eche un vistazo a los documentos.

Yo uso un script como el siguiente para crear una secuencia de comandos para toda la base de datos:

SET SQLPROMPT "-- " 
SET ECHO OFF 
SET NEWPAGE 0 
SET SPACE 0 
SET PAGESIZE 0 
SET FEEDBACK OFF 
SET HEADING OFF 
SET TRIMSPOOL ON 
SET TERMOUT OFF 
SET VERIFY OFF 
SET TAB OFF 
spool doit.sql 
select 'prompt Enabling row movement in '||table_name||'...'||CHR (10)||'alter table '||table_name||' enable row movement;' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%'; 
select 'prompt Setting initial ext for '||table_name||'...'||CHR (10)||'alter table '||table_name||' move storage (initial 1m);' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%'; 
select 'prompt Shrinking space for '||table_name||'...'||CHR (10)||'alter table '||table_name||' shrink space;' from user_tables where table_name not like '%$%' and table_name not like '%QTAB' and table_name not like 'SYS_%'; 
select 'prompt Rebuilding index '||index_name||'...'||CHR (10)||'alter index '||index_name||' rebuild;' from user_indexes where status = 'UNUSABLE'; 
spool off 
prompt now check and then run @doit.sql 
exit 
Cuestiones relacionadas