Author: aashutosh
Updated: 17 Feb 2023 8:42 p.m.
Tags: #Linux #Database #Bash #Scripting #Automation #Oracle #SQL
Summary : Linux Bash shell script to Automatically create new date range partitions for a table every month and delete older partitions.
Lets say, I have a large table called Orders, which I need to partition based on each Month data.
Each partition will contains data for a specific month, and partitions older than 1 year will be deleted automatically.
Each partitions will reside in its own tablespace with same name.
The Bash script will
Below is an example of Partition & Tablespace naming structure
Table Name = ORDERS
New Partition Name = ORDERS_202302
New Tablespace Name = ORDERS_202302
select PARTITION_NAME,
tablespace_name,
NUM_ROWS
from dba_tab_partitions
where TABLE_OWNER = 'schema-name'
and TABLE_NAME='ORDERS' order by partition_name desc;
PARTITION_NAME TABLESPACE_NAME NUM_ROWS
------------------------- ------------------------- ----------
ORDERS_202302 ORDERS_202302 -- > To be created, new partiotion for new month
ORDERS_202301 ORDERS_202301 4074603
ORDERS_202212 ORDERS_202212 5204062
ORDERS_202211 ORDERS_202211 4981191
ORDERS_202210 ORDERS_202210 6456684
ORDERS_202209 ORDERS_202209 4821135
ORDERS_202208 ORDERS_202208 5066927
ORDERS_202207 ORDERS_202207 5824346
ORDERS_202206 ORDERS_202206 6477975
ORDERS_202205 ORDERS_202205 5091088
ORDERS_202204 ORDERS_202204 5774805
ORDERS_202203 ORDERS_202203 7063802
ORDERS_202202 ORDERS_202202 5876999
ORDERS_202201 ORDERS_202201 5098684 -- > To be Dropped, 1 year old partition
OTHER ORDERS_OTHER 102375659
#!/usr/bin/bash
# export ORACLE enviroment
export ORACLE_SID=SID; . oraenv
# Table Name to be partitioned
TABLE=ORDERS
# Partition Date Range
PARTITION_DATE_RANGE=`date +%m/01/%Y`
# NEW_TABLE_PARTITION = ORDERS_202302 (TABLENAME_YYYYMM, current year)
NEW_TABLE_PARTITION=${TABLE}_`date +%Y%m`
# OLD_TABLE_PARTITION = ORDERS_202202 (TABLENAME_YYYYMM, last year)
OLD_TABLE_PARTITION=${TABLE}_`expr $(date +%Y%m) - 100`
# NEW_INDEX_TABLESPACE = ORDERS_IX_202302 (INDEXNAME_YYYYMM, current year)
NEW_INDEX_TABLESPACE=${TABLE}_IX_`date +%Y%m`
# OLD_INDEX_TABLESPACE = ORDERS_IX_202202 (INDEXNAME_YYYYMM, last year)
OLD_INDEX_TABLESPACE=${TABLE}_IX_`expr $(date +%Y%m) - 100`
# Get the old last year tablespace (ORDERS_202202) data_file name & location,
# new tablespace (ORDERS_202302) data file, will be created in the same mount point/directory as old
# OLD_DATAFILE=/storage/APP/DATA001/oradata/orders_202202_01.dbf
OLD_DATAFILE=`sqlplus -s / as sysdba<<EOF
set heading off
set feedback off
set pagesize 0
select file_name from dba_data_files where tablespace_name = '$OLD_TABLE_PARTITION' and rownum=1 order by file_name;
EOF`
# convert names to lower case
OLD_FILE=`echo $OLD_TABLE_PARTITION | tr A-Z a-z`
NEW_FILE=`echo $NEW_TABLE_PARTITION | tr A-Z a-z`
# replace old partition_name to new partition_name in datafile name
# OLD_DATAFILE=/storage/APP/DATA001/oradata/orders_202202_01.dbf
# NEW_DATAFILE=/storage/APP/DATA001/oradata/orders_202302_01.dbf
NEW_DATAFILE=`echo $OLD_DATAFILE | sed "s/$OLD_FILE/$NEW_FILE/g"`
# get filename for index tablespace, and generate new index tablespace file name in same directory
OLD_INDEXFILE=`sqlplus -s / as sysdba<<EOF
set heading off
set feedback off
set pagesize 0
select file_name from dba_data_files where tablespace_name like '$OLD_INDEX_TABLESPACE' and rownum=1 order by file_name;
EOF`
OLD_FILE=`echo $OLD_TABLE_PARTITION | tr A-Z a-z`
NEW_FILE=`echo $NEW_TABLE_PARTITION | tr A-Z a-z`
NEW_INDEXFILE=`echo $OLD_INDEXFILE | sed "s/$OLD_FILE/$NEW_FILE/g"`
echo ""
echo "New_Partition = $NEW_TABLE_PARTITION"
echo "Old_Partition = $OLD_TABLE_PARTITION"
echo "New_Tablespace = $NEW_TABLE_PARTITION"
echo "New_DB_File = $NEW_DATAFILE"
echo "New_Index_DB_File = $NEW_INDEXFILE"
echo "New_Index_Partition = $NEW_INDEX_TABLESPACE"
echo "Old_Index_Partition = $OLD_INDEX_TABLESPACE"
echo ""
# Login to database, drop old partition & tablespace, create new tablespace & split table paritions
sqlplus / as sysdba <<EOF
set time on
set timing on
set echo on
-- Truncate older Partition
alter table schema.ORDERS truncate partition $OLD_TABLE_PARTITION;
--drop older partition
alter table schema.ORDERS drop partition $OLD_TABLE_PARTITION;
--Offline older tablespace
alter tablespace $OLD_TABLE_PARTITION offline;
-- drop older tablespace including datafiles
drop tablespace $OLD_TABLE_PARTITION including contents and datafiles;
--offline older index tablespace
alter tablespace $OLD_INDEX_TABLESPACE offline;
--drop older index tablespace including datafiles
drop tablespace $OLD_INDEX_TABLESPACE including contents and datafiles;
-- create new tablespace
create tablespace $NEW_TABLE_PARTITION datafile '$NEW_DATAFILE' size 8000M;
create tablespace $NEW_INDEX_TABLESPACE datafile '$NEW_INDEXFILE' size 8000M;
-- grant quota to schema user on new tablespace
alter user schema quota unlimited on $NEW_TABLE_PARTITION;
alter user schema quota unlimited on $NEW_INDEX_TABLESPACE;
-- Add & split Parition to table
ALTER TABLE $TABLE SPLIT PARTITION ALL_OTHER AT (TO_DATE('$PARTITION_DATE_RANGE','MM/DD/YYYY')) INTO (PARTITION $NEW_TABLE_PARTITION TABLESPACE $NEW_TABLE_PARTITION, PARTITION OTHER TABLESPACE ORDERS);
EOF
# Generate SQL script to rebuild Indexes
sqlplus -s / as sysdba<<EOF
set lin 300
set heading off
set feedback off
set pagesize 0
spool rebuild_schema_indexes.sql
select 'alter index schema.'||index_name||' rebuild subpartition '||subpartition_name||' tablespace '||tablespace_name||';' from dba_ind_subpartitions where index_name in (select distinct(index_name) from dba_indexes where table_name = 'ORDERS') and status = 'UNUSABLE' order by index_name, partition_name, subpartition_name, tablespace_name;
spool off
EOF
# Rebuild Indexes & Gather Table statistics
sqlplus -s / as sysdba<<EOF
set time on
set timing on
set echo on
@rebuild_schema_indexes.sql
exec dbms_stats.gather_table_stats('schema', 'ORDERS', DEGREE => 8, CASCADE => TRUE);
EOF