暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

ORACLE EXPDP 备份脚本(2025/12/30更新)

原创 楚枫默寒 2024-11-01
260

20251215 更新,1、自动配置并行。2、同时只能进行一个expdp任务,避免资源占用

  1. 自动跟据数据库版本调用 exp 或 expdp
  2. 备份完成后自动移到备份当天日期目录
  3. 可配置备份保留次数,自动清理过期备份
  4. 备份 DG 配置、用户(非系统用户:如 SYS,SYSTEM 等,可自行修改)、用户权限、字符集信息
  5. 表空间信息
  6. 导出profile脚本
  7. 指定用户备份时按下图修改

备份结果:

脚本如下:

#!/bin/bash
 
#==============================================================#
# File    :  expbackup.sh                                      #
# Ctime   :  2022/07/22                                        #
# Mtime   :  2025/12/30                                        #
# Desc    :  Oracle Database EXPDP for single/standlone/rac    #
# Version :  3.0.0                                             #
#==============================================================#

if [[ ! $USER == "oracle" ]];then
    echo -e "此脚本必须以\033[31;1m oracle \033[0m权限运行"
    exit 1
fi

env_set(){
    umask 022
    export ORACLE_SID=xxxx
    export ORACLE_BASE=xxxx
    export ORACLE_HOME=xxxx
    export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin
    export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/usr/lib
    export PS1='$ORACLE_SID:$PWD>'
    
    export LANG=en_US.UTF-8
    
    DB_VER_PRI=$(sqlplus -v|awk '{print $3}' | cut -f 1 -d '.')
    
    db_name=$(sqlplus -s / as sysdba << EOF
set heading off feedback off verify off
select name from v\$database;
exit;
EOF
)
    db_name=$(echo $db_name | tr -d '[:space:]')
    
    BACKPATH='/rman'                            #备份路径
    DBTIME=$(date +%Y%m%d)                      #备份时间
    BAKDIR=${DBTIME}_${db_name}_exp          #EXP备份目录
    ALTIME=$(date +%Y%m%d%H%M%S)                #备份时间
    FILENAME=${db_name}_${ALTIME}
    F_exp_file=FULL_exp_${db_name}_${ALTIME}
    F_expdp_file=FULL_expdp_${db_name}_${ALTIME}
}

calculate_parallelism(){
    if [[ -e /etc/os-release ]];then
        local Verfile='/etc/os-release'
    elif [[ -e /etc/system-release ]];then
        local Verfile='/etc/system-release'
    elif [[ -e /etc/redhat-release ]];then
        local Verfile='/etc/redhat-release'
    fi 
    local os_version=$(cat ${Verfile}|egrep -o '[0-9]{1,3}'|head -n 1)
    #磁盘IOPS
    local temp_file="/tmp/rman_io_test_$$.tmp"
    local io_parallel=$(if command -v dd >/dev/null 2>&1; then
        io_result=$(dd if=/dev/zero of="$temp_file" bs=1M count=1024 2>&1)
        
        # 清理临时文件
        rm -f "$temp_file"
        
        # 提取IO速度
        if echo "$io_result" | grep -q "MB/s"; then
            echo "$io_result" | awk '/MB\/s/{sub(/ MB\/s/, ""); printf "%.0f\n",$8/100}'
        elif echo "$io_result" | grep -q "GB/s"; then
            echo "$io_result" | awk '/GB\/s/{sub(/ GB\/s/, ""); printf "%.0f\n", $NF*1024/100}'
        else
            echo "1"  # 默认值
        fi
    else
        echo "1"  # dd命令不可用时的默认值
    fi)
    #CPU核心数
    local cpu_cores=$(if command -v nproc >/dev/null 2>&1; then
        nproc
    else
        grep -c "^processor" /proc/cpuinfo
    fi)
    #可用内存/GB
    local mem_based=$(if [[ -f /proc/meminfo ]] && grep -q "MemAvailable" /proc/meminfo; then
        # CentOS 7+ 使用MemAvailable
        awk '/MemAvailable/{printf "%.0f", $2/1024/1024}' /proc/meminfo
    else
        # CentOS 5/6 使用free命令
        free -m | awk '/Mem:/{print int($4/1024)}'
    fi)
    case $os_version in
        5) cpu_based=$((cpu_cores / 2)) ;;
        6) cpu_based=$((cpu_cores * 3 / 5)) ;;
        7) cpu_based=$((cpu_cores * 3 / 4)) ;;
        *) cpu_based=$((cpu_cores / 2)) ;;
    esac
    case $os_version in
        5) max_parallel=4 ;;
        6) max_parallel=8 ;;
        7) max_parallel=16 ;;
        *) max_parallel=8 ;;
    esac
    parallel_NO=$(echo "$cpu_based $mem_based $io_parallel" | tr ' ' '\n' | sort -n | head -1)
    if [[ $parallel_NO -lt 1 ]]; then
        parallel_NO=1
    elif [[ $parallel_NO -gt $max_parallel ]]; then
        parallel_NO=$max_parallel
    fi
}

database_back(){
    EXPID=$(ps aux|grep expdp|grep -v grep|awk '{print $2}')
    if [[ -z ${EXPID} ]];then
        #执行备份
        if [[ ${DB_VER_PRI} -eq 10 ]];then
            exp \"/ as sysdba\" file=${BACKPATH}/${F_exp_file}.dmp log=${BACKPATH}/${F_exp_file}.log direct=y compress=Y recordlength=65535 statistics=none full=y;#10
            #压缩备份文件
            gzip ${BACKPATH}/${F_exp_file}.dmp;
        else
            expdp \"/ as sysdba\" DIRECTORY=EXPDIR DUMPFILE=${F_expdp_file}_%U.dmp logfile=${F_expdp_file}_00.log parallel=${parallel_NO} compression=ALL cluster=N exclude=STATISTICS full=y;#11
        fi
        datainfo_back
    else
        echo -e ${RC}"有EXPDP备份进行中"${EC};
    fi
}

datainfo_back(){
#导出附加信息
sqlplus -s / as sysdba <<EOF
create pfile='${BACKPATH}/pfile_${FILENAME}.ora' from spfile;
set line 900
set newpage none
set heading off
set feedback off
set pagesize 0
set echo on
set newp none
set trimout on
set trimspool on
set SERVEROUTPUT ON size 1000000
col name for a20
col value for a50
col display_value for a50
col CMD for a200
col instance_name for a10 
col host_name  for a20 
col online_status for a10 
col TABLESPACE_NAME  for a40 
col status for a10
col Extent for a10 
col sql_TODO for a150
col parameter for a30
spool ${BACKPATH}/DG_${FILENAME}.ini
select name,value,display_value from v\$parameter where name='log_archive_config' or (name like 'log_archive_dest_%' and name not like 'log_archive_dest_state_%') and value is not null order by 1;
spool ${BACKPATH}/CHARACTERSET_${FILENAME}.conf
select * from nls_database_parameters where parameter like '%CHARACTERSET%' order by 1;
spool ${BACKPATH}/profile_${FILENAME}.sql
SELECT v.sql_todo FROM (select profile, decode(PROFILE, 'DEFAULT','alter profile '||PROFILE||' limit '||reslist||';','MONITORING_PROFILE','alter profile '||PROFILE||' limit '||reslist||';', 'create profile '||PROFILE||' limit '||reslist||';') sql_todo from (select profile, listagg(resource_name||' '||limit,',') within group (order by resource_name||' '||limit) reslist from dba_profiles where profile<>'ORA_STIG_PROFILE' group by profile order by 1)) v;
spool ${BACKPATH}/DB_user_create_${FILENAME}.sql
select 'CREATE USER "'||a.username||'" IDENTIFIED BY VALUES '''||b.spare4||';'||b.password||''' DEFAULT TABLESPACE "'||a.default_tablespace||'" TEMPORARY TABLESPACE "'||a.temporary_tablespace||'";' CMD from dba_users a,sys.user\$ b where a.username not in ('APEX_050000','AUDSYS','ADAMS','ANONYMOUS','AURORA$ORB$UNAUTHENTICATED', 'AWR_STAGE', 'APEX_030200','APEX_040200','APEX_PUBLIC_USER','APPQOSSYS','BLAKE','CLARK',' CS MIG','CTXSYS','DBSNMP','DIP','DMSYS','DSSYS','DEMO','DVSYS','DVF','DBSFWUSER','EXFSYS','FLOWS_FILES','GGSYS','GSMADMIN_INTERNAL','GSMCATUSER','GSMUSER','JONES','LBACSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORACLE_OCM','ORDDATA','ORDPLUGINS','ORDSYS','OUTLN','OWBSYS','OWBSYS_AUDIT','OJVMSYS','PE RFS TAT','REMOTE_SCHEDULER_AGENT','SI_INFORMTN_SCHEMA','SPATIAL_CSW_ADMIN_USR','SPATIAL_WFS_ADMIN_USR','SYS','SYSMAN','SPATIAL_CSW_ADMIN_USR','SYSBACKUP','SYSKM','SYSDG','SYSRAC','SYS$UMF','SYSTEM','TRA CES VR','T SMS YS','WMSYS','XDB','XS$NULL','GSMROOTUSER','ZABBIX') and account_status='OPEN' and a.username= b.name ;
spool ${BACKPATH}/Privs_table_${FILENAME}.sql
select 'grant '||PRIVILEGE||' on '||grantor||'.'||TABLE_NAME||' to '||GRANTEE||';' CMD from dba_tab_privs where ( grantee in (select username from dba_users where username not in ('APEX_050000','AUDSYS','ADAMS','ANONYMOUS','AURORA$ORB$UNAUTHENTICATED', 'AWR_STAGE', 'APEX_030200','APEX_040200','APEX_PUBLIC_USER','APPQOSSYS','BLAKE','CLARK',' CS MIG','CTXSYS','DBSNMP','DIP','DMSYS','DSSYS','DEMO','DVSYS','DVF','DBSFWUSER','EXFSYS','FLOWS_FILES','GGSYS','GSMADMIN_INTERNAL','GSMCATUSER','GSMUSER','JONES','LBACSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORACLE_OCM','ORDDATA','ORDPLUGINS','ORDSYS','OUTLN','OWBSYS','OWBSYS_AUDIT','OJVMSYS','PE RFS TAT','REMOTE_SCHEDULER_AGENT','SI_INFORMTN_SCHEMA','SPATIAL_CSW_ADMIN_USR','SPATIAL_WFS_ADMIN_USR','SYS','SYSMAN','SPATIAL_CSW_ADMIN_USR','SYSBACKUP','SYSKM','SYSDG','SYSRAC','SYS$UMF','SYSTEM','TRA CES VR','T SMS YS','WMSYS','XDB','XS$NULL','GSMROOTUSER','ZABBIX') and account_status='OPEN')) 
union 
select 'grant '||PRIVILEGE||' on '||grantor||'.'||TABLE_NAME||' to '||GRANTEE||';' CMD from dba_tab_privs where ( owner in (select username from dba_users where username not in ('APEX_050000','AUDSYS','ADAMS','ANONYMOUS','AURORA$ORB$UNAUTHENTICATED', 'AWR_STAGE', 'APEX_030200','APEX_040200','APEX_PUBLIC_USER','APPQOSSYS','BLAKE','CLARK',' CS MIG','CTXSYS','DBSNMP','DIP','DMSYS','DSSYS','DEMO','DVSYS','DVF','DBSFWUSER','EXFSYS','FLOWS_FILES','GGSYS','GSMADMIN_INTERNAL','GSMCATUSER','GSMUSER','JONES','LBACSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORACLE_OCM','ORDDATA','ORDPLUGINS','ORDSYS','OUTLN','OWBSYS','OWBSYS_AUDIT','OJVMSYS','PE RFS TAT','REMOTE_SCHEDULER_AGENT','SI_INFORMTN_SCHEMA','SPATIAL_CSW_ADMIN_USR','SPATIAL_WFS_ADMIN_USR','SYS','SYSMAN','SPATIAL_CSW_ADMIN_USR','SYSBACKUP','SYSKM','SYSDG','SYSRAC','SYS$UMF','SYSTEM','TRA CES VR','T SMS YS','WMSYS','XDB','XS$NULL','GSMROOTUSER','ZABBIX') and account_status='OPEN'));
spool ${BACKPATH}/Privs_user_${FILENAME}.sql
DECLARE
  l_privs CLOB;
BEGIN
  FOR rec IN (SELECT PRIVILEGE, ADMIN_OPTION, GRANTEE FROM DBA_SYS_PRIVS where grantee in (select username from dba_users where username not in ('APEX_050000','AUDSYS','ADAMS','ANONYMOUS','AURORA$ORB$UNAUTHENTICATED', 'AWR_STAGE', 'APEX_030200','APEX_040200','APEX_PUBLIC_USER','APPQOSSYS','BLAKE','CLARK',' CS MIG','CTXSYS','DBSNMP','DIP','DMSYS','DSSYS','DEMO','DVSYS','DVF','DBSFWUSER','EXFSYS','FLOWS_FILES','GGSYS','GSMADMIN_INTERNAL','GSMCATUSER','GSMUSER','JONES','LBACSYS','MDDATA','MDSYS','MGMT_VIEW','OLAPSYS','ORACLE_OCM','ORDDATA','ORDPLUGINS','ORDSYS','OUTLN','OWBSYS','OWBSYS_AUDIT','OJVMSYS','PE RFS TAT','REMOTE_SCHEDULER_AGENT','SI_INFORMTN_SCHEMA','SPATIAL_CSW_ADMIN_USR','SPATIAL_WFS_ADMIN_USR','SYS','SYSMAN','SPATIAL_CSW_ADMIN_USR','SYSBACKUP','SYSKM','SYSDG','SYSRAC','SYS$UMF','SYSTEM','TRA CES VR','T SMS YS','WMSYS','XDB','XS$NULL','GSMROOTUSER','ZABBIX') and account_status='OPEN')) LOOP
    l_privs := 'GRANT ' || rec.PRIVILEGE || ' TO ' || rec.GRANTEE ||
               CASE WHEN rec.ADMIN_OPTION = 'YES' THEN ' WITH ADMIN OPTION' ELSE '' END || ';';
    DBMS_OUTPUT.PUT_LINE(l_privs);
  END LOOP;
END;
/
SET heading on
SET pagesize 50
spool ${BACKPATH}/Tablespace_${FILENAME}.txt
SELECT I.instance_name,I.host_name,A.status,A.autoextensible Extent,A.TABLESPACE_NAME,ROUND(A.TOTAL_SPACE/1024/1024/1024,0) TOTAL_GB,ROUND((A.BYTES_ALLOC-NVL(B.BYTES_FREE,0))/1024/1024/1024,0) USED_GB
FROM (SELECT status,TABLESPACE_NAME,SUM(BYTES) BYTES_ALLOC,SUM(DECODE(AUTOEXTENSIBLE, 'YES', MAXBYTES, BYTES)) TOTAL_SPACE,autoextensible FROM DBA_DATA_FILES GROUP BY STATUS, TABLESPACE_NAME, autoextensible) A,
(SELECT TABLESPACE_NAME, SUM(BYTES) BYTES_FREE FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NAME) B,
V\$INSTANCE I WHERE A.TABLESPACE_NAME = B.TABLESPACE_NAME(+)
union
SELECT I.instance_name,I.host_name,A.status,A.autoextensible Extent,A.TABLESPACE_NAME,ROUND(A.TOTAL_SPACE/1024/1024/1024,0) TOTAL_GB,ROUND((A.BYTES_ALLOC-NVL(B.BYTES_FREE,0))/1024/1024/1024,0) USED_GB
FROM (SELECT STATUS,TABLESPACE_NAME,SUM(BYTES) BYTES_ALLOC,SUM(DECODE(AUTOEXTENSIBLE, 'YES', MAXBYTES, BYTES)) TOTAL_SPACE,autoextensible FROM DBA_temp_FILES GROUP BY STATUS, TABLESPACE_NAME, autoextensible) A,
 (SELECT TABLESPACE_NAME, SUM(BYTES) BYTES_FREE FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NAME) B,
V\$INSTANCE I WHERE A.TABLESPACE_NAME = B.TABLESPACE_NAME(+) ORDER BY 5;
EOF

}

file_archive(){
    #备份文件整理
    filelist=$(ls -l ${BACKPATH}/*${ALTIME}*)
    if [[ -d ${BACKPATH}/${BAKDIR} ]];then
        if [[ -n ${filelist} ]];then
            mv ${BACKPATH}/*${ALTIME}* ${BACKPATH}/${BAKDIR}/
        fi
    else 
        mkdir -p ${BACKPATH}/${BAKDIR};
        if [[ -n ${filelist} ]];then
            mv ${BACKPATH}/*${ALTIME}* ${BACKPATH}/${BAKDIR}/
        fi
    fi
}

clean_file(){
    #配置备份保留次数(默认值为2,保留1份)
    REDUNDANCY=2
    rmdir_no=$(find ${BACKPATH} -maxdepth 1 -type d -name "*_${db_name}_exp"|sort|tail -n ${REDUNDANCY}|wc -l)
    if [[ ${rmdir_no} -ge ${REDUNDANCY} ]];then
        rmdir=$(find ${BACKPATH} -maxdepth 1 -type d -name "*_${db_name}_exp"|sort|tail -n ${REDUNDANCY}|head -n 1);
        if [[ -n ${rmdir} ]];then
            rm -rf ${rmdir};
        fi
    fi
}
 
main(){
    env_set
    calculate_parallelism
    database_back
    file_archive
    clean_file
}

main "$@"


最后修改时间:2025-12-30 18:37:04
文章转载自楚枫默寒,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论