Saturday, April 12, 2025

#!/bin/bash # Usage: ./list_flashback_points.sh # Input file format (single line): # hostname db_name # Check input file if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi INPUT_FILE="$1" CONN_HOST=$(awk '{print $1}' "$INPUT_FILE") CONN_DB=$(awk '{print $2}' "$INPUT_FILE") REPORT_FILE="flashback_report_$(date +%Y%m%d_%H%M).txt" # Validate input if [[ -z "$CONN_HOST" || -z "$CONN_DB" ]]; then echo "Invalid input file format. Expected:" echo "hostname db_name" exit 1 fi # Get SYS password read -s -p "Enter SYS password for ${CONN_HOST}/${CONN_DB}: " SYS_PASSWORD echo # Function to check database role get_db_role() { local host="$1" local db="$2" sqlplus -S "sys/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF SET HEADING OFF FEEDBACK OFF PAGESIZE 0 SELECT database_role FROM v\$database; EXIT; EOF } # Function to get standby databases get_standbys() { local host="$1" local db="$2" sqlplus -S "sys/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF SET HEADING OFF FEEDBACK OFF PAGESIZE 0 SELECT UPPER(destination) FROM v\$archive_dest WHERE target='STANDBY' AND status='VALID' AND destination IS NOT NULL; EXIT; EOF } # Function to get primary database get_primary() { local host="$1" local db="$2" sqlplus -S "sys/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF SET HEADING OFF FEEDBACK OFF PAGESIZE 0 SELECT UPPER(destination) FROM v\$archive_dest WHERE target='PRIMARY' AND status='VALID' AND destination IS NOT NULL; EXIT; EOF } # Function to list restore points list_restore_points() { local host="$1" local db="$2" echo -e "\n=== Restore Points for ${db} (Host: ${host}) ===" sqlplus -S "sys/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF SET LINESIZE 100 SET PAGESIZE 100 COLUMN name FORMAT A30 COLUMN time FORMAT A25 COLUMN scn FORMAT 99999999999999 SELECT name, TO_CHAR(time, 'YYYY-MM-DD HH24:MI:SS') AS time, scn, guarantee_flashback_database AS guaranteed FROM v\$restore_point ORDER BY scn; EXIT; EOF } # Main execution echo -e "\nInitializing database checks..." ROLE=$(get_db_role "$CONN_HOST" "$CONN_DB" | tr -d '\n') if [[ -z "$ROLE" ]]; then echo "Error connecting to ${CONN_HOST}/${CONN_DB}" exit 1 fi declare -a DBS_TO_CHECK=("${CONN_HOST}:${CONN_DB}") if [[ "$ROLE" == "PRIMARY" ]]; then echo "Primary database detected. Finding standbys..." STANDBYS=$(get_standbys "$CONN_HOST" "$CONN_DB") for sb in $STANDBYS; do DBS_TO_CHECK+=("${CONN_HOST}:${sb}") done elif [[ "$ROLE" == "PHYSICAL STANDBY" ]]; then echo "Standby database detected. Finding primary..." PRIMARY=$(get_primary "$CONN_HOST" "$CONN_DB") if [[ -n "$PRIMARY" ]]; then DBS_TO_CHECK+=("${CONN_HOST}:${PRIMARY}") fi fi # Generate report echo -e "\nGenerating flashback report..." { echo "Flashback Restore Point Report" echo "Generated at: $(date)" echo "======================================" for conn in "${DBS_TO_CHECK[@]}"; do IFS=':' read -r host db <<< "$conn" list_restore_points "$host" "$db" done } | tee "$REPORT_FILE" echo -e "\nReport generated: ${REPORT_FILE}" ### #!/bin/bash # Usage: ./drop_flashback_points.sh # Input file format (single line): # primary_host primary_db # Check input file if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi INPUT_FILE="$1" PRIMARY_HOST=$(awk '{print $1}' "$INPUT_FILE") PRIMARY_DB=$(awk '{print $2}' "$INPUT_FILE") DG_USER="sys" LOG_FILE="drop_restore_points_$(date +%Y%m%d_%H%M).log" # Validate input if [[ -z "$PRIMARY_HOST" || -z "$PRIMARY_DB" ]]; then echo "Invalid input file format. Expected:" echo "primary_host primary_db" exit 1 fi # Get SYS password read -s -p "Enter SYS password for ${PRIMARY_HOST}/${PRIMARY_DB}: " SYS_PASSWORD echo # Function to log messages log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" } # Verify primary database role verify_primary() { log "Verifying primary database role..." role=$(sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${PRIMARY_HOST}:1521/${PRIMARY_DB} as sysdba" << EOF SET HEADING OFF FEEDBACK OFF PAGESIZE 0 SELECT database_role FROM v\$database; EXIT; EOF ) if [[ "$role" != "PRIMARY" ]]; then log "Error: ${PRIMARY_HOST}/${PRIMARY_DB} is not a primary database (Role: ${role})" exit 1 fi log "Primary database confirmed" } # Get standby databases from broker configuration get_standbys() { log "Retrieving standby databases from broker configuration..." standby_list=$(echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\nshow configuration" | dgmgrl / | \ awk '/Physical standby database/ {print $1}') if [ -z "$standby_list" ]; then log "No standby databases found in broker configuration" exit 0 fi log "Found standby databases: ${standby_list}" echo "$standby_list" } # Stop MRP on standby stop_mrp() { local standby_db=$1 log "Stopping MRP on ${standby_db}..." echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\nedit database ${standby_db} set state='APPLY-OFF';" | dgmgrl / >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then log "Failed to stop MRP on ${standby_db}" exit 1 fi log "MRP stopped successfully on ${standby_db}" } # Start MRP on standby start_mrp() { local standby_db=$1 log "Starting MRP on ${standby_db}..." echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\nedit database ${standby_db} set state='APPLY-ON';" | dgmgrl / >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then log "Failed to start MRP on ${standby_db}" exit 1 fi log "MRP started successfully on ${standby_db}" } # Drop restore points drop_restore_points() { local host=$1 local db=$2 log "Dropping restore points on ${db}..." sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF >> "$LOG_FILE" 2>&1 SET SERVEROUTPUT ON DECLARE CURSOR c_rp IS SELECT name FROM v\$restore_point; BEGIN FOR rp IN c_rp LOOP EXECUTE IMMEDIATE 'DROP RESTORE POINT ' || rp.name; DBMS_OUTPUT.PUT_LINE('Dropped restore point: ' || rp.name); END LOOP; END; / EXIT; EOF if grep -q "ORA-" "$LOG_FILE"; then log "Error dropping restore points on ${db}" return 1 fi log "All restore points dropped successfully on ${db}" } # Main execution { verify_primary standbys=$(get_standbys) # Process standbys for standby in $standbys; do log "Processing standby database: ${standby}" stop_mrp "$standby" drop_restore_points "$PRIMARY_HOST" "$standby" start_mrp "$standby" done # Process primary log "Processing primary database: ${PRIMARY_DB}" drop_restore_points "$PRIMARY_HOST" "$PRIMARY_DB" log "Operation completed successfully" } | tee -a "$LOG_FILE" echo "Detailed log saved to: ${LOG_FILE}" ### #!/bin/bash # Usage: ./create_dg_restore_point.sh # Input file format (single line): # primary_host primary_db # Check input file if [ $# -ne 2 ]; then echo "Usage: $0 " exit 1 fi INPUT_FILE="$1" RESTORE_PREFIX="$2" PRIMARY_HOST=$(awk '{print $1}' "$INPUT_FILE") PRIMARY_DB=$(awk '{print $2}' "$INPUT_FILE") DG_USER="sys" LOG_FILE="create_restore_point_$(date +%Y%m%d_%H%M).log" RESTORE_NAME="${RESTORE_PREFIX}_$(date +%Y%m%d_%H%M%S)" # Validate input if [[ -z "$PRIMARY_HOST" || -z "$PRIMARY_DB" ]]; then echo "Invalid input file format. Expected:" echo "primary_host primary_db" exit 1 fi # Get SYS password read -s -p "Enter SYS password for ${PRIMARY_HOST}/${PRIMARY_DB}: " SYS_PASSWORD echo # Function to log messages log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" } # Verify primary database role verify_primary() { log "Verifying primary database role..." role=$(sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${PRIMARY_HOST}:1521/${PRIMARY_DB} as sysdba" << EOF SET HEADING OFF FEEDBACK OFF PAGESIZE 0 SELECT database_role FROM v\$database; EXIT; EOF ) if [[ "$role" != "PRIMARY" ]]; then log "Error: ${PRIMARY_HOST}/${PRIMARY_DB} is not a primary database (Role: ${role})" exit 1 fi log "Primary database confirmed" } # Get standby databases from broker configuration get_standbys() { log "Retrieving standby databases from broker configuration..." standby_list=$(echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\nshow configuration" | dgmgrl / | \ awk '/Physical standby database/ {print $1}') if [ -z "$standby_list" ]; then log "No standby databases found in broker configuration" exit 0 fi log "Found standby databases: ${standby_list}" echo "$standby_list" } # Stop MRP on standby stop_mrp() { local standby_db=$1 log "Stopping MRP on ${standby_db}..." echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\nedit database ${standby_db} set state='APPLY-OFF';" | dgmgrl / >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then log "Failed to stop MRP on ${standby_db}" exit 1 fi log "MRP stopped successfully on ${standby_db}" } # Start MRP on standby start_mrp() { local standby_db=$1 log "Starting MRP on ${standby_db}..." echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\nedit database ${standby_db} set state='APPLY-ON';" | dgmgrl / >> "$LOG_FILE" 2>&1 if [ $? -ne 0 ]; then log "Failed to start MRP on ${standby_db}" exit 1 fi log "MRP started successfully on ${standby_db}" } # Create guaranteed restore point create_restore_point() { local host=$1 local db=$2 log "Creating guaranteed restore point ${RESTORE_NAME} on ${db}..." sqlplus -S "${DG_USER}/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF >> "$LOG_FILE" 2>&1 CREATE RESTORE POINT ${RESTORE_NAME} GUARANTEE FLASHBACK DATABASE; EXIT; EOF if grep -q "ORA-" "$LOG_FILE"; then log "Error creating restore point on ${db}" return 1 fi log "Restore point ${RESTORE_NAME} created successfully on ${db}" } # Verify DG synchronization verify_dg_sync() { local standby_db=$1 log "Verifying Data Guard synchronization for ${standby_db}..." sync_status=$(echo -e "connect ${DG_USER}/${SYS_PASSWORD}@${PRIMARY_DB}\nshow database ${standby_db}" | dgmgrl / | \ awk '/Apply Lag/ {lag=$3" "$4} /Transport Lag/ {transport=$3" "$4} END {print "Apply Lag: "lag", Transport Lag: "transport}') log "Synchronization status for ${standby_db}: ${sync_status}" } # Main execution { log "Starting Data Guard restore point creation process" verify_primary standbys=$(get_standbys) # Process standbys for standby in $standbys; do log "Processing standby database: ${standby}" stop_mrp "$standby" create_restore_point "$PRIMARY_HOST" "$standby" start_mrp "$standby" verify_dg_sync "$standby" done # Process primary log "Processing primary database: ${PRIMARY_DB}" create_restore_point "$PRIMARY_HOST" "$PRIMARY_DB" log "Operation completed successfully" log "Restore point name: ${RESTORE_NAME}" } | tee -a "$LOG_FILE" echo "Detailed log saved to: ${LOG_FILE}"
#!/bin/bash # Usage: ./primary_standby_param_compare.sh # Input file format (single line): # primary_host primary_db # Check input file if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi INPUT_FILE="$1" PRIMARY_HOST=$(awk '{print $1}' "$INPUT_FILE") PRIMARY_DB=$(awk '{print $2}' "$INPUT_FILE") REPORT_FILE="param_diff_${PRIMARY_DB}_$(date +%Y%m%d_%H%M).log" # Validate input if [[ -z "$PRIMARY_HOST" || -z "$PRIMARY_DB" ]]; then echo "Invalid input file format. Expected:" echo "primary_host primary_db" exit 1 fi # Get SYS password read -s -p "Enter SYS password for ${PRIMARY_HOST}/${PRIMARY_DB}: " SYS_PASSWORD echo # Temporary files PRIMARY_TMP=$(mktemp) STANDBY_TMP=$(mktemp) # Function to get all parameters (including hidden) get_all_parameters() { local host="$1" local db="$2" local out_file="$3" sqlplus -S "sys/${SYS_PASSWORD}@//${host}:1521/${db} as sysdba" << EOF > "$out_file" 2>&1 SET FEEDBACK OFF HEADING OFF PAGESIZE 0 LINESIZE 1000 SELECT pi.ksppinm || '=' || cv.ksppstvl FROM x\$ksppi pi JOIN x\$ksppcv cv ON pi.indx = cv.indx UNION SELECT name || '=' || value FROM v\$parameter ORDER BY 1; EXIT EOF if grep -q "ORA-" "$out_file"; then echo "Error connecting to ${host}/${db}" return 1 fi } # Verify primary and get standbys echo -n "Checking primary database status... " ROLE=$(sqlplus -S "sys/${SYS_PASSWORD}@//${PRIMARY_HOST}:1521/${PRIMARY_DB} as sysdba" << EOF SET FEEDBACK OFF HEADING OFF PAGESIZE 0 SELECT DATABASE_ROLE FROM v\$database; EXIT; EOF ) if [[ "$ROLE" != "PRIMARY" ]]; then echo -e "\nError: ${PRIMARY_HOST}/${PRIMARY_DB} is not a primary database (Role: ${ROLE})" exit 1 fi echo "OK (Primary confirmed)" # Get standby databases echo -n "Discovering standby databases... " STANDBY_LIST=$(sqlplus -S "sys/${SYS_PASSWORD}@//${PRIMARY_HOST}:1521/${PRIMARY_DB} as sysdba" << EOF SET FEEDBACK OFF HEADING OFF PAGESIZE 0 SELECT DISTINCT UPPER(destination) FROM v\$archive_dest WHERE target='STANDBY' AND status='VALID' AND destination IS NOT NULL; EXIT; EOF ) if [ -z "$STANDBY_LIST" ]; then echo -e "\nNo standby databases found" exit 0 fi echo "Found: $(echo "$STANDBY_LIST" | wc -l)" # Get primary parameters echo -e "\nCollecting parameters from primary (${PRIMARY_DB})..." get_all_parameters "$PRIMARY_HOST" "$PRIMARY_DB" "$PRIMARY_TMP" # Compare with each standby for STANDBY in $STANDBY_LIST; do echo -e "\nProcessing standby: ${STANDBY}" # Get standby parameters get_all_parameters "$PRIMARY_HOST" "$STANDBY" "$STANDBY_TMP" # Compare and save results echo -e "\n=== Differences between ${PRIMARY_DB} (Primary) and ${STANDBY} (Standby) ===" | tee -a "$REPORT_FILE" diff --side-by-side --suppress-common-lines "$PRIMARY_TMP" "$STANDBY_TMP" | tee -a "$REPORT_FILE" # Cleanup standby temp file rm -f "$STANDBY_TMP" done # Final cleanup and report rm -f "$PRIMARY_TMP" echo -e "\nComparison complete. Report saved to: ${REPORT_FILE}"
#!/bin/bash # Usage: ./compare_db_params_hidden.sh # Input file format (two lines): # source_host source_db # target_host target_db # Check if input file is provided if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi INPUT_FILE=$1 # Read source and target details from input file SRC_HOST=$(sed -n 1p $INPUT_FILE | awk '{print $1}') SRC_DB=$(sed -n 1p $INPUT_FILE | awk '{print $2}') TGT_HOST=$(sed -n 2p $INPUT_FILE | awk '{print $1}') TGT_DB=$(sed -n 2p $INPUT_FILE | awk '{print $2}') # Validate input file content if [[ -z "$SRC_HOST" || -z "$SRC_DB" || -z "$TGT_HOST" || -z "$TGT_DB" ]]; then echo "Invalid input file format. Expected:" echo "source_host source_db" echo "target_host target_db" exit 1 fi # Temporary files for parameters SRC_TMP=$(mktemp) TGT_TMP=$(mktemp) # Function to fetch ALL parameters (including hidden) fetch_params() { local host=$1 local db=$2 local tmp_file=$3 read -s -p "Enter SYS password for $host/$db: " password echo echo "Fetching parameters (including hidden) from $host/$db..." sqlplus -S "sys/${password}@//${host}:1521/${db} as sysdba" << EOF > "$tmp_file" 2>&1 SET HEADING OFF SET PAGESIZE 0 SET FEEDBACK OFF SELECT pi.ksppinm || '=' || cv.ksppstvl FROM x\$ksppi pi JOIN x\$ksppcv cv ON pi.indx = cv.indx ORDER BY pi.ksppinm; EXIT EOF # Check for errors if grep -q "ORA-" "$tmp_file"; then echo "Failed to connect to $host/$db. Check credentials/networking." rm -f "$tmp_file" exit 1 fi } # Fetch parameters for source and target fetch_params "$SRC_HOST" "$SRC_DB" "$SRC_TMP" fetch_params "$TGT_HOST" "$TGT_DB" "$TGT_TMP" # Compare parameters (including hidden) echo "Comparing parameters (including hidden) between $SRC_DB and $TGT_DB..." diff --side-by-side --suppress-common-lines "$SRC_TMP" "$TGT_TMP" # Cleanup rm -f "$SRC_TMP" "$TGT_TMP" ## #!/bin/bash # Usage: ./rac_health_scan.sh # Input file format (single line): # scan_host db_name # Check input file if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi INPUT_FILE="$1" SCAN_HOST=$(awk '{print $1}' "$INPUT_FILE") DB_NAME=$(awk '{print $2}' "$INPUT_FILE") REPORT_FILE="rac_health_$(date +%Y%m%d_%H%M).html" # Validate input if [[ -z "$SCAN_HOST" || -z "$DB_NAME" ]]; then echo "Invalid input file format. Expected:" echo "scan_host db_name" exit 1 fi # Get SYS password read -s -p "Enter SYS password for ${SCAN_HOST}/${DB_NAME}: " SYS_PASSWORD echo # HTML Header cat > "$REPORT_FILE" << EOF RAC Health Check: ${DB_NAME}

Oracle RAC Health Report: ${DB_NAME}

Generated at: $(date)

SCAN Name: ${SCAN_HOST}

EOF # Function to run SQL and format as HTML table run_sql_to_html() { local title="$1" local query="$2" local critical="$3" echo "

${title}

" >> "$REPORT_FILE" sqlplus -S "sys/${SYS_PASSWORD}@//${SCAN_HOST}:1521/${DB_NAME} as sysdba" << EOF | awk ' BEGIN { print ""; print "" } /^ERROR/ { print "" } /=/ { split($0, arr, "="); cls = ""; if (arr[2] ~ /CRITICAL/) cls = "critical"; if (arr[2] ~ /WARNING/) cls = "warning"; print "" } END { print "
MetricValue
" $0 "
" arr[1] "" arr[2] "
" } ' >> "$REPORT_FILE" SET FEEDBACK OFF HEADING OFF PAGESIZE 0 LINESIZE 1000 ${query} EXIT EOF } # RAC Node Status run_sql_to_html "Cluster Node Status" " SELECT 'Node ' || instance_number || ': ' || instance_name || ' (' || host_name || ')' || '=' || status || ' | Version: ' || version || ' | Startup: ' || TO_CHAR(startup_time, 'YYYY-MM-DD HH24:MI') FROM gv\$instance; " # Wait Events Analysis run_sql_to_html "Top Wait Events (Non-Idle)" " SELECT event || '=' || ROUND(time_waited_micro/1000000,1) || 's (Waits: ' || total_waits || ', Avg: ' || ROUND(time_waited_micro/total_waits/1000,2) || 'ms)' FROM ( SELECT event, total_waits, time_waited_micro FROM gv\$system_event WHERE wait_class NOT IN ('Idle', 'System I/O') ORDER BY time_waited_micro DESC FETCH FIRST 10 ROWS ONLY ); " # Global Cache Statistics run_sql_to_html "Global Cache Performance" " SELECT 'Global Cache CR Block Receive Time (ms)' || '=' || ROUND((SUM(CASE name WHEN 'gc cr block receive time' THEN value END) / SUM(CASE name WHEN 'gc cr blocks received' THEN value END)) * 10,2) || 'ms [CR] | ' || ROUND((SUM(CASE name WHEN 'gc current block receive time' THEN value END) / SUM(CASE name WHEN 'gc current blocks received' THEN value END)) * 10,2) || 'ms [Current]' FROM gv\$sysstat WHERE name IN ( 'gc cr block receive time', 'gc cr blocks received', 'gc current block receive time', 'gc current blocks received' ); " # Tablespace Usage run_sql_to_html "Tablespace Usage" " SELECT tablespace_name || '=' || ROUND(used_percent,1) || '% used | ' || CASE WHEN used_percent > 90 THEN 'CRITICAL' WHEN used_percent > 80 THEN 'WARNING' ELSE 'OK' END FROM ( SELECT a.tablespace_name, (a.bytes_alloc - nvl(b.bytes_free,0))/a.bytes_alloc*100 used_percent FROM ( SELECT tablespace_name, SUM(bytes) bytes_alloc FROM dba_data_files GROUP BY tablespace_name ) a, ( SELECT tablespace_name, SUM(bytes) bytes_free FROM dba_free_space GROUP BY tablespace_name ) b WHERE a.tablespace_name = b.tablespace_name(+) ) ORDER BY used_percent DESC; " # Cluster Interconnect run_sql_to_html "Interconnect Health" " SELECT 'Network Latency (' || name || ')' || '=' || ROUND(value/100,2) || 'ms' || CASE WHEN value/100 > 2 THEN ' CRITICAL' WHEN value/100 > 1 THEN ' WARNING' ELSE '' END FROM gv\$sysmetric WHERE metric_name = 'Network Latency' AND group_id = 2 AND value > 0; " # HTML Footer cat >> "$REPORT_FILE" << EOF EOF echo -e "\nReport generated: ${REPORT_FILE}"

Saturday, March 15, 2025

1) drop #!/bin/bash # Oracle Schema Migration Script # Description: Exports a schema from Source DB (A) and imports into Target DB (B) # Pre-requisites: # - Oracle Data Pump directories must be configured on both databases # - User must have necessary privileges (EXP_FULL_DATABASE, IMP_FULL_DATABASE) # - Target schema user must exist in Database B # Configuration SOURCE_DB="SOURCE_USER/SOURCE_PASSWORD@DATABASE_A" TARGET_DB="TARGET_USER/TARGET_PASSWORD@DATABASE_B" SCHEMA_NAME="YOUR_SCHEMA_NAME" DATA_PUMP_DIR="DATA_PUMP_DIR_NAME" # Oracle directory object name DUMPFILE="${SCHEMA_NAME}_export.dmp" LOGFILE_EXPORT="${SCHEMA_NAME}_export.log" LOGFILE_IMPORT="${SCHEMA_NAME}_import.log" # Function to drop all objects in target schema drop_target_objects() { echo "Dropping all objects in target schema: ${SCHEMA_NAME}" sqlplus -S /nolog <" > $REPORT_FILE echo "Schema Comparison Report" >> $REPORT_FILE echo "" >> $REPORT_FILE echo "

Schema Comparison Report

" >> $REPORT_FILE # Step 3: Compare missing objects (tables, views, indexes, sequences, procedures) echo "

Missing Objects

" >> $REPORT_FILE echo "" >> $REPORT_FILE sqlplus -s $ORACLE_USER/$ORACLE_PASSWORD@$TARGET_DB_B < temp_missing_objects.txt SET PAGESIZE 500 SET LINESIZE 200 SET HEADING OFF SELECT 'Table', table_name FROM all_tables@${DBLINK_NAME} WHERE table_name NOT IN (SELECT table_name FROM all_tables WHERE owner = UPPER('$SCHEMA_NAME')); SELECT 'View', view_name FROM all_views@${DBLINK_NAME} WHERE view_name NOT IN (SELECT view_name FROM all_views WHERE owner = UPPER('$SCHEMA_NAME')); SELECT 'Index', index_name FROM all_indexes@${DBLINK_NAME} WHERE index_name NOT IN (SELECT index_name FROM all_indexes WHERE owner = UPPER('$SCHEMA_NAME')); SELECT 'Sequence', sequence_name FROM all_sequences@${DBLINK_NAME} WHERE sequence_name NOT IN (SELECT sequence_name FROM all_sequences WHERE owner = UPPER('$SCHEMA_NAME')); SELECT 'Procedure', object_name FROM all_procedures@${DBLINK_NAME} WHERE object_name NOT IN (SELECT object_name FROM all_procedures WHERE owner = UPPER('$SCHEMA_NAME')); EXIT; EOF while read line; do object_type=$(echo $line | awk '{print $1}') object_name=$(echo $line | awk '{$1=""; print $0}' | sed 's/^ *//g') if [ ! -z "$object_name" ]; then echo "" >> $REPORT_FILE fi done < temp_missing_objects.txt echo "
Object TypeObject Name
$object_type$object_name
" >> $REPORT_FILE rm temp_missing_objects.txt # Step 4: Compare row counts for all tables echo "

Row Count Differences

" >> $REPORT_FILE echo "" >> $REPORT_FILE sqlplus -s $ORACLE_USER/$ORACLE_PASSWORD@$TARGET_DB_B < temp_row_counts.txt SET PAGESIZE 500 SET LINESIZE 200 SET HEADING OFF SELECT table_name, (SELECT COUNT(*) FROM ${SCHEMA_NAME}."||table_name||"@$DBLINK_NAME) AS SRC_COUNT, (SELECT COUNT(*) FROM ${SCHEMA_NAME}."||table_name||") AS TGT_COUNT FROM all_tables WHERE owner = UPPER('$SCHEMA_NAME'); EXIT; EOF while read line; do table_name=$(echo $line | awk '{print $1}') src_count=$(echo $line | awk '{print $2}') tgt_count=$(echo $line | awk '{print $3}') if [ "$src_count" == "$tgt_count" ]; then status="MATCH" else status="MISMATCH" fi echo "" >> $REPORT_FILE done < temp_row_counts.txt echo "
Table NameSource CountTarget CountStatus
$table_name$src_count$tgt_count$status
" >> $REPORT_FILE rm temp_row_counts.txt # Step 5: Finish HTML Report echo "" >> $REPORT_FILE echo "Comparison report saved in: $REPORT_FILE" # Step 6: Display report in terminal cat $REPORT_FILE ############# ################## redo log ################## #!/bin/bash # Define Variables STANDBY_LIST_FILE="database_list.txt" # User-provided file containing one SCAN host and DB service ORA_USER="oracle" ORA_PASS="your_password" # Replace with secure password management method DGB_ADMIN_USER="sys" DGB_ADMIN_PASS="your_password" # Replace with actual password SLEEP_INTERVAL=10 # Time in seconds to wait before retrying MAX_RETRIES=3 # Maximum number of retries for log drops export ORACLE_SID="orcl" # Check if the input file exists if [[ ! -f "$STANDBY_LIST_FILE" ]]; then echo "Error: Standby list file ($STANDBY_LIST_FILE) not found!" exit 1 fi # Read primary SCAN and DB service from file read -r INPUT_SCAN INPUT_DB < "$STANDBY_LIST_FILE" echo "User-Provided SCAN: $INPUT_SCAN" echo "User-Provided DB Service: $INPUT_DB" # Prompt user for new redo log file size read -p "Enter the new redo log file size in MB: " NEW_LOG_SIZE_MB echo "### Step 1: Identify Primary & All Standby Databases Using Data Guard Broker ###" DGMGRL_OUTPUT=$(dgmgrl sys/$DGB_ADMIN_PASS@$INPUT_SCAN <

Wednesday, February 5, 2025

Oracle RAC Build/Installation Prerequisites & Planning What prerequisites (OS packages, kernel parameters, network setup) are critical for an Oracle RAC installation? How do you configure shared storage (ASM, NFS, etc.) for RAC? What tools (e.g., asmca, crsctl) would you use? Installation Process Walk me through the steps to install Oracle RAC using Oracle Universal Installer (OUI). What role does the Grid Infrastructure (GI) play in a RAC environment? How does it differ from a standalone installation? Network Configuration Explain the purpose of SCAN (Single Client Access Name) listeners. How do they differ from regular listeners? How would you troubleshoot interconnect communication issues between RAC nodes? Post-Installation Checks What commands (e.g., crsctl, srvctl) would you use to verify the health of the cluster? How do you validate that all RAC nodes are functioning correctly and can access shared storage? ASM Integration How do you configure ASM disk groups for RAC? What redundancy levels (normal, high, external) are appropriate for different scenarios? What is the role of voting disks and OCR (Oracle Cluster Registry) in RAC? How would you back them up? Oracle RAC Patching & Upgrades Patch Types What is the difference between a PSU (Patch Set Update), CPU (Critical Patch Update), and a one-off patch? When would you use an OPatch auto rollback versus manual rollback? Rolling vs. Non-Rolling Patches Explain the process for applying a rolling patch to Oracle RAC. What components can be patched without downtime? How do you handle a non-rolling patch (e.g., Grid Infrastructure upgrade) in a RAC environment? Patching Workflow Walk through the steps to patch a RAC environment using OPatch. What pre-checks are mandatory? How do you verify that all nodes are running the same patch level post-update? Troubleshooting Patching Failures What logs would you check if a RAC patch fails during application (e.g., GI patching errors)? How do you resolve OPatch conflicts or missing dependencies during patching? Upgrade Strategies How would you plan a RAC database upgrade from 12c to 19c with minimal downtime? What are the risks of using DBUA (Database Upgrade Assistant) versus manual upgrades in a RAC environment? Troubleshooting RAC-Specific Issues Node Eviction & Split Brain What causes node evictions in RAC? How would you diagnose and resolve this? What is a "split-brain" scenario, and how does RAC prevent it? Performance in RAC How does "Global Cache Block Transfer" impact RAC performance? What wait events (e.g., gc cr block busy) would you monitor? What tools (AWR, ADDM) or views (GV$SESSION, GV$LOCK) do you use to diagnose RAC-specific performance issues? Clusterware Issues How do you troubleshoot OCR or voting disk corruption in RAC? What steps would you take if crsctl start crs fails on a RAC node? Situational/Scenario-Based Questions Disaster Recovery A RAC node crashes due to storage failure. How do you restore the cluster to full health? How would you rebuild a lost OCR file or voting disk in a live RAC environment? Scaling & Maintenance How do you add a new node to an existing RAC cluster? What steps are involved? Describe a time you performed a rolling maintenance task (e.g., OS patching) on a RAC cluster. High Availability How do you configure services in RAC to ensure workload balancing and failover? What is the role of FAN (Fast Application Notification) in RAC, and how does it integrate with applications? Advanced Topics RAC on Cloud/Exadata What unique considerations apply when deploying RAC on Oracle Exadata or OCI (Oracle Cloud Infrastructure)? How does RAC differ from Oracle Autonomous Database in terms of scalability and management? Security How do you enforce TDE (Transparent Data Encryption) in a RAC environment? What security best practices apply to RAC interconnect traffic? Automation How have you automated RAC provisioning or patching using tools like Ansible, Terraform, or OEM?

Sunday, February 2, 2025

@echo off setlocal enabledelayedexpansion set "urls_file=urls.txt" set "username=your_username" set "password=your_password" set "edge_path=%ProgramFiles(x86)%\Microsoft\Edge\Application\msedge.exe" :: Loop through each URL for /f "usebackq delims=" %%u in ("%urls_file%") do ( set "url=%%u" :: Launch Edge with URL start "" "%edge_path%" --new-window "!url!" :: Wait for page to load (adjust delay as needed) timeout /t 7 >nul :: Send credentials using PowerShell powershell -command "$wshell = New-Object -ComObject wscript.shell; $wshell.AppActivate('Microsoft Edge'); Start-Sleep -Milliseconds 800; $wshell.SendKeys('{TAB}'); $wshell.SendKeys('%username%'); $wshell.SendKeys('{TAB}'); $wshell.SendKeys('%password%'); $wshell.SendKeys('~')" :: Wait for login to process timeout /t 5 >nul :: Close Edge window (Alt+F4) powershell -command "$wshell = New-Object -ComObject wscript.shell; $wshell.AppActivate('Microsoft Edge'); $wshell.SendKeys('%%{F4}')" :: Add delay before next URL timeout /t 2 >nul ) ## #!/bin/bash # Database Connection Parameters DB_USER="sysman" DB_PASS="your_password" DB_HOST="rac-host.example.com" DB_SERVICE="your_service" SYSDBA="as sysdba" # Email Parameters EMAIL_TO="dba@example.com" EMAIL_SUBJECT="Oracle RAC Health Check Report" # Output File OUTPUT_FILE="/tmp/rac_health_report.html" # Function to run SQL query and format HTML run_query() { sqlplus -s /nolog << EOF | awk 'BEGIN{print ""} {print ""} END{print "
" $0 "
"}' | sed 's/|/\<\/td\>\/g' connect $DB_USER/$DB_PASS@$DB_HOST/$DB_SERVICE $SYSDBA set pagesize 50000 set linesize 1000 set heading off set feedback off $1 exit EOF } # Start HTML Report cat > $OUTPUT_FILE << EOF Oracle RAC Health Check Report

Oracle RAC Health Check Report

Generated: $(date)

EOF # 1. All Instance/DB Status echo "

1. Database/Instance Status

" >> $OUTPUT_FILE run_query "SELECT INST_ID, INSTANCE_NAME, HOST_NAME, STATUS, DATABASE_STATUS FROM GV\$INSTANCE;" >> $OUTPUT_FILE # 2. Long Running Sessions echo "

2. Long Running Sessions (> 1 hour)

" >> $OUTPUT_FILE run_query "SELECT INST_ID, SID, SERIAL#, USERNAME, SQL_ID, ROUND((SYSDATE - SQL_EXEC_START)*24,2) HOURS, STATUS FROM GV\$SESSION WHERE (SYSDATE - SQL_EXEC_START)*24 > 1;" >> $OUTPUT_FILE # 3. DB Blocking echo "

3. Database Blocking Sessions

" >> $OUTPUT_FILE run_query "SELECT blocker.INST_ID, blocker.SID, blocker_user.username blocker_user, waiter.INST_ID, waiter.SID, waiter_user.username waiter_user FROM GV\$LOCK blocker JOIN GV\$LOCK waiter ON (blocker.ID1 = waiter.ID1 AND blocker.ID2 = waiter.ID2) JOIN GV\$SESSION blocker_user ON (blocker.SID = blocker_user.SID) JOIN GV\$SESSION waiter_user ON (waiter.SID = waiter_user.SID) WHERE blocker.BLOCK > 0 AND waiter.REQUEST > 0;" >> $OUTPUT_FILE # 4. DB Locking echo "

4. Database Locking

" >> $OUTPUT_FILE run_query "SELECT INST_ID, SID, TYPE, LMODE, REQUEST, CTIME FROM GV\$LOCK WHERE TYPE NOT IN ('MR','AE');" >> $OUTPUT_FILE # 5. DB Load Last 1 Hour echo "

5. Database Load (Last 1 Hour)

" >> $OUTPUT_FILE run_query "SELECT BEGIN_TIME, END_TIME, AVG(CPU) CPU_AVG, AVG(IO) IO_AVG FROM GV\$SYSMETRIC_HISTORY WHERE GROUP_ID = 2 AND INTSIZE_CSEC < (60 * 100 * 60) GROUP BY BEGIN_TIME, END_TIME ORDER BY BEGIN_TIME DESC FETCH FIRST 12 ROWS ONLY;" >> $OUTPUT_FILE # 6. DB Load Last 5 Minutes echo "

6. Database Load (Last 5 Minutes)

" >> $OUTPUT_FILE run_query "SELECT BEGIN_TIME, END_TIME, CPU, IO FROM GV\$SYSMETRIC WHERE GROUP_ID = 2 ORDER BY BEGIN_TIME DESC FETCH FIRST 1 ROW ONLY;" >> $OUTPUT_FILE # 7. DB Parallel echo "

7. Database Parallel Processes

" >> $OUTPUT_FILE run_query "SELECT INST_ID, COUNT(*) PARALLEL_PROCS FROM GV\$PX_PROCESS GROUP BY INST_ID;" >> $OUTPUT_FILE # 8. Invalid Objects echo "

8. Invalid Objects

" >> $OUTPUT_FILE run_query "SELECT OWNER, OBJECT_TYPE, COUNT(*) FROM DBA_OBJECTS WHERE STATUS != 'VALID' GROUP BY OWNER, OBJECT_TYPE;" >> $OUTPUT_FILE # 9. Session Failure echo "

9. Session Failures

" >> $OUTPUT_FILE run_query "SELECT INST_ID, COUNT(*) FROM GV\$SESSION WHERE FAILOVER_TYPE IS NOT NULL AND FAILED_OVER = 'YES' GROUP BY INST_ID;" >> $OUTPUT_FILE # 10. Active Session Count echo "

10. Active Session Count

" >> $OUTPUT_FILE run_query "SELECT INST_ID, COUNT(*) ACTIVE_SESSIONS FROM GV\$SESSION WHERE STATUS = 'ACTIVE' GROUP BY INST_ID;" >> $OUTPUT_FILE # 11. All Database Service Info echo "

11. Database Services

" >> $OUTPUT_FILE run_query "SELECT INST_ID, NAME, NETWORK_NAME, CREATED, GOAL, ENABLED FROM GV\$SERVICES;" >> $OUTPUT_FILE # 12. All ORA-Errors echo "

12. Recent ORA-Errors

" >> $OUTPUT_FILE run_query "SELECT ORIGINATING_TIMESTAMP, MESSAGE_TEXT FROM GV\$DIAG_ALERT_EXT WHERE MESSAGE_TEXT LIKE 'ORA-%' AND ORIGINATING_TIMESTAMP > SYSDATE - 1/24;" >> $OUTPUT_FILE # Close HTML echo "" >> $OUTPUT_FILE # Send Email mailx -a "$OUTPUT_FILE" -s "$EMAIL_SUBJECT" -S content-type=text/html "$EMAIL_TO" < /dev/null # Cleanup rm -f $OUTPUT_FILE

Saturday, February 1, 2025

#!/bin/bash # Configuration ORACLE_USER="remote_user" ORACLE_PASS="password" RAC_NODE="rac_node1" EMAIL_RECIPIENT="admin@example.com" REPORT_FILE="/tmp/oracle_health_report.html" # Create HTML Report Header cat << EOF > $REPORT_FILE Oracle RAC Health Check Report

Oracle RAC Health Check Report

Generated on: $(date)

EOF # Run Database Checks sqlplus -s /nolog << EOF >> $REPORT_FILE connect $ORACLE_USER/$ORACLE_PASS@$RAC_NODE set markup html on pre off entmap off set pagesize 500 linesize 200 set feedback off heading on prompt

Recent ORA Errors (Last 5 Minutes)

SELECT INST_ID, TO_CHAR(ORIGINATING_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') AS TIMESTAMP, MESSAGE_TEXT FROM GV\$DIAG_ALERT_EXT WHERE MESSAGE_TEXT LIKE 'ORA-%' AND ORIGINATING_TIMESTAMP >= SYSDATE - 5/1440 ORDER BY ORIGINATING_TIMESTAMP DESC; prompt

Top Waiting Events (Last 5 Minutes)

SELECT INST_ID, EVENT, COUNT(*) AS WAIT_COUNT, ROUND(COUNT(*)*100/SUM(COUNT(*)) OVER(), 2) AS PCT FROM GV\$ACTIVE_SESSION_HISTORY WHERE SAMPLE_TIME >= SYSDATE - 5/1440 AND EVENT IS NOT NULL GROUP BY INST_ID, EVENT ORDER BY WAIT_COUNT DESC; exit EOF # Add HTML Footer cat << EOF >> $REPORT_FILE EOF # Send Email with HTML Report mailx -s "$(echo -e "Oracle RAC Health Check Report\nContent-Type: text/html")" \ $EMAIL_RECIPIENT < $REPORT_FILE # Cleanup rm -f $REPORT_FILE #### #!/bin/bash set -eo pipefail trap 'echo "Error at line $LINENO"; exit 1' ERR # Configuration REMOTE_USER="oracleuser" REMOTE_HOSTS=("rac-node1" "rac-node2") # Multiple RAC nodes ORACLE_SID="ORCLCDB" ORACLE_HOME="/u01/app/oracle/product/19.0.0/dbhome_1" EMAIL_RECIPIENT="dba@example.com" EMAIL_SUBJECT="Oracle RAC Health Check Report - $(date +%Y%m%d)" REPORT_FILE="/tmp/rac_health_report.html" LOG_FILE="/tmp/rac_health_check.log" AWK_SCRIPT="/tmp/rac_stats.awk" declare -A THRESHOLDS=( [TABLESPACE]=90 [WAIT_TIME]=1000 [CPU_PER_SESSION]=75 [ASM_FREE]=10 ) # Initialize files : > "$REPORT_FILE" : > "$LOG_FILE" # Create HTML template cat >> "$REPORT_FILE" << EOF Oracle RAC Health Check Report

Oracle RAC Health Check Report

Generated on: $(date "+%Y-%m-%d %H:%M:%S")

EOF # Function to run remote SQL run_remote_sql() { local host=$1 local sql=$2 ssh -q "$REMOTE_USER@$host" " export ORACLE_SID=$ORACLE_SID export ORACLE_HOME=$ORACLE_HOME \$ORACLE_HOME/bin/sqlplus -S / as sysdba << SQLEND SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF $sql SQLEND" } # Cluster Health Check echo "

► Cluster Health

" >> "$REPORT_FILE" echo "" >> "$REPORT_FILE" # AWR/ASH Report Generation echo "

► AWR/ASH Reports

" >> "$REPORT_FILE" echo "" >> "$REPORT_FILE" # Historical Trend Analysis echo "

► Historical Trends

" >> "$REPORT_FILE" echo "" >> "$REPORT_FILE" # Backup Status Check echo "

► Backup Status

" >> "$REPORT_FILE" echo "" >> "$REPORT_FILE" # JavaScript for collapsible sections cat >> "$REPORT_FILE" << EOF EOF # Send email with mailx ( echo "From: Oracle Health Check " echo "To: $EMAIL_RECIPIENT" echo "Subject: $EMAIL_SUBJECT" echo "MIME-Version: 1.0" echo "Content-Type: text/html" echo cat "$REPORT_FILE" ) | mailx -s "$EMAIL_SUBJECT" -a "$REPORT_FILE" "$EMAIL_RECIPIENT" # Cleanup rm -f "$REPORT_FILE" "$LOG_FILE" #!/bin/bash # Configuration (Modify these parameters) DB_USER="your_db_user" DB_PASS="your_db_password" DB_HOST="your_db_host" DB_SERVICE="your_db_service" EMAIL_TO="your_email@example.com" EMAIL_SUBJECT="Oracle RAC Health Check Report" HTML_REPORT="/tmp/oracle_rac_health_check.html" # Start HTML Output echo "Oracle RAC Health Check" > $HTML_REPORT echo "

Oracle RAC Database Health Check Report

" >> $HTML_REPORT echo "
" >> $HTML_REPORT # Function to run SQL and format output as HTML run_sql() { local title=$1 local sql_query=$2 echo "

$title

" >> $HTML_REPORT echo "
" >> $HTML_REPORT

    sqlplus -s "$DB_USER/$DB_PASS@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=$DB_HOST)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=$DB_SERVICE)))" <> $HTML_REPORT
SET LINESIZE 200
SET PAGESIZE 100
SET TRIMSPOOL ON
SET HEADING OFF
$sql_query
EXIT;
EOF
    echo "

" >> $HTML_REPORT } # 1) All Instance / DB Status run_sql "RAC Instance and Database Status" "SELECT inst_id, instance_name, status, database_status FROM GV\$INSTANCE;" # 2) Long Running Sessions (active > 1 hour) run_sql "Long Running Sessions (per instance)" " SELECT inst_id, sid, serial#, username, status, sql_id, last_call_et FROM GV\$SESSION WHERE status='ACTIVE' AND last_call_et > 3600 ORDER BY last_call_et DESC;" # 3) DB Blocking run_sql "Blocking Sessions Across Instances" " SELECT inst_id, blocking_session, sid, serial#, wait_class, seconds_in_wait FROM GV\$SESSION WHERE blocking_session IS NOT NULL;" # 4) DB Locking run_sql "Database Locks" " SELECT inst_id, sid, type, id1, id2, lmode, request, block FROM GV\$LOCK WHERE block != 0;" # 5) DB Load Last 1 Hour run_sql "Database Load Last 1 Hour" " SELECT inst_id, TO_CHAR(begin_time, 'YYYY-MM-DD HH24:MI:SS'), average_active_sessions FROM GV\$SYSMETRIC_HISTORY WHERE metric_name = 'Average Active Sessions' AND group_id = 2 ORDER BY begin_time DESC FETCH FIRST 12 ROWS ONLY;" # 6) DB Load Last 5 Minutes run_sql "Database Load Last 5 Minutes" " SELECT inst_id, TO_CHAR(begin_time, 'YYYY-MM-DD HH24:MI:SS'), average_active_sessions FROM GV\$SYSMETRIC_HISTORY WHERE metric_name = 'Average Active Sessions' AND group_id = 2 ORDER BY begin_time DESC FETCH FIRST 1 ROW ONLY;" # 7) DB Parallel Processing run_sql "Parallel Execution Processes" " SELECT inst_id, degree, req_degree, dop, requested_dop FROM GV\$PX_PROCESS;" # 8) Invalid Objects run_sql "Invalid Objects Across All Nodes" " SELECT inst_id, owner, object_name, object_type FROM GV\$DBA_OBJECTS WHERE status <> 'VALID';" # 9) Session Failures run_sql "Failed User Sessions" " SELECT inst_id, username, machine, terminal, logon_time FROM GV\$AUDIT_SESSION WHERE returncode != 0;" # 10) Active Session Count run_sql "Active Sessions Count per Instance" " SELECT inst_id, COUNT(*) AS active_sessions FROM GV\$SESSION WHERE status = 'ACTIVE' GROUP BY inst_id;" # 11) Database Service Info run_sql "Database Services Across All Instances" " SELECT inst_id, name, pdb FROM GV\$ACTIVE_SERVICES;" # 12) ORA-ERRORs in Alert Logs (Last 24 Hours) run_sql "Recent ORA-Errors in Alert Logs" " SELECT inst_id, originating_timestamp, message_text FROM GV\$DIAG_ALERT_EXT WHERE message_text LIKE 'ORA-%' AND originating_timestamp > SYSDATE - 1 ORDER BY originating_timestamp DESC;" # Close HTML Output echo "" >> $HTML_REPORT # Send Email with the HTML report mailx -a "$HTML_REPORT" -s "$EMAIL_SUBJECT" "$EMAIL_TO" < $HTML_REPORT echo "RAC Health Check Report Sent to $EMAIL_TO" ### #!/bin/bash set -eo pipefail # Configuration DB_USER="sys as sysdba" DB_PASSWORD="your_password" DB_HOST="rac-scan.example.com" DB_PORT=1521 SERVICE_NAME="ORCLCDB" EMAIL_TO="dba@example.com" REPORT_FILE="/tmp/rac_health_report.html" # Oracle Connection String CONN_STR="${DB_USER}/${DB_PASSWORD}@//${DB_HOST}:${DB_PORT}/${SERVICE_NAME}" # HTML Header cat > $REPORT_FILE < Oracle RAC Health Report

Oracle RAC Health & Performance Report

Generated: $(date "+%Y-%m-%d %H:%M:%S")

EOF # Function to run SQL and format output run_sql() { local sql=$1 local title=$2 local critical=$3 echo "

$title

" >> $REPORT_FILE output=$(sqlplus -S -L "${CONN_STR}" <No issues found

" >> $REPORT_FILE else echo "" >> $REPORT_FILE while IFS= read -r line; do echo "" >> $REPORT_FILE done <<< "$output" echo "
$line
" >> $REPORT_FILE fi } # 1. Instance/DB Status run_sql " SELECT 'Instance ' || instance_name || ' - ' || status || ' | Version: ' || version || ' | Uptime: ' || ROUND((SYSDATE - startup_time)*24) || ' hours' FROM gv\$instance;" "Cluster Instance Status" # 2. Long Running Sessions (>30 minutes) run_sql " SELECT 'SID: ' || sid || ', Inst: ' || inst_id || ', User: ' || username || ', SQL_ID: ' || sql_id || ', Elapsed: ' || ROUND((SYSDATE - logon_time)*1440) || ' mins' FROM gv\$session WHERE status = 'ACTIVE' AND (SYSDATE - logon_time)*1440 > 30;" "Long Running Sessions" "warning" # 3. DB Blocking/Locking run_sql " SELECT 'Blocker: ' || b.inst_id || ':' || b.sid || ' | Waiter: ' || w.inst_id || ':' || w.sid || ' | Object: ' || o.object_name || ' | Wait: ' || ROUND((SYSDATE - w.logon_time)*1440) || ' mins' FROM gv\$lock b, gv\$lock w, dba_objects o WHERE b.block = 1 AND w.request > 0 AND b.id1 = w.id1 AND b.id2 = w.id2 AND o.object_id = b.id1;" "Blocking Sessions" "critical" # 4. DB Load Analysis run_sql " SELECT 'Last Hour: CPU ' || ROUND(AVG(cpu_percent)) || '%' || ' | Active: ' || AVG(active_sessions) || ' | Parallel: ' || AVG(parallel_servers) || ' | Last 5m: ' || ROUND(5min_cpu) || '%' FROM ( SELECT h.metric_value cpu_percent, (SELECT COUNT(*) FROM gv\$session WHERE status = 'ACTIVE') active_sessions, (SELECT SUM(servers_in_use) FROM gv\$px_process_sysstat) parallel_servers, LEAD(h.metric_value, 12) OVER (ORDER BY h.begin_time) 5min_cpu FROM gv\$sysmetric_history h WHERE h.metric_name = 'CPU Usage Per Sec' AND h.begin_time > SYSDATE - 1/24 );" "Load Analysis" # 5. Parallel Processes run_sql " SELECT 'Inst ' || inst_id || ' | Used: ' || servers_in_use || ' | Available: ' || servers_available || ' | Status: ' || status FROM gv\$px_process_sysstat;" "Parallel Execution Status" # 6. Invalid Objects run_sql " SELECT owner || '.' || object_name || ' (' || object_type || ')' FROM dba_objects WHERE status != 'VALID' AND owner NOT IN ('SYS','SYSTEM');" "Invalid Objects" "warning" # 7. Session Failures run_sql " SELECT 'Inst ' || inst_id || ' | User: ' || username || ' | Count: ' || COUNT(*) || ' | Last: ' || MAX(timestamp) FROM gv\$session WHERE status = 'FAILED' GROUP BY inst_id, username;" "Session Failures" "critical" # 8. Active Session Count run_sql " SELECT 'Inst ' || inst_id || ' | Active: ' || COUNT(*) || ' | CPU: ' || SUM(CASE WHEN state = 'ON CPU' THEN 1 ELSE 0 END) FROM gv\$session WHERE status = 'ACTIVE' GROUP BY inst_id;" "Active Sessions" # 9. Database Services run_sql " SELECT name || ' | ' || status || ' | Node: ' || node || ' | Created: ' || TO_CHAR(creation_date, 'YYYY-MM-DD HH24:MI') FROM gv\$services;" "Database Services" # 10. ORA-Errors run_sql " SELECT 'Inst ' || inst_id || ' | ' || TO_CHAR(timestamp, 'YYYY-MM-DD HH24:MI') || ' | ' || REGEXP_SUBSTR(message_text, 'ORA-[0-9]+:.*') FROM gv\$diag_alert_ext WHERE message_type = 'ERROR' AND timestamp > SYSDATE - 1;" "Recent ORA Errors" "critical" # Complete HTML cat >> $REPORT_FILE < EOF # Send Email ( echo "From: Oracle Monitor " echo "To: $EMAIL_TO" echo "Subject: Oracle RAC Health Report" echo "MIME-Version: 1.0" echo "Content-Type: text/html" echo cat $REPORT_FILE ) | sendmail -t # Cleanup rm -f $REPORT_FILE