Πώς γλυτώνουμε χώρο από παλιά partitions πινάκων σε βάση δεδομένων της Oracle
- Πώς συλλέγουμε to actual execution plan από τα queries με χρήση Extended Event και πως διαβάζουμε τα δεδομένα του - 2 Δεκέμβριος 2024
- Πώς βρίσκουμε τι δικαιώματα έχει ένας χρήστης σε βάση δεδομένων της Oracle - 1 Νοέμβριος 2024
- Πώς ενεργοποιούμε το Unified Auditing σε Oracle Database - 7 Οκτώβριος 2024
Όταν έχουμε πολύ μεγάλους πίνακες βοηθάει πολύ η χρήση Table Partitions. Το Table Partition χωρίζει τον πίνακα σε μικρότερα κομμάτια ανάλογα με το πεδίο που έχουμε ορίσει ως κριτήριο π.χ. “ημερομηνία εισαγωγής”, τα κομμάτια αυτά μπορεί να βρίσκονται είτε στο ίδιο tablespace είτε σε διαφορετικά. Με τη χρήση τους βελτιώνετε η απόδοση των queries αλλά μας δίνονται και περισσότερες δυνατότητες κατά το backup π.χ. να μην πέρνουμε backup παλιά partitions που δεν αλλάζουν. Το πρόβλημα όμως είναι ότι σε βάθος χρόνου ακόμα και να μην έχουν πλέον εγγραφές τα partitions καταλαμβάνουν κάποιο χώρο. Σε αυτό το άρθρο θα δούμε πως μπορούμε να ελευθερώσουμε αυτόν τον χώρο σε Oracle Database.
Πώς βρίσκουμε τα Table Partitions
Με το παρακάτω query που έχω γράψει μπορούμε να βρούμε για ένα συγκεκριμένο σχήμα π.χ. το “SH”, πόσα Table Partitions υπάρχουν που δεν περιέχουν στο όνομα τους το φετινό έτος και δεν περιέχουν αυτή τη στιγμή εγγραφές.
Μέσα από αυτό το query μπορούμε να δούμε το μέγεθος του κάθε partition και να μας γίνουν generate με dynamic SQL οι εντολές που θα χρειαστούμε για την διεργασία:
select ALLP.TABLE_OWNER,ALLP.TABLE_NAME,ALLP.PARTITION_NAME,ALLP.NUM_ROWS,ALLP.TABLESPACE_NAME,SEGM.GB_size, 'select * from ' ||ALLP.TABLE_OWNER||'.'||ALLP.TABLE_NAME ||' PARTITION ("'||ALLP.PARTITION_NAME||'");' as select_partition, 'ALTER TABLE '||ALLP.TABLE_OWNER||'.'||ALLP.TABLE_NAME ||' TRUNCATE PARTITION "'||ALLP.PARTITION_NAME||'" UPDATE INDEXES;' as truncate_partition from all_tab_partitions ALLP left join (select owner,partition_name,round(bytes/1024/1024/1024,3) as GB_size from dba_segments) SEGM on SEGM.PARTITION_NAME=ALLP.PARTITION_NAME and SEGM.OWNER=ALLP.TABLE_OWNER where 1=1 and ALLP.table_owner = 'SH' and ALLP.partition_name not like (select '%'||extract(year from sysdate)||'%' from dual) and ALLP.num_rows = 0 order by partition_name;
Στην στήλη SELECT_PARTITION μας γίνετε generate το query για να δούμε τι εγγραφές περιέχει το κάθε partition. Στην περίπτωση μας για όποιο partition και να το τρέξουμε θα δούμε ότι δεν επιστρέφει εγραφές, αφού έχουμε ορίσει να μας φέρει μόνο τα partitions με μηδενικές εγγραφές:
select * from SH.COSTS PARTITION ("COSTS_1995");
Πώς αποδεσμεύουμε τον χώρο
Στην στήλη TRUNCATE_PARTITION μας γίνετα generate το query της εντολής για το κάθε partition ξεχωριστά η οποία θα σβήσει τις εγγραφές (αν υπάρχουν μέσα) και θα αποδευσμεύσει τον χώρο που καταλαμβάνει χωρίς όμως να σβήσει το partition. Για να ενημερωθεί ταυτόχρονα και ο Index Online και να μην γυρίσει σε Unusable η εντολή περιέχει την παράμετρο Update Indexes:
ALTER TABLE SH.COSTS TRUNCATE PARTITION "COSTS_1995" UPDATE INDEXES;
Για να δούμε το συνολικό μέγεθος του σχήματος πριν τρέξουμε το Truncate Partition, τρέχουμε το παρακάτω:
select round(sum(bytes)/1024/1024/1024,3) as GB_size from dba_segments SEGM where SEGM.OWNER ='SH';
Πώς μπορεί να τρέξει αυτόματα η διαδικασία για όλα τα Table Partitions που πληρούν τα κριτήρια
Για να κάνουμε τη ζωή μας πιο εύκολη μπορούμε το παραπάνω query με κάποιες μετατροπές να το φτιάξουμε έτσι ώστε όταν το εκτελούμε ως εκτελέσιμο αρχείο πάνω από τον Oracle Database Server να δημιουργεί τις εντολές και έπειτα να τις εκτελεί μία μία μόνο του.
Το μόνο που χρειάζεται να κάνουμε είναι να πάρουμε το παρακάτω query και να το αποθηκεύσουμε σε ένα αρχείο τοπικά πάνω στον Server με όνομα π.χ truncate_tables.sql:
set linesize 200; set heading off; set feedback off; set echo off; set pagesize 0; spool truncate_partitions_commands.txt select 'ALTER TABLE '||ALLP.TABLE_OWNER||'.'||ALLP.TABLE_NAME ||' TRUNCATE PARTITION "'||ALLP.PARTITION_NAME||'" UPDATE INDEXES;' as truncate_partition from all_tab_partitions ALLP left join (select owner,partition_name from dba_segments) SEGM on SEGM.PARTITION_NAME=ALLP.PARTITION_NAME and SEGM.OWNER=ALLP.TABLE_OWNER where 1=1 --and ALLP.table_owner = 'SH' and ALLP.partition_name not like (select '%'||extract(year from sysdate)||'%' from dual) and ALLP.num_rows = 0; spool off; @truncate_partitions_commands.txt exit;
Έπειτα φτιάχνουμε ένα εκτελέσιμο αρχείο που θα το καλεί με όνομα π.χ. truncate_partitions.sh:
#!/usr/bin/ksh sqlplus / as sysdba @truncate_partitions.sql
Το μόνο που μένει να κάνουμε είναι να το εκτελέσουμε:
[opc@dp-gr ~]$ chmod +x truncate_partitions.sh
[opc@dp-gr ~]$ ./truncate_partitions.sh