Recupero di spazio libero su disco per file di dati semplificato / automatizzato


8

Su Oracle versione 11g:

Dopo aver cercato su Google, non riesco a trovare un modo semplice per recuperare spazio libero dopo aver eliminato una tabella.

Ho trovato molte spiegazioni, raccontando come il file di dati diventa frammentato, la grande pila di query noiose che devi eseguire per spostare lo "spazio vuoto" alla fine del file di dati (tabella per tabella ... anche quando hai 200 tavoli!?).

Quindi devi ridurre la dimensione del file di dati "indovinando" di quanto puoi ridurla, oppure devi sapere esattamente qual è la tua "dimensione del blocco" ... E infine non dovresti dimenticare di "ricostruire gli indici".

Vedi ad esempio: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:54178027703899

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

Esiste una semplice procedura PL / SQL che, dato un nome di tablespace o un nome di file di dati, farebbe a quel lavoro? O qualsiasi strumento Oracle simile?


Informazioni interessanti: controlla se i tuoi tablespace sono "gestiti localmente" o "gestiti dalla directory". Il primo sembra avere una migliore gestione dei file di dati "deframmentati". Vedi: orafaq.com/node/3
Frosty Z

Risposte:


5

La risposta breve è No . Sfortunatamente, il modo per farlo in Oracle richiede il "grosso stack di query noiose". Gli articoli a cui sei collegato sono alcune delle migliori informazioni disponibili sull'argomento. Il file di dati diventa effettivamente frammentato, cosicché anche se esiste spazio libero al di sotto del segmento più alto, Oracle non lo consoliderà automaticamente al RESIZEtermine.

Per "deframmentare" il tablespace è necessario spostare questi segmenti all'inizio del file di dati anziché alla fine. Per le tabelle si tratta di un processo offline che significa che la tabella non sarà disponibile durante lo spostamento. Gli indici possono essere spostati offline o con Enterprise Edition possono essere spostati online. Dato che hai una finestra di interruzione, ti consiglio di seguire questi passaggi.

A. Ridurre i file di dati con spazio libero oltre il limite massimo. Questo può essere fatto come segue (la query è simile alla procedura di 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. Dopo aver ridotto le cose al di sopra del livello massimo dell'acqua, scopri quali spazi del tavolo trarrebbero ancora beneficio se i segmenti venissero spostati.

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. Per ciascuno di questi tablespace, determinare quali segmenti devono essere spostati. (Sostituisci USER con il nome del tuo tablespace o unisciti a esso con la query precedente)

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. Spostare ogni tabella e ricostruire gli indici e le statistiche.

E. Ripetere il passaggio A.

Ho appena creato la maggior parte di queste query, quindi ti consigliamo di testarle accuratamente prima dell'uso. Suppongo che potresti creare una procedura da utilizzare EXECUTE IMMEDIATEper creare le istruzioni effettive da eseguire in modo dinamico, ma poiché le query riceveranno ORA-08103: l'oggetto non esiste più mentre è in corso lo spostamento, penso che sia meglio controllare quel processo manualmente anche se ciò significa un po 'più di tempo / fatica.


3

Soluzione parziale ispirata a questa pagina :

Non riorganizza lo spazio libero ma rileva automaticamente lo spazio libero disponibile alla fine dei file di dati e stampa i comandi 'RESIZE' corretti.

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

Prima di provare a ridurre i file di dati, chiediti: hai intenzione di creare di nuovo nuovi segmenti all'interno del tablespace associato in un futuro non molto lontano? Se sì, non ha senso ridursi. Lo spazio verrà riutilizzato per i tuoi nuovi segmenti e risparmierai te stesso e il sistema lasciandolo così com'è.


2

Dopo aver navigato su Google per giorni, ho trovato l'esempio più semplice e chiaro per recuperare lo spazio libero nel tablespace dopo l'eliminazione. spero che questo possa essere d'aiuto

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

soluzione:

ALTER TABLE MOVE demo

Creiamo una tabella con 9999 righe al suo interno, ciascuna delle dimensioni intorno a 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 tabella ha 29 estensioni assegnate ad essa, per un totale di 14,6 milioni:

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

Eliminiamo TUTTE le righe:

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

Ora "sorpresa" - la tabella usa ancora le stesse estensioni:

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

Perché ? Perché anche se si eliminano tutte le righe della tabella, l'High Water Mark non viene diminuito, non viene mai diminuito, per consentire la massima concorrenza (Oracle è seriamente intenzionato a massimizzare la concorrenza, ovvero prestazioni e scalabilità; è la ragione principale del suo successo nelle applicazioni Enterprise).

La deallocazione dello spazio inutilizzato (= spazio sopra l'HWM) non aiuta molto (poiché non c'è molto spazio inutilizzato sopra l'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

Muoviamo ora la tabella, che in sostanza significa clonare la tabella (inclusi trigger, vincoli e così via), trasferire le righe, eliminare la "vecchia" tabella e rinominare la nuova - tutto creato dal kernel, così super-sicuro anche in caso di guasto macchina / server:

SQL> alter table t move;
Table altered.

Ora, abbiamo ora solo l'estensione iniziale assegnata:

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

Avvertenza: in genere accade che molti / tutti gli indici sulla tabella siano INUTILIZZABILI dopo lo spostamento (non in questo caso ma sto eseguendo 9.2.0.4, l'ultima versione, che probabilmente ha ottimizzato il processo in caso di tabelle totalmente vuote ):

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

Se STATUS non fosse VALID, potresti semplicemente ricostruire manualmente gli indici:

SQL> alter index SYS_C002573 rebuild;
Index altered.

Oppure potresti automatizzare l'intero processo:

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;
/

Ad esempio, impostiamo manualmente l'indice su UNUSABLE:

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.

HT Alberto


1

Come detto in precedenza, dovrai spostare tutte le oltre 200 tabelle in quello spazio tabella per liberare spazio nel tuo file di dati e quindi ridimensionare per recuperare lo spazio. Ma invece di eseguire tutte quelle query, 12c Enterprise manager esegue questa attività. Dovrai accedere a Database Home> Archiviazione> Spazio tabelle. Seleziona il tablespace su cui vuoi lavorare e fai clic su Riorganizza. Fornirà un'opzione per visualizzare le istruzioni SQL che stanno per essere eseguite. Puoi prenderne una copia ed eseguirlo da solo o pianificare un lavoro in EM.

In realtà crea un altro tablespace, sposta tutti gli oggetti nel nuovo tablespace, ricostruisce gli indici e rilascia gli oggetti dal vecchio tablespace.

Ci sono un paio di inconvenienti che mi vengono in mente. Questo dovrebbe essere fatto durante le ore non di punta, altrimenti verrà fuori dicendo che la risorsa è occupata. Il file di dati (non tablespace) avrà "reorg" aggiunto al suo nome, verso la fine.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.