Recuperación de espacio libre en disco simplificada / automatizada


8

En Oracle versión 11g:

Después de buscar en Google, no puedo encontrar una manera simple de recuperar espacio libre después de eliminar una tabla.

He encontrado muchas explicaciones, que dicen cómo el archivo de datos se fragmenta, la gran pila de consultas aburridas que tienes que ejecutar para mover el "espacio vacío" al final del archivo de datos (tabla por tabla ... incluso cuando tener 200 mesas!?).

Luego, debe reducir el tamaño del archivo de datos "adivinando" cuánto puede reducirlo, o debe saber exactamente cuál es su "tamaño de bloque" ... Y, por último, no debe olvidarse de "reconstruir los índices".

Ver por ejemplo: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:54178027703899

y http://www.oracle-base.com/articles/misc/ReclaimingUnusedSpace.php

¿Existe un procedimiento PL / SQL simple que, dado un nombre de espacio de tabla o un nombre de archivo de datos, sería adecuado para ese trabajo? ¿O alguna herramienta similar de Oracle?


Información interesante: verifique si sus espacios de tablas están "administrados localmente" o "administrados por directorio". El primero parece tener un mejor manejo de "desfragmentar" archivos de datos. Ver: orafaq.com/node/3
Frosty Z

Respuestas:


5

La respuesta corta es no . Desafortunadamente, la forma de hacer esto en Oracle requiere la "gran pila de consultas aburridas". Los artículos a los que se vinculó son la mejor información disponible sobre el tema. De hecho, el archivo de datos se fragmenta, de modo que incluso si el espacio libre existe debajo del segmento más alto, Oracle no lo consolidará automáticamente cuando RESIZEhaya terminado.

Para "desfragmentar" el espacio de tablas, debe mover estos segmentos al inicio del archivo de datos en lugar de al final. Para las tablas, este es un proceso fuera de línea, lo que significa que la tabla no estará disponible mientras se realiza el movimiento. Los índices se pueden mover fuera de línea o con Enterprise Edition, se pueden mover en línea. Como tiene una ventana de interrupción, le recomiendo que siga estos pasos.

A. Reduzca los archivos de datos con espacio libre más allá de la marca de límite superior. Esto se puede hacer de la siguiente manera (la consulta es similar al procedimiento de Frosty Z):

SELECT ceil( blocks*(a.BlockSize)/1024/1024) "Current Size",
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Smallest Poss.",
   ceil( blocks*(a.BlockSize)/1024/1024) -
   ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) "Savings",
   'alter database datafile '''|| file_name || ''' resize ' || 
      ceil((nvl(hwm,1)*(a.BlockSize))/1024/1024/100)*100  || 'm;' "Command"
FROM (SELECT a.*, p.value BlockSize FROM dba_data_files a 
JOIN v$parameter p ON p.Name='db_block_size') a
LEFT JOIN (SELECT file_id, max(block_id+blocks-1) hwm FROM dba_extents GROUP BY file_id ) b
ON a.file_id = b.file_id
WHERE ceil( blocks*(a.BlockSize)/1024/1024) - ceil( (nvl(hwm,1)*(a.BlockSize))/1024/1024 ) 
   > 100 /* Minimum MB it must shrink by to be considered. */
ORDER BY "Savings" Desc;

B. Después de reducir las cosas por encima de la marca de agua alta, averigüe qué espacios de tabla aún se beneficiarían si se movieran los segmentos.

SELECT DISTINCT tablespace_name FROM
(      
    SELECT tablespace_name, block_id + blocks LastBlock,
       lead(block_id) OVER (PARTITION BY File_ID 
          ORDER BY tablespace_name, file_id, block_id) NextBlock
       FROM dba_free_space 
) WHERE LastBlock <> NextBlock AND NextBlock IS NOT NULL;

C. Para cada uno de estos espacios de tabla, determine qué segmentos deben moverse. (Reemplace USUARIOS con el nombre de su tablespace o únase a él con la consulta anterior)

SELECT distinct de.segment_name
FROM dba_extents de
JOIN
(
   SELECT tablespace_name, file_id, MIN(block_id) LowestFreeBlock
   FROM dba_free_space
   WHERE tablespace_name = 'USERS'
  GROUP BY tablespace_name, file_id
) dfs ON dfs.tablespace_name = de.tablespace_name AND dfs.file_id = de.file_id
WHERE de.tablespace_name = 'USERS'
AND de.block_id > dfs.LowestFreeBlock;

D. Mueva cada tabla y reconstruya los índices y estadísticas.

E. Repita el paso A.

Acabo de construir la mayoría de estas consultas, por lo que querrá probarlas a fondo antes de usarlas. Supongo que podría crear un procedimiento que usaría EXECUTE IMMEDIATEpara crear las declaraciones reales para que se ejecuten dinámicamente, pero debido a que las consultas recibirán ORA-08103: el objeto ya no existe mientras el movimiento está en progreso, creo que es mejor controlar ese proceso manualmente incluso si significa un poco más de tiempo / esfuerzo.


3

Solución parcial inspirada en esta página :

No reorganiza el espacio libre, pero detecta automáticamente el espacio libre disponible al final de los archivos de datos e imprime los comandos 'RESIZE' adecuados.

DECLARE
    BLKSIZE INTEGER;

BEGIN
    SELECT VALUE INTO BLKSIZE FROM V$PARAMETER WHERE NAME = 'db_block_size';

    FOR INDEX_ROW IN (
      SELECT 'ALTER DATABASE DATAFILE ''' || FILE_NAME || ''' RESIZE ' || CEIL( (NVL(HWM,1)*BLKSIZE)/1024/1024 ) || 'M;' SHRINK_DATAFILES FROM DBA_DATA_FILES DBADF,
            (SELECT FILE_ID, MAX(BLOCK_ID+BLOCKS-1) HWM FROM DBA_EXTENTS GROUP BY FILE_ID ) DBAFS
            WHERE DBADF.FILE_ID = DBAFS.FILE_ID(+) AND CEIL(BLOCKS*BLKSIZE/1024/1024)- CEIL((NVL(HWM,1)* BLKSIZE)/1024/1024 ) > 0
    ) LOOP
        DBMS_OUTPUT.PUT_LINE(INDEX_ROW.SHRINK_DATAFILES);
    END LOOP;
END;

2

Antes de intentar reducir los archivos de datos, pregúntese: ¿va a crear nuevos segmentos nuevamente dentro del espacio de tablas asociado en un futuro no tan lejano? Si es así, no tiene sentido encogerse. El espacio simplemente se reutilizará para sus nuevos segmentos y se ahorrará mucho esfuerzo al sistema y lo dejará como está.


2

Después de navegar en Google durante días, he encontrado el ejemplo más simple y claro para reclamar el espacio libre en el espacio de tabla después de eliminarlo. espero que esto ayude

Enlace: http://www.dbforums.com/oracle/976248-how-reduce-tablespaces-used-space-after-delete-records-2.html

solución:

ALTER TABLE MOVE demo

Creemos una tabla con 9999 filas, cada una de ellas con un tamaño de alrededor de 1k:

SQL> create table t (x char(1000) default 'x' primary key);
Table created.
SQL> insert /*+ append nologging */ into t(x) select rownum from all_objects where rownum < 10000;
9999 rows created.
SQL> commit;
Commit complete.

La tabla tiene 29 extensiones asignadas, para un total de 14.6M:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

Eliminemos TODAS las filas:

SQL> delete from t;
9999 rows deleted.
SQL> commit;
Commit complete.

Ahora- "sorpresa" - la tabla todavía usa las mismas extensiones:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 14680064

Por qué ? Porque incluso si elimina todas las filas de la tabla, la High Water Mark no disminuye, nunca disminuye para permitir la máxima concurrencia (Oracle se toma muy en serio la maximización de la concurrencia, es decir, el rendimiento y la escalabilidad; es la razón principal de su éxito en aplicaciones empresariales).

Desasignar el espacio no utilizado (= espacio sobre el HWM) no ayuda mucho (ya que no hay mucho espacio no utilizado sobre el HWM):

SQL> alter table t deallocate unused;
Table altered.
SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
29 13959168

Ahora, MOVEMOS la tabla, que en esencia significa clonar la tabla (incluidos los desencadenantes, restricciones, etc.), transferir las filas, soltar la tabla "antigua" y cambiar el nombre de la nueva, todo hecho por el núcleo, muy seguro incluso en caso de falla de la máquina / servidor:

SQL> alter table t move;
Table altered.

Ahora, solo tenemos la extensión inicial asignada:

SQL> select count(*), sum(bytes) from user_extents where segment_name='T';
COUNT(*) SUM(BYTES)
---------- ----------
1 65536

Advertencia: normalmente sucede que muchos / todos los índices de la tabla no se pueden usar después del movimiento (no en este caso, pero estoy ejecutando 9.2.0.4, la última versión, que probablemente ha optimizado el proceso en el caso de tablas totalmente vacías ):

SQL> col table_name form a30
SQL> col index_name form a30
SQL> set lines 123 
SQL> select table_name, index_name, status from user_indexes where table_name='T';

TABLE_NAME INDEX_NAME STATUS
------------------------------ ------------------------------ ------------------------
T SYS_C002573 VALID

Si STATUS no fuera VÁLIDO, simplemente podría reconstruir manualmente los índices:

SQL> alter index SYS_C002573 rebuild;
Index altered.

O podría automatizar todo el proceso:

set serveroutput on size 100000
begin
for n in (select index_name from user_indexes where status <> 'VALID') loop
dbms_output.put_line ('rebuilding ' || n.index_name);
execute immediate 'alter index ' || n.index_name || ' rebuild';
end loop;
end;
/

Como ejemplo, configuremos manualmente el índice como INUSABLE:

SQL> alter index SYS_C002573 unusable;
Index altered.

SQL> set serveroutput on size 100000
SQL> begin
2 for n in (select index_name from user_indexes where status <> 'VALID') loop
3 dbms_output.put_line ('rebuilding ' || n.index_name);
4 execute immediate 'alter index ' || n.index_name || ' rebuild';
5 end loop;
6 end;
7 /
rebuilding SYS_C002573

PL/SQL procedure successfully completed.

HTH Alberto


1

Como se dijo anteriormente, tendrá que mover todas las más de 200 tablas en ese espacio de tablas para liberar espacio en su archivo de datos y luego cambiar el tamaño para recuperar el espacio. Pero en lugar de ejecutar todas esas consultas, 12c Enterprise Manager realiza esta tarea. Tendrá que navegar a Inicio de la base de datos> Almacenamiento> Espacio de tabla. Seleccione el espacio de tabla en el que desea trabajar y haga clic en Reorganizar. Le dará una opción para ver las instrucciones SQL que están a punto de ejecutarse. Puede tomar una copia de ellos y ejecutarla usted mismo o programar un trabajo en EM.

Realmente crea otro espacio de tabla, mueve todos los objetos al nuevo espacio de tabla, reconstruye los índices y suelta los objetos del antiguo espacio de tabla.

Hay un par de inconvenientes en los que puedo pensar. Esto debe hacerse durante las horas de menor actividad; de lo contrario, aparecerá un error diciendo que el recurso está ocupado. El archivo de datos (no el espacio de tabla) tendrá "reorg" agregado a su nombre, hacia el final.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.