Monday, January 5, 2015

Points to remember in Couchbase

#!/bin/bash
#GEM
# TNS related
# Configuration
RETRY_COUNT=3
RETRY_GAP=120 # in seconds (2 minutes)
LOG_FILE="/var/log/git_push.log"
MAX_LOG_SIZE=$((500 * 1024 * 1024)) # 500MB
CONFLUENCE_LINK="https://somelink"
TNS_FILE="/store/dpd-tns/tnsnames.ora" #added TNS file definition
VALIDATION_LOG_FILE="/var/log/tns_validation.log" # added tns validation log file

# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
}
# Function to log messages related to TNS validation
tns_log_message() {
local level="$1"
local message="$2"
echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $message" >> "$VALIDATION_LOG_FILE"
echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $message"
}

# Function to check log file size and delete if it exceeds MAX_LOG_SIZE
check_log_size() {
if [ -f "$LOG_FILE" ] && [ $(stat -c%s "$LOG_FILE") -ge $MAX_LOG_SIZE ]; then
rm "$LOG_FILE"
log_message "Log file exceed max size. New one created."
fi
if [ -f "$VALIDATION_LOG_FILE" ] && [ $(stat -c%s "$VALIDATION_LOG_FILE") -ge $MAX_LOG_SIZE ]; then
rm "$VALIDATION_LOG_FILE"
tns_log_message "INFO" "TNS Validation Log file exceed max size. New one created."
fi
}

# Function to send alert to DBAs
send_alert() {
local error_message="$1"
cd /store/scripts/SNOW-Ticketing || { log_message "Failed to navigate to /store/scripts/SNOW-Ticketing"; return 1; }
/store/scripts/SNOW-Ticketing/snow-ticketing-sh -s "tnsnames.ora update failure" -c "$error_message. Please refer to the Confluence page: $CONFLUENCE_LINK" -u "2" -i "2"
local snow_ret=$?
if [ $snow_ret -ne 0 ]; then
log_message "Error sending alert to SNOW. return code: $snow_ret"
else
log_message "Alert sent to SNOW successfully."
fi
return $snow_ret
}

# ---- TNS Validation functions -----
check_file_exists() {
if [ ! -f "$TNS_FILE" ]; then
tns_log_message "ERROR" "TNS file not found: $TNS_FILE"
return 1
fi
tns_log_message "INFO" "TNS file found: $TNS_FILE"
return 0
}

check_file_permissions() {
if [ ! -r "$TNS_FILE" ]; then
tns_log_message "ERROR" "TNS file is not readable: $TNS_FILE"
return 1
fi
tns_log_message "INFO" "TNS file is readable."
return 0
}

check_file_not_empty() {
if [ ! -s "$TNS_FILE" ]; then
tns_log_message "ERROR" "TNS file is empty: $TNS_FILE"
return 1
fi
tns_log_message "INFO" "TNS file is not empty."
return 0
}

# Basic syntax check (very rudimentary, but can catch some obvious errors)
check_syntax_basic() {
tns_log_message "INFO" "Performing basic syntax checks..."
local error_count=0
# Check for missing equals signs, parenthesis
while IFS= read -r line; do
line=$(echo "$line" | tr -d ' ') #remove spaces
if [[ -n "$line" && ! "$line" =~ ^#.* ]] ; then #ignore comments and empty lines
if [[ ! "$line" =~ .*=.* ]] ; then
tns_log_message "ERROR" "Missing equals sign in line: $line"
error_count=$((error_count+1))
fi
if [[ ${line//[()]/} != "$line" && ! "$line" =~ ^.*\(.*\) ]]; then
tns_log_message "ERROR" "Mismatched parenthesis or missing parenthesis in line: $line"
error_count=$((error_count+1))
fi
# Check for valid characters (alphanumeric, underscore, dot, parentheses, equals)
if ! echo "$line" | grep -E "^[a-zA-Z0-9._=()]+$"; then
tns_log_message "ERROR" "Invalid characters found in line: $line"
error_count=$((error_count+1))
fi
fi
done < "$TNS_FILE"
if [ "$error_count" -gt "0" ]; then
tns_log_message "ERROR" "Basic syntax check failed with $error_count errors."
return 1
else
tns_log_message "INFO" "Basic syntax check passed."
return 0
fi

}

# Check for duplicate TNS names (case-insensitive)
check_duplicate_names() {
tns_log_message "INFO" "Checking for duplicate TNS names..."
local -A tns_names
local error_count=0

while IFS= read -r line; do
# Extract TNS name (up to the first equals sign) and convert to lowercase
if [[ "$line" =~ ^([^=]+)=.* ]]; then
tns_name="${BASH_REMATCH[1]}"
tns_name_lower=$(echo "$tns_name" | tr '[:upper:]' '[:lower:]')
if [[ -v tns_names["$tns_name_lower"] ]]; then
tns_log_message "ERROR" "Duplicate TNS name found: $tns_name (case-insensitive)"
error_count=$((error_count+1))
else
tns_names["$tns_name_lower"]=1
fi
fi
done < "$TNS_FILE"
if [ "$error_count" -gt "0" ]; then
tns_log_message "ERROR" "Duplicate TNS name check failed with $error_count errors."
return 1
else
tns_log_message "INFO" "Duplicate TNS name check passed."
return 0
fi
}

# --- End TNS Validation functions -----

# Main script
host_name=$(hostname -f)
cd /store/dpd-tns/ || { log_message "Failed to navigate to /store/dpd-tns/"; exit 1; }

check_log_size

log_message "Starting git operations from $host_name"

# Clear validation log file
> "$VALIDATION_LOG_FILE"
tns_log_message "INFO" "Starting TNS file validation for: $TNS_FILE"

# Run TNS Validation
check_file_exists || { tns_log_message "ERROR" "TNS validation failed."; send_alert "TNS validation failed: file not found."; exit 1; }
check_file_permissions || { tns_log_message "ERROR" "TNS validation failed."; send_alert "TNS validation failed: file not readable."; exit 1; }
check_file_not_empty || { tns_log_message "ERROR" "TNS validation failed."; send_alert "TNS validation failed: file empty."; exit 1; }
check_syntax_basic || { tns_log_message "ERROR" "TNS validation failed."; send_alert "TNS validation failed: syntax error."; exit 1; }
check_duplicate_names || { tns_log_message "ERROR" "TNS validation failed."; send_alert "TNS validation failed: duplicate names."; exit 1; }

tns_log_message "INFO" "TNS file validation completed successfully."
log_message "TNS file validation completed successfully"

git add --all
git_add_ret=$?
if [ $git_add_ret -ne 0 ]; then
log_message "git add failed. return code: $git_add_ret"
send_alert "git add failed. return code: $git_add_ret"
exit $git_add_ret
else
log_message "git add successful"
fi

git commit -m "Automated file update from $host_name"
git_commit_ret=$?
if [ $git_commit_ret -ne 0 ]; then
log_message "git commit failed. return code: $git_commit_ret"
send_alert "git commit failed. return code: $git_commit_ret"
exit $git_commit_ret
else
log_message "git commit successful"
fi

git push -u origin master > output 2>&1
git_push_ret=$?
if [ $git_push_ret -ne 0 ]; then
log_message "Initial git push failed. Starting retry attempts."
CNT=1
while [ $CNT -le $RETRY_COUNT ]; do
sleep $RETRY_GAP
git push -u origin master > output 2>&1
git_retry_push_ret=$?
if [ $git_retry_push_ret -eq 0 ]; then
log_message "Git push successful on attempt $CNT."
exit 0
else
log_message "Git push failed on attempt $CNT."
CNT=$((CNT + 1))
fi
done
ERROR=$(cat output)
log_message "All retry attempts failed. Error: $ERROR"
send_alert "$ERROR"
exit $git_retry_push_ret
else
log_message "Git push successful."
fi

exit 0

23ai

 

Slide 1: Title Slide

  • Title: Oracle 23ai Upgrade Project Plan
  • Subtitle: From Oracle 19c Non-Multitenant to Oracle 23ai Multitenant
  • Your Name

Slide 2: Overview

  • Project Scope: Upgrade from Oracle 19c non-multitenant to Oracle 23ai multitenant architecture.
  • Key Components: Incorporate Oracle 23ai Goldengate Microservices Architecture.
  • Main Tasks: Conversion to multitenant, upgrade to 23ai, documentation, and automation.

Slide 3: Task: Conversion to Multitenant

  • Subtask 1: Define Standards and Documentation
    • Define Standards: 1 CDB to 1 PDB, naming conventions, resource allocation.
    • CMDB Modifications: Document required changes to CMDB.
    • Conversion Steps: Detailed documentation of conversion process.
    • Develop Automation: Automate conversion with error handling and logging.
    • SQL Scripts: Scripts for creating CDBs, plugging in PDBs, and validation.
    • .profile Setup: Simplify DB connections for administrators.

Slide 4: Subtask 2: Modify Existing Automation and Provisioning

  • Modification to Existing Automation: Update scripts for multitenant architecture.
  • Provisioning: Scripts for creating databases, RMAN duplication, EUS, TDE, and backups.
  • Estate SQL: Manage and monitor database estate across hosts.
  • Agile Patching: Implement agile patching processes.
  • Master TNS: Create consistent and up-to-date TNS configuration.
  • Patching Report: Develop Tableau report for leadership.
  • CyberArk EID Onboarding: Enhance security with CyberArk.

Slide 5: Subtask 3: Confluence Runbooks/Training and Testing

  • Runbooks/Training: Develop comprehensive documentation and training materials.
  • Test Conversion: Conduct test conversions to validate the process.

Slide 6: Task: Upgrade to 23ai

  • Subtask 1: Define Standards and Documentation
    • Define Standards: Utilize new features in Oracle 23ai.
    • Upgrade Steps: Detailed documentation of upgrade process.
    • Develop Automation: Automate upgrade with error handling and logging.
    • Test Upgrade: Conduct test upgrades to validate the process.
    • Update Confluence Documents: Reflect new architecture and upgrade process.
    • Create New SOPs: Develop Standard Operating Procedures for the upgraded environment.

Slide 7: Additional Enhancements

  • Performance Tuning: Optimize database performance and resource utilization.
  • Security Enhancements: Implement additional security measures.
  • Monitoring and Alerting: Set up proactive monitoring and alerting.
  • Disaster Recovery Planning: Update disaster recovery plans.
  • Stakeholder Communication: Maintain regular communication and provide status updates.

Slide 8: Conclusion

  • Summary: Comprehensive plan for a smooth upgrade to Oracle 23ai multitenant architecture.
  • Next Steps: Execute the plan with minimal disruption and maximum efficiency.
EpicUser StoryDescriptionAssigneeEstimated Time (Days)Start DateEnd DateStatus
Conversion to Multitenant
Epic 1User Story 1.1Define Standards and DocumentationDBA Lead501-Nov-202305-Nov-2023Not Started
Epic 1User Story 1.2Develop Automation for ConversionAutomation Engineer1006-Nov-202315-Nov-2023Not Started
Epic 1User Story 1.3Create SQL Scripts for ConversionSQL Developer716-Nov-202322-Nov-2023Not Started
Epic 1User Story 1.4Configure .profile for Ease of DB ConnectSystem Admin323-Nov-202325-Nov-2023Not Started
Modify Existing Automation and Provisioning
Epic 2User Story 2.1Update Existing Automation ScriptsAutomation Engineer726-Nov-202302-Dec-2023Not Started
Epic 2User Story 2.2Develop Provisioning ScriptsDBA Lead1003-Dec-202312-Dec-2023Not Started
Epic 2User Story 2.3Create Estate SQL ScriptsSQL Developer513-Dec-202317-Dec-2023Not Started
Epic 2User Story 2.4Implement Agile PatchingDBA Lead718-Dec-202324-Dec-2023Not Started
Epic 2User Story 2.5Create Master TNS ConfigurationDBA Lead325-Dec-202327-Dec-2023Not Started
Epic 2User Story 2.6Develop Patching Report for LeadershipData Analyst528-Dec-202301-Jan-2024Not Started
Epic 2User Story 2.7Onboard Databases to CyberArkSecurity Engineer702-Jan-202408-Jan-2024Not Started
Confluence Runbooks/Training and Testing
Epic 3User Story 3.1Develop Confluence Runbooks and Training MaterialsTechnical Writer1009-Jan-202418-Jan-2024Not Started
Epic 3User Story 3.2Conduct Test ConversionsDBA Lead1019-Jan-202428-Jan-2024Not Started
Upgrade to 23ai
Epic 4User Story 4.1Define Standards for New FeaturesDBA Lead529-Jan-202402-Feb-2024Not Started
Epic 4User Story 4.2Document Upgrade StepsTechnical Writer703-Feb-202409-Feb-2024Not Started
Epic 4User Story 4.3Develop Automation for UpgradeAutomation Engineer1010-Feb-202419-Feb-2024Not Started
Epic 4User Story 4.4Conduct Test UpgradesDBA Lead1020-Feb-202429-Feb-2024Not Started
Epic 4User Story 4.5Update Confluence DocumentsTechnical Writer501-Mar-202405-Mar-2024Not Started
Epic 4User Story 4.6Create New SOPsTechnical Writer706-Mar-202412-Mar-2024Not Started
Additional Enhancements
Epic 5User Story 5.1Conduct Performance TuningDBA Lead713-Mar-202419-Mar-2024Not Started
Epic 5User Story 5.2Implement Security EnhancementsSecurity Engineer720-Mar-202426-Mar-2024Not Started
Epic 5User Story 5.3Set Up Monitoring and AlertingSystem Admin527-Mar-202431-Mar-2024Not Started
Epic 5User Story 5.4Update Disaster Recovery PlansDBA Lead501-Apr-202405-Apr-2024Not Started
Epic 5User Story 5.5Maintain Stakeholder CommunicationProject ManagerOngoing01-Nov-2023OngoingIn Progress

Notes:

  • Assignee Roles:

    • DBA Lead: Database Administrator Lead
    • Automation Engineer: Responsible for developing automation scripts
    • SQL Developer: Responsible for creating SQL scripts
    • System Admin: Responsible for system configurations
    • Data Analyst: Responsible for developing reports
    • Security Engineer: Responsible for security-related tasks
    • Technical Writer: Responsible for documentation and training materials
    • Project Manager: Responsible for overall project management and stakeholder communication
  • Status:

    • Not Started: Task has not yet begun
    • In Progress: Task is currently being worked on
    • Completed: Task has been finished

This table provides a clear and organized way to track the progress of each task, ensuring that the project stays on schedule and that all team members are aware of their responsibilities and deadlines.

Notes:

23ai Upgrade Project Plan

Overview

This project involves upgrading from Oracle 19c non-multitenant architecture to Oracle 23ai multitenant architecture, incorporating Oracle 23ai Goldengate Microservices Architecture. The plan includes tasks for conversion to multitenant, upgrade to 23ai, and necessary documentation and automation.

Task: Conversion to Multitenant

Subtask 1: Define Standards and Documentation

  1. Define Standards

    • Establish the standard of 1 CDB (Container Database) to 1 PDB (Pluggable Database).
    • Define naming conventions for CDBs and PDBs.
    • Determine resource allocation standards for CDBs and PDBs.
  2. Define Required CMDB Modifications

    • Identify and document any required changes to the Configuration Management Database (CMDB).
    • Ensure CMDB reflects the new multitenant architecture.
  3. Document Conversion Steps

    • Create detailed documentation outlining the steps for converting from non-multitenant to multitenant architecture.
    • Include pre-conversion checks, conversion process, and post-conversion validation.
  4. Develop Automation

    • Automate the conversion process using scripts and tools.
    • Ensure automation includes error handling and logging.
  5. SQL Scripts

    • Develop SQL scripts required for the conversion process.
    • Include scripts for creating CDBs, plugging in PDBs, and validating the conversion.
  6. .profile Setup for Ease of DB Connect

    • Configure .profile settings to simplify database connections for administrators.
    • Include environment variables and aliases for common tasks.

Subtask 2: Modify Existing Automation and Provisioning

  1. Modification to Existing Automation

    • Update existing automation scripts to support the new multitenant architecture.
    • Ensure compatibility with Oracle 23ai features.
  2. Provisioning

    • Develop scripts for creating databases, RMAN duplication, EUS, TDE, and RMAN backups.
    • Ensure provisioning scripts are optimized for multitenant architecture.
  3. Estate SQL to Run Across Database Hosts

    • Create SQL scripts to manage and monitor the database estate.
    • Ensure scripts can run across multiple database hosts.
  4. Agile Patching

    • Implement agile patching processes for the new architecture.
    • Develop automation for patch deployment and rollback.
  5. Master TNS

    • Create a master TNS (Transparent Network Substrate) configuration for the new architecture.
    • Ensure TNS entries are consistent and up-to-date.
  6. Patching Report for Leadership Tableau Report

    • Develop a patching report for leadership, integrating with Tableau.
    • Include key metrics and status updates.
  7. CyberArk EID Onboarding

    • Onboard databases to CyberArk for enhanced security.
    • Ensure credentials are managed securely.

Subtask 3: Confluence Runbooks/Training and Testing

  1. Confluence Runbooks/Training

    • Develop runbooks and training materials for the conversion process.
    • Ensure documentation is comprehensive and accessible.
  2. Test Conversion

    • Conduct test conversions to validate the process.
    • Identify and resolve any issues encountered during testing.

Task: Upgrade to 23ai

Subtask 1: Define Standards and Documentation

  1. Define Standards with Regard to New Features

    • Establish standards for utilizing new features in Oracle 23ai.
    • Document best practices and guidelines.
  2. Document Upgrade Steps

    • Create detailed documentation outlining the steps for upgrading to Oracle 23ai.
    • Include pre-upgrade checks, upgrade process, and post-upgrade validation.
  3. Develop Automation

    • Automate the upgrade process using scripts and tools.
    • Ensure automation includes error handling and logging.
  4. Test Upgrade

    • Conduct test upgrades to validate the process.
    • Identify and resolve any issues encountered during testing.
  5. Update Confluence Documents

    • Update Confluence documentation to reflect the new architecture and upgrade process.
    • Ensure documentation is comprehensive and accessible.
  6. Create New SOPs

    • Develop new Standard Operating Procedures (SOPs) for the upgraded environment.
    • Ensure SOPs are aligned with best practices and organizational standards.

Additional Enhancements

  1. Performance Tuning

    • Conduct performance tuning for the new multitenant architecture.
    • Optimize database performance and resource utilization.
  2. Security Enhancements

    • Implement additional security measures for the new architecture.
    • Ensure compliance with organizational security policies.
  3. Monitoring and Alerting

    • Set up monitoring and alerting for the new architecture.
    • Ensure proactive identification and resolution of issues.
  4. Disaster Recovery Planning

    • Update disaster recovery plans to reflect the new architecture.
    • Ensure robust backup and recovery processes are in place.
  5. Stakeholder Communication

    • Maintain regular communication with stakeholders throughout the project.
    • Provide status updates and address any concerns.

By following this comprehensive plan, the upgrade to Oracle 23ai multitenant architecture can be executed smoothly, ensuring minimal disruption and maximum efficiency.


Jiras:

Epic 1: Conversion to Multitenant

User Story 1.1: Define Standards and Documentation

Description: As a database administrator, I need to define standards for the new multitenant architecture, including naming conventions, resource allocation, and CMDB modifications, so that the conversion process is standardized and documented. Business Justification: Standardizing the conversion process ensures consistency, reduces errors, and facilitates easier management and troubleshooting.

User Story 1.2: Develop Automation for Conversion

Description: As a database administrator, I need to develop automation scripts for the conversion process, including error handling and logging, so that the conversion can be performed efficiently and with minimal manual intervention. Business Justification: Automation reduces the risk of human error, speeds up the conversion process, and ensures repeatability.

User Story 1.3: Create SQL Scripts for Conversion

Description: As a database administrator, I need to create SQL scripts for creating CDBs, plugging in PDBs, and validating the conversion, so that the conversion process is streamlined and reliable. Business Justification: Having pre-defined SQL scripts ensures that the conversion steps are executed correctly and consistently.

User Story 1.4: Configure .profile for Ease of DB Connect

Description: As a database administrator, I need to configure .profile settings to simplify database connections, so that administrators can easily connect to the databases and perform their tasks. Business Justification: Simplifying database connections improves productivity and reduces the likelihood of connection errors.

Epic 2: Modify Existing Automation and Provisioning

User Story 2.1: Update Existing Automation Scripts

Description: As a database administrator, I need to update existing automation scripts to support the new multitenant architecture, so that the automation is compatible with Oracle 23ai features. Business Justification: Ensuring compatibility with the new architecture and features is crucial for maintaining automation efficiency and effectiveness.

User Story 2.2: Develop Provisioning Scripts

Description: As a database administrator, I need to develop scripts for creating databases, RMAN duplication, EUS, TDE, and RMAN backups, so that the provisioning process is automated and optimized for the new architecture. Business Justification: Automating the provisioning process reduces manual effort, speeds up database creation, and ensures consistency.

User Story 2.3: Create Estate SQL Scripts

Description: As a database administrator, I need to create SQL scripts to manage and monitor the database estate, so that I can ensure the health and performance of the databases. Business Justification: Effective management and monitoring are essential for maintaining database performance and availability.

User Story 2.4: Implement Agile Patching

Description: As a database administrator, I need to implement agile patching processes and develop automation for patch deployment and rollback, so that patches can be applied quickly and safely. Business Justification: Agile patching ensures that security vulnerabilities and bugs are addressed promptly, reducing the risk of downtime and data breaches.

User Story 2.5: Create Master TNS Configuration

Description: As a database administrator, I need to create a master TNS configuration for the new architecture, so that TNS entries are consistent and up-to-date. Business Justification: A consistent TNS configuration simplifies database connectivity and reduces connection issues.

User Story 2.6: Develop Patching Report for Leadership

Description: As a database administrator, I need to develop a patching report for leadership, integrating with Tableau, so that key metrics and status updates are easily accessible. Business Justification: Providing leadership with clear and concise reports ensures transparency and facilitates informed decision-making.

User Story 2.7: Onboard Databases to CyberArk

Description: As a database administrator, I need to onboard databases to CyberArk for enhanced security, so that credentials are managed securely. Business Justification: Secure credential management is critical for protecting sensitive data and preventing unauthorized access.

Epic 3: Confluence Runbooks/Training and Testing

User Story 3.1: Develop Confluence Runbooks and Training Materials

Description: As a database administrator, I need to develop runbooks and training materials for the conversion process, so that team members are well-prepared and informed. Business Justification: Comprehensive documentation and training ensure that the team can execute the conversion process effectively and handle any issues that arise.

User Story 3.2: Conduct Test Conversions

Description: As a database administrator, I need to conduct test conversions to validate the process, so that any issues can be identified and resolved before the actual conversion. Business Justification: Testing the conversion process ensures that it works as expected and reduces the risk of issues during the actual conversion.

Epic 4: Upgrade to 23ai

User Story 4.1: Define Standards for New Features

Description: As a database administrator, I need to define standards for utilizing new features in Oracle 23ai, so that best practices are established and documented. Business Justification: Establishing standards for new features ensures that they are used effectively and consistently across the organization.

User Story 4.2: Document Upgrade Steps

Description: As a database administrator, I need to create detailed documentation outlining the steps for upgrading to Oracle 23ai, so that the upgrade process is clear and well-documented. Business Justification: Clear documentation ensures that the upgrade process is executed correctly and reduces the risk of errors.

User Story 4.3: Develop Automation for Upgrade

Description: As a database administrator, I need to develop automation scripts for the upgrade process, so that the upgrade can be performed efficiently and with minimal manual intervention. Business Justification: Automation reduces the risk of human error, speeds up the upgrade process, and ensures repeatability.

User Story 4.4: Conduct Test Upgrades

Description: As a database administrator, I need to conduct test upgrades to validate the process, so that any issues can be identified and resolved before the actual upgrade. Business Justification: Testing the upgrade process ensures that it works as expected and reduces the risk of issues during the actual upgrade.

User Story 4.5: Update Confluence Documents

Description: As a database administrator, I need to update Confluence documentation to reflect the new architecture and upgrade process, so that team members have access to accurate and up-to-date information. Business Justification: Keeping documentation up-to-date ensures that the team can execute their tasks effectively and reduces the risk of errors.

User Story 4.6: Create New SOPs

Description: As a database administrator, I need to develop new Standard Operating Procedures (SOPs) for the upgraded environment, so that best practices are established and followed. Business Justification: Establishing SOPs ensures that the team follows best practices and maintains consistency in their work.

Additional Enhancements

User Story 5.1: Conduct Performance Tuning

Description: As a database administrator, I need to conduct performance tuning for the new multitenant architecture, so that database performance is optimized. Business Justification: Optimizing performance ensures that the databases run efficiently and meet the organization's performance requirements.

User Story 5.2: Implement Security Enhancements

Description: As a database administrator, I need to implement additional security measures for the new architecture, so that the databases are secure and compliant with organizational policies. Business Justification: Enhancing security protects sensitive data and reduces the risk of data breaches.

User Story 5.3: Set Up Monitoring and Alerting

Description: As a database administrator, I need to set up monitoring and alerting for the new architecture, so that issues can be identified and resolved proactively. Business Justification: Proactive monitoring and alerting ensure that issues are addressed before they impact the business.

User Story 5.4: Update Disaster Recovery Plans

Description: As a database administrator, I need to update disaster recovery plans to reflect the new architecture, so that robust backup and recovery processes are in place. Business Justification: Ensuring robust disaster recovery processes minimizes downtime and data loss in the event of a disaster.

User Story 5.5: Maintain Stakeholder Communication

Description: As a project manager, I need to maintain regular communication with stakeholders throughout the project, so that they are informed and any concerns are addressed. Business Justification: Regular communication ensures that stakeholders are aware of the project's progress and can provide input as needed.

By organizing the project into these Epics and User Stories, the team can effectively manage and track the progress of the 23ai upgrade project, ensuring that all tasks are completed efficiently and to a high standard.


Project Plan for Migrating Oracle Databases from 19c Non-Multitenant to 23c Multitenant

Project Overview

This project aims to migrate Oracle databases from 19c Non-Multitenant architecture to 23c Multitenant architecture. The project will be divided into two main tasks: conversion to multitenant and upgrade to 23c. Each task will have its own set of subtasks, meetings, Jira tickets, user stories, and documentation requirements.

Task 1: Conversion to Multitenant

Subtasks:

  1. Define Standards

    • User Story: As a DBA, I need to define the standards for the multitenant architecture to ensure consistency across the estate.
    • Subtasks:
      • Research best practices for multitenant architecture.
      • Define the standard for 1 CDB to 1 PDB.
      • Document the standards in Confluence.
  2. Define Required CMDB Modifications

    • User Story: As a DBA, I need to identify and document any required CMDB modifications to support the new architecture.
    • Subtasks:
      • Review current CMDB entries.
      • Identify required modifications.
      • Document the changes.
  3. Document Conversion Steps

    • User Story: As a DBA, I need to document the steps required to convert from non-multitenant to multitenant architecture.
    • Subtasks:
      • Research conversion steps.
      • Create a detailed conversion guide.
      • Review and approve the guide.
  4. Develop Automation

    • User Story: As a DBA, I need to develop automation scripts to streamline the conversion process.
    • Subtasks:
      • Identify automation requirements.
      • Develop scripts for conversion.
      • Test and validate scripts.
  5. Modifications to Existing Automation

    • User Story: As a DBA, I need to modify existing automation scripts to support the new multitenant architecture.
    • Subtasks:
      • Provisioning (DB create/RMAN dup/EUS/TDE/RMAN)
      • Estate SQL (runs across the fleet of databases)
      • DPD agile patching page
      • Master TNS
      • Patching report for leadership's Tableau report
      • CyberArk EID onboarding
  6. Confluence Runbooks/Training

    • User Story: As a DBA, I need to create runbooks and training materials to ensure smooth operations post-conversion.
    • Subtasks:
      • Create runbooks for common tasks.
      • Develop training materials.
      • Conduct training sessions.
  7. Test Conversion

    • User Story: As a DBA, I need to test the conversion process to ensure it works as expected.
    • Subtasks:
      • Set up a test environment.
      • Perform test conversions.
      • Document test results.
  8. Convert the Estate

    • User Story: As a DBA, I need to convert the entire database estate to the new multitenant architecture.
    • Subtasks:
      • Schedule conversions.
      • Perform conversions.
      • Monitor and validate conversions.

Task 2: Upgrade to 23c

Subtasks:

  1. Define Standards with Regard to New Features

    • User Story: As a DBA, I need to define standards for using new features in Oracle 23c.
    • Subtasks:
      • Research new features.
      • Define standards.
      • Document standards.
  2. Document Upgrade Steps

    • User Story: As a DBA, I need to document the steps required to upgrade to Oracle 23c.
    • Subtasks:
      • Research upgrade steps.
      • Create a detailed upgrade guide.
      • Review and approve the guide.
  3. Develop Automation

    • User Story: As a DBA, I need to develop automation scripts to streamline the upgrade process.
    • Subtasks:
      • Identify automation requirements.
      • Develop scripts for upgrade.
      • Test and validate scripts.
  4. Test Upgrade

    • User Story: As a DBA, I need to test the upgrade process to ensure it works as expected.
    • Subtasks:
      • Set up a test environment.
      • Perform test upgrades.
      • Document test results.
  5. Update Confluence Documents

    • User Story: As a DBA, I need to update Confluence documents to reflect the new upgrade process.
    • Subtasks:
      • Review existing documents.
      • Update documents with new information.
      • Review and approve updates.
  6. Create New SOPs

    • User Story: As a DBA, I need to create new Standard Operating Procedures (SOPs) for the upgraded environment.
    • Subtasks:
      • Identify new SOP requirements.
      • Create SOPs.
      • Review and approve SOPs.
  7. Upgrade the Estate

    • User Story: As a DBA, I need to upgrade the entire database estate to Oracle 23c.
    • Subtasks:
      • Schedule upgrades.
      • Perform upgrades.
      • Monitor and validate upgrades.

Points of Contact (POCs) and Exploring New Features

  • User Story: As a DBA, I need to identify POCs and explore new features in Oracle 23c to leverage them effectively.
  • Subtasks:
    • Identify POCs for each new feature.
    • Conduct research and testing on new features.
    • Document findings and recommendations.

Meetings

  1. Kickoff Meeting

    • Agenda: Project overview, objectives, roles, and responsibilities.
    • Attendees: Project Manager, DBAs, Stakeholders.
  2. Weekly Status Meetings

    • Agenda: Progress updates, issues, and next steps.
    • Attendees: Project Manager, DBAs, Stakeholders.
  3. Technical Review Meetings

    • Agenda: Review technical details, standards, and automation scripts.
    • Attendees: DBAs, Technical Leads.
  4. Training Sessions

    • Agenda: Training on new architecture, processes, and SOPs.
    • Attendees: DBAs, Operations Team.

Jira Tickets

Epics

  1. Epic: Conversion to Multitenant

    • User Stories: Define standards, CMDB modifications, document conversion steps, develop automation, modify existing automation, create runbooks/training, test conversion, convert the estate.
  2. Epic: Upgrade to 23c

    • User Stories: Define standards with regard to new features, document upgrade steps, develop automation, test upgrade, update Confluence documents, create new SOPs, upgrade the estate.

User Stories and Subtasks

  • Each user story will have associated subtasks as detailed above.
  • Each subtask will be tracked as a Jira ticket with clear descriptions, assignees, and due dates.

Documentation

  • Confluence: All standards, conversion steps, upgrade steps, runbooks, training materials, and SOPs will be documented in Confluence.
  • Jira: All tasks, user stories, and subtasks will be tracked in Jira.

Conclusion

This detailed project plan outlines the steps required to migrate Oracle databases from 19c Non-Multitenant to 23c Multitenant architecture. By following this plan, we can ensure a smooth and efficient migration process, leveraging automation and best practices to minimize downtime and ensure consistency across the database estate.



Okay, this is a comprehensive and ambitious project! Migrating an entire Oracle 19c non-multitenant database estate to 23ai multitenant, including a subsequent upgrade, is a significant undertaking. I'll break down the plan into detailed phases, including meetings, Jira elements, automation, and documentation.

Project Goal: Migrate the entire Oracle 19c Non-Multitenant database estate to Oracle 23ai Multitenant and subsequently upgrade them to 23ai, while ensuring minimal disruption and maximizing the benefits of the new architecture.

Phases:

  1. Planning and Assessment (Discovery)
  2. Multitenant Conversion (Migration)
  3. 23ai Upgrade
  4. Post-Migration/Upgrade and Optimization

Jira Structure:

  • Epic: Migrate Oracle 19c Estate to 23ai Multitenant
    • Epic: Convert to Multitenant
    • Epic: Upgrade to 23ai
  • Stories: Represent the major work items within each Epic (e.g., "Define Multitenant Standards," "Develop Conversion Automation," "Upgrade Non-Prod to 23ai").
  • Subtasks: Break down each Story into actionable tasks (e.g., "Document CDB Naming Convention," "Write PowerShell Script for PDB Creation").

Phase 1: Planning and Assessment (Discovery)

Goal: Understand the current state, define standards, and create a detailed migration/upgrade plan.

Meetings:

  1. Project Kickoff Meeting:
    • Attendees: Database Leads, DBA Team, Application Owners, Security Team, Infrastructure Team, Project Manager, Management.
    • Topics: Project overview, goals, scope, high-level timeline, roles, initial challenges, communication plan.
    • Outcome: Project charter, stakeholder buy-in.
  2. Environment Assessment Meetings (Multiple):
    • Attendees: DBAs, Application Owners.
    • Topics: Review each database instance, application dependencies, size, data growth rate, downtime tolerance, existing customizations, special configurations, and criticality.
    • Outcome: Database inventory, compatibility assessment, potential risks, resource needs.
  3. Standards Definition Meetings:
    • Attendees: DBA Leads, Security Team.
    • Topics: CDB/PDB naming standards, number of PDBs per CDB (1:1, 1:N), resource management (CPU, memory), security policies, backup/recovery strategy, TDE, EUS, network configurations, performance monitoring requirements.
    • Outcome: Multitenant Standards Document.
  4. CMDB modification meeting
    • Attendees: DBA Leads, CMDB Owner
    • Topics: go through the list of CMDB attributes, how will they change?
    • Outcome: list of changes to be made to CMDB

Jira Elements (Epic: Convert to Multitenant):

  • Story: Define Multitenant Standards
    • Subtask: Document CDB Naming Convention
    • Subtask: Document PDB Naming Convention
    • Subtask: Define CDB/PDB Resource Allocation Standards
    • Subtask: Define Security Best Practices for Multitenant
    • Subtask: Define Backup/Recovery Strategy for Multitenant
    • Subtask: 1 CDB to 1 PDB ratio approved.
  • Story: CMDB Modifications
    • Subtask: Review list of attributes with CMDB Owner.
    • Subtask: Define the list of changes to be made.
    • Subtask: CMDB changed after testing and UAT.
  • Story: Create Database Inventory and Compatibility Assessment
    • Subtask: Inventory all 19c non-multitenant databases.
    • Subtask: Document application connections and dependencies.
    • Subtask: Document data growth rates.
    • Subtask: Assess compatibility for each database.
    • Subtask: Document any incompatibilities and mitigation steps.
  • Story: Develop Detailed Migration Plan
    • Subtask: Define migration approach (hot/cold/logical/physical).
    • Subtask: Create detailed timelines for each database.
    • Subtask: Create rollback strategy for each database.
    • Subtask: Define data validation procedures after migration.
    • Subtask: Define application connectivity tests after migration

Phase 2: Multitenant Conversion (Migration)

Goal: Migrate all 19c non-multitenant databases to 19c multitenant databases.

Documentation:

  1. Conversion Runbook: Step-by-step guide for converting each non-multitenant database to a PDB.
    • Detailed commands, scripts, expected output.
    • Pre-conversion checks (e.g., database health, space).
    • Conversion steps (using unplug/plug, Data Pump, etc.).
    • Post-conversion validation (e.g., data integrity, application connectivity).
    • Rollback steps (if needed).
    • Troubleshooting guide.
  2. Training Material: step by step document for new dba on how to provision a PDB from scratch.
  3. Documentation of how to add a service into the master TNS
  4. Automation Design Document: Describes the automation architecture, tools, scripts, and how they interact.

Automation:

  1. Provisioning:
    • CDB Creation: Script (e.g., Python, PowerShell, shell) to create a new CDB.
    • PDB Creation:
      • From Seed: Use CREATE PLUGGABLE DATABASE syntax.
      • From Non-CDB: Use unplug/plug with XML or Data Pump.
      • RMAN Duplicate: Script to duplicate non-CDB to PDB.
      • EUS (Enterprise User Security): Automate user/role mapping to the CDB, PDB, and directories
      • TDE (Transparent Data Encryption): Automate TDE wallet creation/management at the CDB and PDB level.
      • RMAN: Automate RMAN backups for the CDB and PDBs.
    • Cyberark EID onboard: Create the PDB in cyberark.
  2. Estate SQL:
    • Modify existing scripts to run against CDB/PDB architecture (e.g., parameter checking, schema validation). Ensure the scripts run accross all the CDBs/PDBs.
  3. DPD agile patching page:
    • Update the page with the new type of database (CDB, PDB)
    • update the way patches are applied, CDB first, then PDBs.
  4. Master TNS:
    • Automate service creation in the master TNS for PDBs.
    • Update connection strings in applications to use PDB service names.
  5. Patching Report:
    • Modify patching scripts to handle CDB/PDB patching.
    • Update the Tableau reporting to include CDB/PDB info.
  6. CMDB updates:
    • Develop scripts to update the CMDB after database creation.

Jira Elements (Epic: Convert to Multitenant):

  • Story: Develop Conversion Runbook
    • Subtask: Document Pre-Conversion Checks
    • Subtask: Document Conversion Steps (Unplug/Plug, Data Pump)
    • Subtask: Document Post-Conversion Validation
    • Subtask: Document Rollback Steps
    • Subtask: Document Troubleshooting Guide
    • Subtask: Document Training material for creating PDB.
  • Story: Develop Conversion Automation
    • Subtask: Develop CDB Creation Script
    • Subtask: Develop PDB Creation Script (From Seed)
    • Subtask: Develop PDB Unplug/Plug Script
    • Subtask: Develop PDB RMAN Duplicate Script
    • Subtask: Develop Cyberark EID onboarding Script
    • Subtask: Develop CMDB update scripts.
  • Story: Modify Existing Automation
    • Subtask: Update Estate SQL Scripts for CDB/PDB
    • Subtask: Update RMAN Backup Scripts
    • Subtask: Update Provisioning scripts.
    • Subtask: update patching report.
    • Subtask: Update DPD agile patching page.
    • Subtask: Update Master TNS.
  • Story: Test Conversion Automation
    • Subtask: Unit test automation scripts.
    • Subtask: Test Conversion Runbook on a dev database.
    • Subtask: Test Conversion Runbook on a test database.
    • Subtask: Perform end-to-end testing (including application connectivity).
  • Story: Convert Database Estate
    • Subtask: Convert Database XYZ to PDB
    • Subtask: Convert Database ABC to PDB
    • (Repeat for each database)

Phase 3: 23ai Upgrade

Goal: Upgrade the entire 19c multitenant estate to Oracle 23ai.

Meetings:

  1. New Features Review Meeting:
    • Attendees: DBA Leads, Security Team, Application Architects.
    • Topics: Review new 23ai features, assess their applicability, identify features to implement, create a roadmap for feature adoption.
    • Outcome: 23ai Features Roadmap.

Documentation:

  1. Upgrade Runbook: Step-by-step guide for upgrading each CDB and its PDBs to 23ai.
    • Pre-upgrade checks (e.g., database health, space, patching level).
    • Upgrade steps (using DBUA, command line).
    • Post-upgrade validation (e.g., data integrity, performance).
    • Rollback steps (if needed).
    • Troubleshooting guide.
  2. New SOPs: New operational procedures that change because of new features (e.g. json_relational duality view, etc).
  3. Updated runbook on how to provision a PDB

Automation:

  1. Upgrade Automation:
    • Script to automate the pre-upgrade checks.
    • Script to automate the upgrade process (DBUA or command line).
    • Script to automate post-upgrade validation.
  2. Updated Provisioning scripts:
    • Scripts updated to create a 23ai PDB.
  3. Updated patching scripts:
    • Scripts updated to handle 23ai.

Jira Elements (Epic: Upgrade to 23ai):

  • Story: Define 23ai Feature Adoption Strategy
    • Subtask: Research New 23ai Features
    • Subtask: Define Prioritized Feature List
    • Subtask: Document Feature Implementation Roadmap
  • Story: Develop Upgrade Runbook
    • Subtask: Document Pre-Upgrade Checks
    • Subtask: Document Upgrade Steps
    • Subtask: Document Post-Upgrade Validation
    • Subtask: Document Rollback Steps
    • Subtask: Document Troubleshooting Guide
    • Subtask: Update document on how to provision a PDB.
  • Story: Develop Upgrade Automation
    • Subtask: Develop Pre-Upgrade Check Script
    • Subtask: Develop Upgrade Script
    • Subtask: Develop Post-Upgrade Validation Script
    • Subtask: Update provisioning scripts.
    • Subtask: Update patching scripts.
  • Story: Test Upgrade Automation
    • Subtask: Unit test automation scripts.
    • Subtask: Test Upgrade Runbook on a dev database.
    • Subtask: Test Upgrade Runbook on a test database.
    • Subtask: Perform end-to-end testing (including application connectivity).
  • Story: Upgrade Database Estate
    • Subtask: Upgrade CDB XYZ and its PDBs to 23ai
    • Subtask: Upgrade CDB ABC and its PDBs to 23ai
    • (Repeat for each CDB)
  • Story: Update Confluence Documents
    • Subtask: Update runbooks
    • Subtask: Create new SOPS.
  • Story: POCs
    • Subtask: POC using JSON_RELATIONAL DUALITY VIEW
    • Subtask: POC using Automatic indexes.

Phase 4: Post-Migration/Upgrade and Optimization

Goal: Ensure stability, address any issues, and begin to take advantage of 23ai features.

Activities:

  1. Performance Monitoring: Monitor CDB/PDB performance, identify bottlenecks, and tune as needed.
  2. Feature Implementation: Begin implementing the 23ai features prioritized in the roadmap.
  3. Documentation Updates: Keep documentation updated with any changes or lessons learned.
  4. Knowledge Sharing: Conduct training sessions to share knowledge about multitenant and 23ai.
  5. Post Migration/Upgrade validation: check all the application, check all the databases, check if all the process are ok.

Jira Elements:

  • Story: Monitor and Optimize Performance
    • Subtask: Monitor Database Performance
    • Subtask: Identify Performance Bottlenecks
    • Subtask: Tune Databases
  • Story: Implement 23ai Features
    • Subtask: Implement Feature X
    • Subtask: Implement Feature Y
  • Story: Update Documentation and Train Team
    • Subtask: Update Conversion Runbook
    • Subtask: Update Upgrade Runbook
    • Subtask: Conduct Multitenant Training
    • Subtask: Conduct 23ai Training
  • Story: Validate migration/upgrade.

Key Success Factors:

  • Strong Communication: Keep all stakeholders informed.
  • Thorough Testing: Rigorous testing is critical at every stage.
  • Automation: Automation reduces errors and speeds up execution.
  • Documentation: Clear documentation is crucial for consistency and knowledge transfer.
  • Rollback Strategy: Having a well-defined rollback plan is essential.
  • Expertise: Ensure the team has the necessary Oracle multitenant and 23ai expertise.

This detailed plan provides a solid framework for your migration/upgrade project. Remember that this is a large project, so staying organized and maintaining focus on the goals is critical.



Project Information

Sizing Requirements

  • Storage Volume Limitation: Will you be limiting the volume of storage required for your database on Exadata? Exadata resources are expensive and therefore limited. Expanding resources requires a significant amount of time and money.
  • Shared Platform: Can your database reside on a shared platform? Your application will not have the option to decide when patching/maintenance occurs.
  • Connection Volume Control: How will connection volume be controlled/limited? Connection storms can cause node evictions.
  • Production Build Correspondence: If OA, will there be a corresponding production build?
  • Production Build Request: If production builds are planned, when will the request be submitted?
  • Production Database Size Estimate: What will the production database size estimate be from a compute and storage perspective for the next 12 months?
  • Planned Production Go-Live Date: What is the planned production go-live date?
  • Capacity Forecasting Survey: Were the sizing estimates included within the latest capacity forecasting survey?
  • ACT Validation: When will you be validating ACT (read/write services)? It is a requirement that applications be able to withstand a node going down. Validation is required that transactions are not lost when a node is taken down for patching or maintenance. It is not permitted to go live on Exadata if your application is not ACTG compliant.
  • Exadata-Specific Features: Do you intend to leverage any of the features specific to Exadata? If so, what and why?

Important Note

An approved TDF# with "TDF Stage" of at least "Provision, Code and Test" is required before DPS can work on any QA and Production builds. Consult the following page for additional details regarding requirements for being placed on Exadata.

Post-Provisioning Validation

You can run the post_provisioning_validation.sh script which will also perform the following functionalities:

Database Type Reporting

  • RAC or Single Instance: Adds information about whether the database is RAC or single instance to the summary report.

Validation Checks

  • Encryption Wallet Validation: Checks if the encryption wallet is open.
  • Tablespace Encryption Validation: Checks if tablespace encryption is enabled.
  • Password File Validation: Checks if a password file exists.
  • Invalid Components Validation: Checks for invalid components in the database.
  • Block Change Tracking Validation: Checks if block change tracking is enabled.
  • NLS Character Set Information: Retrieves and reports the NLS character set information.
  • DNG Triggers Validation: Checks for DNG startup/switchover services, with different checks for RAC and single instance databases.
  • RAC Services Validation: Checks if RWSV related services are running (only for RAC databases).
  • Parameter Validation: Compares current database parameters with default values and categorizes them into failures, successes, and info.
  • Summary Report Generation: Writes failures, successes, and info to the summary report in the mentioned order.
  • Detailed Report Generation: Writes detailed validation results to the detailed report.

Additional Checks

  • Listener Check: Validates the status and configuration of the database listener.
  • EUS Check: Validates Enterprise User Security (EUS) configurations.
  • sqlnet.ora File Check: Validates the configurations in the sqlnet.ora file.
  • Backup Configuration Check: Ensures that backup configurations are in place and functioning correctly.
  • Alert Log Monitoring: Checks the alert logs for any critical errors or warnings.
  • Resource Manager Plan Validation: Ensures that the Resource Manager plan is configured and active.
  • ASM Disk Group Validation: Checks the status and configuration of ASM disk groups.
  • Data Guard Configuration Check: Validates Data Guard configurations if applicable.

Script Explanation

If you need an explanation and understanding of the logic of this script, I have provided it at the bottom of the script. 


Enhanced Provisioning Check Document: Exadata Database Deployment

Introduction:

This document outlines the critical checks and information required before provisioning a database on the Exadata platform and the post provisioning validations. Exadata is a high-performance, specialized platform with limited resources and specific operational requirements. Ensuring your database and application are compatible with Exadata and that you've planned accordingly is essential for a smooth deployment and ongoing stability. Careful adherence to this document will contribute significantly to a successful implementation.

Part 1: Pre-Provisioning Checklist - Key Considerations for Exadata Deployment

This section outlines the questions that need to be addressed and documented before any database is provisioned on Exadata. Failure to provide this information will delay or potentially block your project's progress.

Project Details:

  • Project Name: [Enter Project Name Here]
  • Project Manager: [Enter Project Manager Here]
  • Application Name: [Enter Application Name Here]
  • Application Owner: [Enter Application Owner Name here]
  • Application Team Contact:[Enter Application team contact info here]
  • TDF#: [Enter Approved TDF# - Must be in "Provision, Code and Test" stage or higher]

1. Resource Sizing and Planning:

  • 1.1 Storage Requirements:
    • Question: Will you be limiting the volume of storage required for your database on Exadata?
    • Why it Matters: Exadata resources (especially storage) are expensive and finite. Accurately determining your storage needs is crucial.
    • Expected information: Provide exact number in TB or GB
    • Response: [Provide detailed answer here]
  • 1.2 Compute Requirements:
    • Question: What is the estimated production database size (compute and storage) for the next 12 months?
    • Why it Matters: This helps us plan for potential growth and ensure sufficient resources are available.
    • Expected information: Number of cores, and approximate size in TB or GB
    • Response: [Provide detailed answer here]
  • 1.3 Resource Expansion:
    • Question: Are you aware that expanding resources on Exadata (compute or storage) requires a significant amount of time and potentially substantial cost?
    • Why it Matters: Planning for future growth should be done proactively.
    • Response: [Confirm awareness and understanding]
  • 1.4 Capacity Forecasting:
    • Question: Were the sizing estimates included within the latest capacity forecasting survey?
    • Why it Matters: This enables the team to validate and plan for resources needed.
    • Response: [Provide details if submitted in capacity survey]

2. Platform and Architecture:

  • 2.1 Shared Platform Suitability:
    • Question: Can your database reside on a shared Exadata platform?
    • Why it Matters: Shared platforms have scheduled patching and maintenance windows that all databases must adhere to. This is important to understand if your application has any tight control on maintenace.
    • Response: [Provide detailed answer here]
  • 2.2 High Availability (HA) and Active/Active (ACT) Compliance:
    • Question: When will you be validating Active/Active (read/write services) capability?
    • Why it Matters: Exadata is a high-availability environment. Applications must be able to withstand a node failure without losing transactions. Applications that cannot meet this requirement are not allowed to run on Exadata.
    • Expected Information: Date when ACT validation will be performed.
    • Response: [Provide detailed answer here]
  • 2.3. Prod Build:
    • Question: If QA is planned, will there be a corresponding prod build?
    • Why it matters: To plan ahead and make sure resources are available for the prod deployment.
    • Response: [Confirm if prod build is planned.]
  • 2.4. Prod Build request date:
    • Question: If prod builds are planned, when will the request be submitted?
    • Why it matters: to provide us with ample time to prepare for the build.
    • Response: [Provide Date]

3. Security and Connectivity:

  • 3.1 Connection Management:
    • Question: How will connection volume be controlled/limited?
    • Why it Matters: Uncontrolled connection surges (connection storms) can overwhelm Exadata nodes and lead to node evictions, causing outages.
    • Expected Information: planned number of concurrent connections, connection pooling mechanism, failover strategy etc.
    • Response: [Provide detailed answer here]
  • 3.2. EUS:
    • Question: Does the application use Enterprise User Security (EUS)?
    • Why it matters: This information will be needed to configure the application.
    • Response: [Provide details here.]

4. Exadata-Specific Features:

  • 4.1 Feature Utilization:
    • Question: Do you intend to leverage any of the features specific to Exadata (e.g., Smart Scans, Hybrid Columnar Compression, Flash Cache)? If so, what and why?
    • Why it Matters: Using Exadata's unique features can greatly enhance performance. Understanding your intent helps us optimize the environment.
    • Response: [Provide detailed answer here]

5. Go-Live and Timeline:

  • 5.1 Production Go-Live:
    • Question: What is the planned production go-live date?
    • Why it Matters: This information is crucial for resource planning and scheduling.
    • Response: [Provide date here]

6. TDF Requirement:

  • IMPORTANT: An APPROVED TDF# with "TDF Stage" of at least "Provision, Code and Test" is required before DPS can work on any QA and Production builds. This process ensures all necessary stakeholders are engaged and agree on the technical design.
  • Referance: [Consult the following page for additional details regarding requirements for being placed on Exadata. Please insert a link here]

Part 2: Post-Provisioning Validation Checklist

This section details the steps required to validate the newly provisioned database. It should be run automatically after provisioning is complete.

Script-Based Validation ( post_provisioning_validation.sh ):

The post_provisioning_validation.sh script automates many of these checks. Run the script and review the generated summary and detailed reports.

Validation Functionalities:

  1. Database Type Reporting:
    • Check: Determines and reports if the database is a RAC (Real Application Clusters) database or a single-instance database.
    • Importance: Knowing the database type impacts other validation checks.
  2. Encryption Wallet Validation:
    • Check: Verifies that the encryption wallet is open and accessible.
    • Importance: Ensures data-at-rest encryption is functioning correctly.
  3. Tablespace Encryption Validation:
    • Check: Determines if tablespace encryption is enabled.
    • Importance: Confirms that the tablespaces have data at rest encryption.
  4. Password File Validation:
    • Check: Confirms the existence of a password file.
    • Importance: Critical for database authentication.
  5. Invalid Components Validation:
    • Check: Identifies and reports any invalid objects or components within the database.
    • Importance: Invalid components can lead to errors and instability.
  6. Block Change Tracking Validation:
    • Check: Verifies that block change tracking is enabled.
    • Importance: Essential for efficient backups and recovery.
  7. NLS Character Set Information:
    • Check: Reports the database's NLS character set.
    • Importance: Ensures proper handling of character data.
  8. DNG Triggers Validation:
    • Check: Confirms DNG (Data Guard) startup/switchover services are properly configured. Different checks apply for RAC vs. single-instance.
    • Importance: Critical for disaster recovery and high availability.
  9. RAC Services Validation (RAC Only):
    • Check: Ensures that RWSV (Read/Write Service Verification) related services are active.
    • Importance: Ensures services are running on the cluster.
  10. Parameter Validation:
    • Check: Compares the current database parameters with default values. Results are categorized into failures, successes, and informational items.
    • Importance: Identifies potential performance or configuration issues.
  11. Summary Report Generation:
    • Output: Writes a concise summary of failures, successes, and informational items in the defined order.
    • Importance: Provides a quick overview of the validation results.
  12. Detailed Report Generation:
    • Output: Generates a comprehensive report with detailed results for each validation check.
    • Importance: Allows for in-depth analysis and troubleshooting.

Manual and Additional Checks:

These checks are to be performed manually or in addition to the script.

  1. Listener Check:
    • Check: Verify that the database listener is running and configured correctly. Check that database registered properly with the listener.
    • Command Example: lsnrctl status
    • Importance: Critical for external connections to the database.
  2. sqlnet.ora file Check:
    • Check: Verify that the sqlnet.ora file is properly configured.
    • Importance: This file containes important information for connection and security purposes.
  3. TNS alias check:
    • Check: Check if the database can be connected using the provided tns alias.
    • Importance: Confirms the network connectivity for the db.
  4. Network Connectivity:
    • Check: Test connectivity from application servers to the database using SQL*Plus or other tools.
    • Importance: Ensures applications can reach the database.
  5. Alert log:
    • Check: Check the alert log for any errors.
    • Importance: This contains any error or warning that has happened.
  6. ASM diskgroup usage:
    • Check: Check the asm diskgroup usage
    • Importance: Make sure enough space is available.
  7. OS space:
    • Check: Check the OS space on each node.
    • Importance: Make sure enough OS space is available.
  8. RMAN Backup:
    • Check: Test if RMAN can connect properly and backup is working.
    • Importance: For backup purposes, rman needs to be working.
  9. Patching Level:
    • Check: confirm the patching level of the database.
    • Importance: Make sure the database is on the correct patch level.
  10. Privileges:
    • Check: make sure that the required privileges were granted.
    • Importance: Make sure that the application will be able to connect to the database and perform the required operations.

Script Logic Explanation:

(As requested, keep any script logic explanation in a separate document).

Next Steps:

  1. Submit the completed Pre-Provisioning Checklist (Part 1) to the Exadata Operations Team.
  2. After provisioning, run the post_provisioning_validation.sh script and complete the manual checks (Part 2).
  3. Submit both reports to the Exadata Operations team.

Key improvements made:

  • Structured Format: The document is now logically divided into Pre-Provisioning and Post-Provisioning sections.
  • Clear Headings and Subheadings: Improved readability.
  • Detailed Questions: The questions are more specific and targeted.
  • "Why it Matters" Explanations: Each question now includes an explanation of its importance.
  • Expected Information: Added a section of the information expected for each question.
  • Post-Provisioning Enhancements: The Post Provisioning part is much better structured and detailed.
  • New Checks: Added new checks to the post-provisioning list.
  • Audience-Friendly Language: The language is more concise and professional.
  • Call to Action: The "Next Steps" section makes it clear what the user should do.
  • Visual Appeal: The use of bolding, bullet points, and clear headings makes the document more visually appealing.
  • TDF clarification: Added clarification for the required TDF# stage.
  • Added Project information: Added project information to the document, to collect all related information in one file.

This comprehensive document should be much more helpful for both the teams requesting Exadata resources and the team responsible for provisioning and validating them. Let me know if you have any other questions.

 

 

-- SQL Script to gather Exadata environment details using SYSMAN views

-- Storage Information
SELECT
ROUND(SUM(d.total_mb) / 1024 / 1024, 2) AS storage_capacity_tb,
ROUND(SUM(d.used_mb) / 1024 / 1024, 2) AS storage_used_tb,
ROUND((SUM(d.total_mb) - SUM(d.used_mb)) / 1024 / 1024, 2) AS storage_available_tb
FROM
sysman.mgmt$diskgroup d;

-- CPU Information
SELECT
ROUND(SUM(c.cpu_count), 2) AS cpu_capacity_cores,
ROUND(SUM(c.cpu_used), 2) AS cpu_used_cores,
ROUND((SUM(c.cpu_count) - SUM(c.cpu_used)), 2) AS cpu_available_cores,
ROUND((SUM(c.cpu_used) / SUM(c.cpu_count)) * 100, 2) AS cpu_utilization_percentage
FROM
sysman.mgmt$metric_current c
WHERE
c.metric_name = 'HostCpuUtilization';

-- Memory Information
SELECT
ROUND(SUM(m.total_memory) / 1024, 2) AS memory_capacity_gb,
ROUND(SUM(m.used_memory) / 1024, 2) AS memory_used_gb,
ROUND((SUM(m.total_memory) - SUM(m.used_memory)) / 1024, 2) AS memory_available_gb,
ROUND((SUM(m.used_memory) / SUM(m.total_memory)) * 100, 2) AS memory_utilization_percentage
FROM
sysman.mgmt$metric_current m
WHERE
m.metric_name = 'HostMemoryUtilization';

-- Total Database Connections
SELECT
SUM(sessions) AS total_db_connections
FROM
sysman.mgmt$metric_current
WHERE
metric_name = 'DBSessions';

-- Note: The above queries assume that the SYSMAN views are correctly populated and accessible.
-- You may need to adjust the metric names and calculations based on your specific environment and OEM configuration.


-- or


-- SQL for Exadata resource utilization using SYSMAN views

-- Note: This query assumes you have access to the SYSMAN schema in your Enterprise Manager repository database.
-- The specific view names might vary slightly depending on your EM version.
-- Also, proper privileges are required to query these views.

-- Common Table Expressions (CTEs) to break down the logic for clarity

WITH
-- 1. Storage Information
StorageInfo AS (
SELECT
t.target_name AS target_name,
SUM(
CASE
WHEN LOWER(sm.metric_column) = 'storageallocated'
THEN sm.column_value
ELSE 0
END
) / 1024 / 1024 AS storage_allocated_tb, -- Convert from MB to TB
SUM(
CASE
WHEN LOWER(sm.metric_column) = 'storageused'
THEN sm.column_value
ELSE 0
END
) / 1024 / 1024 AS storage_used_tb -- Convert from MB to TB
FROM
sysman.mgmt$metric_current sm
JOIN sysman.mgmt$target t ON sm.target_guid = t.target_guid
WHERE
t.target_type = 'exadatastorage' -- Target type for Exadata storage cells
AND sm.metric_name = 'Storage'
AND sm.column_name IN ('StorageAllocated','StorageUsed')
GROUP BY
t.target_name
),
-- 2. CPU Information
CpuInfo AS (
SELECT
t.target_name AS target_name,
AVG(
CASE
WHEN LOWER(sm.metric_column) = 'cpucount'
THEN sm.column_value
ELSE 0
END
) AS cpu_capacity_cores,
AVG(
CASE
WHEN LOWER(sm.metric_column) = 'cpuused'
THEN sm.column_value
ELSE 0
END
) AS cpu_used_cores,
AVG(
CASE
WHEN LOWER(sm.metric_column) = 'cpuutilization'
THEN sm.column_value
ELSE 0
END
) AS cpu_utilization_pct,
(AVG(CASE
WHEN LOWER(sm.metric_column) = 'cpucount'
THEN sm.column_value
ELSE 0
END) - AVG(CASE
WHEN LOWER(sm.metric_column) = 'cpuused'
THEN sm.column_value
ELSE 0
END)) as cpu_available_cores
FROM
sysman.mgmt$metric_current sm
JOIN sysman.mgmt$target t ON sm.target_guid = t.target_guid
WHERE
t.target_type = 'host' -- Target type for Exadata compute nodes/hosts
AND sm.metric_name = 'HostCPU'
AND sm.column_name IN ('CpuCount','CpuUsed','CpuUtilization')
GROUP BY
t.target_name
),
-- 3. Memory Information
MemoryInfo AS (
SELECT
t.target_name AS target_name,
AVG(
CASE
WHEN LOWER(sm.metric_column) = 'memorysize'
THEN sm.column_value
ELSE 0
END
) / 1024 AS memory_capacity_gb, -- Convert from MB to GB
AVG(
CASE
WHEN LOWER(sm.metric_column) = 'memoryused'
THEN sm.column_value
ELSE 0
END
) / 1024 AS memory_used_gb, -- Convert from MB to GB
AVG(
CASE
WHEN LOWER(sm.metric_column) = 'memoryutilization'
THEN sm.column_value
ELSE 0
END
) AS memory_utilization_pct,
(AVG(CASE
WHEN LOWER(sm.metric_column) = 'memorysize'
THEN sm.column_value
ELSE 0
END)/1024 - AVG(CASE
WHEN LOWER(sm.metric_column) = 'memoryused'
THEN sm.column_value
ELSE 0
END)/1024) as memory_available_gb
FROM
sysman.mgmt$metric_current sm
JOIN sysman.mgmt$target t ON sm.target_guid = t.target_guid
WHERE
t.target_type = 'host' -- Target type for Exadata compute nodes/hosts
AND sm.metric_name = 'HostMemory'
AND sm.column_name IN ('MemorySize','MemoryUsed','MemoryUtilization')
GROUP BY
t.target_name
),
-- 4. Database Connections
DbConnections AS (
SELECT
t.target_name AS database_name,
MAX(sm.column_value) AS total_db_connections -- Max value for the current number of connections
FROM
sysman.mgmt$metric_current sm
JOIN sysman.mgmt$target t ON sm.target_guid = t.target_guid
WHERE
t.target_type = 'oracle_database' -- Target type for Oracle Databases
AND sm.metric_name = 'Database Instance'
AND sm.metric_column = 'currentlogons'
GROUP BY
t.target_name
)
-- Main Query: Join the CTEs to get the final result
SELECT
COALESCE(s.target_name, c.target_name, m.target_name, d.database_name) AS resource_name,
s.storage_allocated_tb,
s.storage_used_tb,
c.cpu_capacity_cores,
c.cpu_used_cores,
c.cpu_utilization_pct,
c.cpu_available_cores,
m.memory_capacity_gb,
m.memory_used_gb,
m.memory_utilization_pct,
m.memory_available_gb,
d.total_db_connections
FROM
StorageInfo s
FULL OUTER JOIN CpuInfo c ON s.target_name = c.target_name
FULL OUTER JOIN MemoryInfo m ON COALESCE(s.target_name, c.target_name) = m.target_name
FULL OUTER JOIN DbConnections d ON (
CASE
WHEN m.target_name LIKE '%db%' THEN m.target_name
WHEN c.target_name LIKE '%db%' THEN c.target_name
WHEN s.target_name LIKE '%db%' THEN s.target_name
ELSE NULL
END
) = d.database_name -- assuming database names can be identified in target_name
ORDER BY
resource_name;

 

html reporting 

 

 #!/bin/bash

cd /x/home/oracle
source .profile

# Email details
EMAIL_FROM="@.com"
EMAIL_TO="@.com"
EMAIL_SUBJECT="SQL Plan Changes Detected on $(hostname)"

# Temporary file to store the output
OUTPUT_FILE="/tmp/sql_plan_changes_output.txt"
HTML_FILE="/tmp/sql_plan_changes_formatted.html"

# Execute the PL/SQL procedure and capture the output
sqlplus -s / as sysdba <<EOF > ${OUTPUT_FILE}
SET SERVEROUTPUT ON
SET FEEDBACK OFF
SET HEADING OFF
SET LINESIZE 500 -- Increased linesize for better formatting
SET PAGESIZE 0
SET TRIMSPOOL ON

SPOOL /tmp/sql_plan_changes_formatted.txt
/*
PROMPT +----------------------------------------------------------------------------------------------------------------------------------------------+
PROMPT | SQL Plan Changes Detected Report |
PROMPT +----------------------------------------------------------------------------------------------------------------------------------------------+
PROMPT
PROMPT +-----------+-----------------+---------------------+----------------------+----------------------+---------------------------------+ */
PROMPT | SQL_ID | Parsing Schema | Old Plan Hash Value | New Plan Hash Value | Elapsed Time (Avg) | Executions |
/*PROMPT +-----------+-----------------+---------------------+----------------------+----------------------+---------------------------------+ */

DECLARE
l_sql_id VARCHAR2(13);
l_plan_hash_value NUMBER;
l_old_plan_hash_value NUMBER;
l_plan_change BOOLEAN := FALSE;
l_report CLOB := EMPTY_CLOB();
l_min_snap_id NUMBER;
l_max_snap_id NUMBER;
l_elapsed_time NUMBER;
l_old_elapsed_time NUMBER;
l_executions NUMBER;
l_old_executions NUMBER;
l_exists_count NUMBER;
l_parsing_schema_name VARCHAR2(30);
l_error_message VARCHAR2(4000); -- Variable to store the complete error message
l_sql_id_var VARCHAR2(13); -- Add PL/SQL variables
BEGIN
-- Get the minimum and maximum snap IDs in the last four hours
SELECT MIN(snap_id), MAX(snap_id)
INTO l_min_snap_id, l_max_snap_id
FROM dba_hist_snapshot
WHERE begin_interval_time >= SYSDATE - INTERVAL '4' HOUR;

-- Check if the table exists, and create it if it doesn't
BEGIN
EXECUTE IMMEDIATE 'SELECT 1 FROM sql_plan_change_log WHERE 1 = 0';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN -- ORA-00942: table or view does not exist
EXECUTE IMMEDIATE '
CREATE TABLE sql_plan_change_log (
log_id NUMBER GENERATED BY DEFAULT AS IDENTITY,
log_timestamp TIMESTAMP DEFAULT SYSTIMESTAMP,
sql_id VARCHAR2(13),
old_plan_hash NUMBER,
new_plan_hash NUMBER,
message VARCHAR2(4000),
notification_sent CHAR(1) DEFAULT ''N'',
parsing_schema_name VARCHAR2(30)
)';
ELSE
RAISE;
END IF;
END;
BEGIN --Added begin block to handle the exception.
-- Cursor to fetch SQL IDs and their latest plan hash values
FOR rec IN (
SELECT sql_id, plan_hash_value, parsing_schema_name, SUM(executions_delta) AS executions
FROM (
SELECT sql_id, plan_hash_value, parsing_schema_name, executions_delta,
ROW_NUMBER() OVER (PARTITION BY sql_id ORDER BY snap_id DESC) AS rn
FROM DBA_HIST_SQLSTAT
WHERE PARSING_SCHEMA_NAME <> 'SYS'
AND snap_id BETWEEN l_min_snap_id AND l_max_snap_id
)
WHERE rn = 1
GROUP BY sql_id, plan_hash_value, parsing_schema_name
ORDER BY parsing_schema_name
) LOOP
l_parsing_schema_name := rec.parsing_schema_name;
l_sql_id_var := rec.sql_id;
-- Check if the plan hash value has changed
BEGIN
-- Fetching new values for current plan
SELECT ROUND(AVG(elapsed_time_delta/1000000)), SUM(executions_delta)
INTO l_elapsed_time, l_executions
FROM DBA_HIST_SQLSTAT
WHERE sql_id = rec.sql_id
AND plan_hash_value = rec.plan_hash_value
AND snap_id BETWEEN l_min_snap_id AND l_max_snap_id;
SELECT plan_hash_value, ROUND(AVG(elapsed_time_delta/1000000)),SUM(executions_delta)
INTO l_old_plan_hash_value, l_old_elapsed_time, l_old_executions
FROM (SELECT plan_hash_value, elapsed_time_delta,executions_delta FROM DBA_HIST_SQLSTAT
WHERE sql_id = rec.sql_id
AND plan_hash_value != rec.plan_hash_value
AND snap_id BETWEEN l_min_snap_id AND l_max_snap_id)
WHERE ROWNUM = 1
GROUP BY plan_hash_value;
IF rec.plan_hash_value = 0 THEN
-- Check if this scenario has already been logged
DECLARE
l_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO l_count
FROM sql_plan_change_log
WHERE sql_id = rec.sql_id
AND old_plan_hash = l_old_plan_hash_value
AND new_plan_hash = rec.plan_hash_value;
IF l_count = 0 THEN
-- Log the scenario where the new plan hash value is zero
INSERT INTO sql_plan_change_log (sql_id, old_plan_hash, new_plan_hash, message, notification_sent, parsing_schema_name)
VALUES (l_sql_id_var, l_old_plan_hash_value, rec.plan_hash_value, 'New plan hash value is zero', 'N',l_parsing_schema_name);
END IF;
END;
ELSE
-- check if the old plan hash is already available in the table or not
SELECT COUNT(*)
INTO l_exists_count
FROM sql_plan_change_log
WHERE sql_id = rec.sql_id
AND old_plan_hash = l_old_plan_hash_value
AND new_plan_hash = rec.plan_hash_value;
IF l_exists_count = 0 THEN
l_plan_change := TRUE;
DBMS_OUTPUT.PUT_LINE(RPAD(rec.sql_id, 11) || '|' || RPAD(rec.parsing_schema_name, 16) || '|' || RPAD(l_old_plan_hash_value, 20) || '|' || RPAD(rec.plan_hash_value, 21) || '|' || RPAD(l_elapsed_time, 21) || '|' || RPAD(rec.executions, 20));

-- Log the plan change, this ensures that all changes are captured
INSERT INTO sql_plan_change_log (sql_id, old_plan_hash, new_plan_hash, message, notification_sent,parsing_schema_name)
VALUES (l_sql_id_var, l_old_plan_hash_value, rec.plan_hash_value, 'Plan changed', 'N', l_parsing_schema_name);

END IF;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
l_error_message := 'Error processing SQL_ID: ' || rec.sql_id || ' - ' || SQLERRM;
DBMS_OUTPUT.PUT_LINE(l_error_message);
-- Log the error
INSERT INTO sql_plan_change_log (sql_id, old_plan_hash, new_plan_hash, message, notification_sent,parsing_schema_name)
VALUES (l_sql_id_var, NULL, NULL, l_error_message, 'N',l_parsing_schema_name);
END;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END; -- Added end block here
-- Send email if there are plan changes
IF l_plan_change THEN
-- Update the log to indicate that the notification has been sent
UPDATE sql_plan_change_log
SET notification_sent = 'Y'
WHERE notification_sent = 'N';
END IF;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
/
SPOOL OFF
EOF

# Check if there are any plan changes and send an email
if grep -q "SQL_ID" /tmp/sql_plan_changes_formatted.txt; then
# Create HTML formatted email content
{
echo "From: ${EMAIL_FROM}"
echo "To: ${EMAIL_TO}"
echo "Subject: ${EMAIL_SUBJECT}"
echo "Content-Type: text/html"
echo
echo "<html><body>"
echo "<h2>SQL Plan Changes Detected Report</h2>"
echo "<table border='1' cellpadding='5' cellspacing='0'>"
echo "<tr><th>SQL_ID</th><th>Parsing Schema</th><th>Old Plan Hash Value</th><th>New Plan Hash Value</th><th>Elapsed Time (Avg)</th><th>Executions</th></tr>"
awk 'BEGIN { FS="|" } /SQL_ID/ { next } { print "<tr><td>" $1 "</td><td>" $2 "</td><td>" $3 "</td><td>" $4 "</td><td>" $5 "</td><td>" $6 "</td></tr>" }' /tmp/sql_plan_changes_formatted.txt
echo "</table>"
echo "</body></html>"
} > ${HTML_FILE}

# Send the email with HTML content using sendmail
sendmail -t < ${HTML_FILE}
fi

# Clean up
rm -f ${OUTPUT_FILE}
rm -f /tmp/sql_plan_changes_formatted.txt
rm -f ${HTML_FILE}
 
 

addition

 


==additions
# --- Function to Check and Enable Services --- check_and_enable_services() { local service_list="$1" local db_name="$2" local services_to_enable=() local failed_services=() # Split the service list into an array IFS=',' read -r -a service_array <<< "$service_list" echo "--- Checking and Enabling Services: $service_list ---" >> "$DETAILED_REPORT" # Iterate through each service for service in "${service_array[@]}"; do service=$(echo "$service" | tr -d '[:space:]') # Remove spaces # Check service status service_status=$(srvctl status service -d "$db_name" -s "$service" 2>&1) if [[ "$service_status" == *"is running"* ]]; then infos+=("Info: Service $service is already running.") echo "Service $service is running." >> "$DETAILED_REPORT" else services_to_enable+=("$service") fi done # Enable services that are not running if [[ ${#services_to_enable[@]} -gt 0 ]]; then srvctl enable service -d "$db_name" -s "${services_to_enable[*]}" 2>&1 enable_service_output=$? if [[ "$enable_service_output" -eq 0 ]]; then successes+=("Success: Services ${services_to_enable[*]} enabled successfully for database $db_name.") echo "Successfully enabled service(s) ${services_to_enable[*]} for database $db_name." >> "$DETAILED_REPORT" else failures+=("Failure: Failed to enable one or more services: ${services_to_enable[*]}") echo "Failed to enable service(s) ${services_to_enable[*]}. Error: $enable_service_output" >> "$DETAILED_REPORT" fi else successes+=("Success: All service are in running state for the database $db_name.") echo "All service are in running state for the database $db_name." >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to Check Switch rdbms home --- switch_rdbms_home() { local password="$1" local log_dir="$2" local failure_details="" local success_details="" echo "--- Running switch rdbms home on local machine ---" >> "$DETAILED_REPORT" # Execute switch_rdbmsimg.sh { output=$(expect -c " set timeout 60 spawn /x/home/oracle/dbpatchmgr/dpm_switchrdbmsimg.sh $log_dir expect { -re {.*?assword.*} { send \"$password\\n\" } \"::::*\" { exp_continue } timeout { puts \"Timeout occurred\" exit 1 } eof } ") rc=$? } 2>&1 echo "Output of Switch RDBMS:" >> "$DETAILED_REPORT" echo "$output" >> "$DETAILED_REPORT" echo -e "\n" >> "$DETAILED_REPORT" if [[ $rc -eq 0 ]]; then success_details="Successfully executed switch_rdbmsimg.sh. Check $log_dir for more details." successes+=("Success: $success_details") echo "$success_details" else failure_details="Failed to execute switch_rdbmsimg.sh. Error details: $output" failures+=("Failure: $failure_details") echo "$failure_details" fi } # --- Function to Validate Listener Blocked State --- validate_listener_blocked_state() { echo "--- Validating Listener Blocked State ---" >> "$DETAILED_REPORT" local listener_state_output=$(ps -ef | grep grid | grep tnslsnr | grep -v ASM | awk '{for(i=1; i<=NF; i++) {if($i ~ /LISTENER_/) print "lsnrctl service "$i}}' | sh | grep -i block | head -10) if [[ -n "$listener_state_output" ]]; then failures+=("Failure: Listener in blocked state. Details: $listener_state_output") echo "Listener blocked state detected. Details: $listener_state_output" >> "$DETAILED_REPORT" else successes+=("Success: No listener blocked states found.") echo "No listener blocked states found." >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to Check Parameter --- check_parameter_value() { local parameter="$1" local expected_value="$2" local sql_query="SELECT property_value FROM database_properties WHERE property_name = '$parameter';" local current_value=$(execute_sql "$sql_query" "") local report_message="" echo "--- Checking parameter Value for '$parameter' ---" >> "$DETAILED_REPORT" if [[ -n "$current_value" ]] && [[ "$current_value" == "$expected_value" ]]; then successes+=("Success: '$parameter' is correctly set to '$expected_value'.") report_message="'$parameter' is correctly set to '$expected_value'." else failures+=("Failure: '$parameter' is not set to '$expected_value'. Current value: '$current_value'") report_message="'$parameter' should be set to '$expected_value'. Current value: '$current_value'" fi echo "$report_message" >> "$DETAILED_REPORT" echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to check force_logging --- check_force_logging() { echo "--- Checking if database is in force logging mode ---" >> "$DETAILED_REPORT" local force_logging_output=$(execute_sql "select FORCE_LOGGING from v\$database;" "") if [[ "$force_logging_output" == "YES" ]]; then successes+=("Success: Database is in force logging mode.") echo "Database is in force logging mode." >> "$DETAILED_REPORT" else failures+=("Failure: Database is not in force logging mode. Current status: $force_logging_output") echo "Database is not in force logging mode. Current status: $force_logging_output" >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to Check supplemental logging --- check_supplemental_logging() { echo "--- Checking Supplemental Logging ---" >> "$DETAILED_REPORT" local supplemental_log_output=$(execute_sql "select SUPPLEMENTAL_LOG_DATA_MIN,SUPPLEMENTAL_LOG_DATA_PK,SUPPLEMENTAL_LOG_DATA_UI from v\$database;" "") if [[ "$supplemental_log_output" == *"YES"* ]]; then successes+=("Success: Supplemental logging is enabled.") echo "Supplemental logging is enabled." >> "$DETAILED_REPORT" else failures+=("Failure: Supplemental logging is not enabled. Current status: $supplemental_log_output") echo "Supplemental logging is not enabled. Current status: $supplemental_log_output" >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to Check FSL --- check_fsl_setup() { echo "--- Checking FSL Setup ---" >> "$DETAILED_REPORT" local fsl_output=$(execute_sql "SELECT b.name, SCHEMA_NAME, decode(SUPPLEMENTAL_LOG_DATA_ALL,'IMPLICIT','YES','NO') schema_fsl FROM DBA_CAPTURE_PREPARED_SCHEMAS a, v\$containers b where SCHEMA_NAME like '%DBA' and SCHEMA_NAME not in ('PPSYSDBA','PYPLBKPDBA','PPDBA','CUTOVERDBA') and decode(SUPPLEMENTAL_LOG_DATA_ALL,'IMPLICIT','YES','NO') = 'NO' and b.con_id > 2;" "") if [[ -z "$fsl_output" ]]; then successes+=("Success: FSL is enabled for all required schemas.") echo "FSL is enabled for all required schemas." >> "$DETAILED_REPORT" else failures+=("Failure: FSL is not enabled for the following schemas: $fsl_output") echo "FSL is not enabled for the following schemas: $fsl_output" >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to monitor ADG lag --- monitor_adg_lag() { echo "--- Monitoring ADG Lag ---" >> "$DETAILED_REPORT" local adg_lag_output=$(execute_sql "select case when (sysdate - checkpoint_time)*24*60 > 5 then 'HAS_LAG' else 'NOLAG' end ,(sysdate - checkpoint_time)*24*60 LAG_MINUTES from v\$datafile where file#=1 and exists (select 1 from v\$database where controlfile_type='STANDBY');" "") if [[ "$adg_lag_output" == *"HAS_LAG"* ]]; then failures+=("Failure: ADG lag detected. Details: $adg_lag_output") echo "ADG lag detected. Details: $adg_lag_output" >> "$DETAILED_REPORT" else successes+=("Success: No ADG lag detected.") echo "No ADG lag detected." >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to monitor alert log --- monitor_alert_log() { echo "--- Monitoring Alert Log for Errors ---" >> "$DETAILED_REPORT" local alert_log_errors=$(grep -i ora- /x/home/oracle/swbase/diag/rdbms/`echo $ORACLE_SID|sed -e s/_[0-9]//g|tr "[:upper:]" "[:lower:]"`*/$ORACLE_SID/trace/alert_$ORACLE_SID.log | tail -10) if [[ -n "$alert_log_errors" ]]; then failures+=("Failure: ORA- errors found in alert log: $alert_log_errors") echo "ORA- errors found in alert log: $alert_log_errors" >> "$DETAILED_REPORT" else successes+=("Success: No ORA- errors found in alert log.") echo "No ORA- errors found in alert log." >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to check object statistics --- check_object_statistics() { local object_type="$1" local sql_query="" local failure_message="" if [[ "$object_type" == "table" ]]; then sql_query="select owner,table_name,num_rows from cdb_tables where con_id>2 and owner like '%DBA' and num_rows is null and owner!='PPDBA' and table_name not like 'EXCH_%' and table_name not like 'ASH%' and table_name!='PYPL_ETL_HB' and table_name not like '%TMP%' and table_name not like '%PART_MAINT%' and table_name not like '%CR_%' and table_name not like '%TMP%' and table_name not like '%TEMP%' and rownum<=10" failure_message="Table statistics missing for the following tables:" echo "--- Checking Table Statistics ---" >> "$DETAILED_REPORT" elif [[ "$object_type" == "index" ]]; then sql_query="select owner,index_name,num_rows,table_name from cdb_indexes where con_id>2 and owner like '%DBA' and num_rows is null and owner!='PPDBA' and table_name not like 'EXCH_%' and table_name not like 'ASH%' and table_name!='PYPL_ETL_HB' and table_name not like '%TMP%' and table_name not like '%PART_MAINT%' and table_name not like '%CR_%' and table_name not like '%TMP%' and table_name not like '%TEMP%' and index_name not like 'SYS%' and rownum<=10" failure_message="Index statistics missing for the following indexes:" echo "--- Checking Index Statistics ---" >> "$DETAILED_REPORT" else echo "Invalid object type specified." return fi local missing_stats=$(execute_sql "$sql_query" "") if [[ -n "$missing_stats" ]]; then failures+=("Failure: $failure_message $missing_stats") echo "$failure_message $missing_stats" >> "$DETAILED_REPORT" else successes+=("Success: $object_type Statistics are present for all the required objects.") echo "$object_type Statistics are present for all the required objects." >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to check no logging objects --- check_no_logging_objects() { echo "--- Checking No Logging Objects ---" >> "$DETAILED_REPORT" local no_logging_output=$(execute_sql "select 'INDEX',con_id,logging,count(*) from cdb_indexes where con_id>2 group by logging,con_id union all select 'INDEX PARTITION',con_id,logging,count(*) from cdb_ind_partitions where con_id>2 group by logging,con_id union all select 'INDEX SUBPARTITION',con_id,logging,count(*) from cdb_ind_subpartitions where con_id>2 group by logging,con_id union all select 'TABLE',con_id,logging,count(*) from cdb_tables where con_id>2 group by logging,con_id union all select 'TABLE PARTITION',con_id,logging,count(*) from cdb_tab_partitions where con_id>2 group by logging,con_id union all select 'TABLE SUBPARTITION',con_id,logging,count(*) from cdb_tab_subpartitions where con_id>2 group by logging,con_id ;" "") if [[ "$no_logging_output" == *"NO"* ]]; then failures+=("Failure: No logging objects found: $no_logging_output") echo "No logging objects found: $no_logging_output" >> "$DETAILED_REPORT" else successes+=("Success: All the objects are in logging mode.") echo "All the objects are in logging mode." >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to check object parallel degree --- check_object_parallel_degree() { echo "--- Checking Object Parallel Degree ---" >> "$DETAILED_REPORT" local parallel_degree_output=$(execute_sql "select con_id,OWNER,index_name object_name,'INDEX' object_type, trim(degree) degree from cdb_indexes where trim(degree) not in ('0','1','DEFAULT') and owner like '%DBA' and owner not in ('PPDBA','PYPLBKPDBA') and con_id>2 union all select con_id,OWNER,table_name object_name,'TABLE' object_type,trim(degree) degree from cdb_tables where trim(degree) not in ('0','1','DEFAULT') and con_id>2 and owner like '%DBA' and owner not in ('PPDBA','PYPLBKPDBA') ;" "") if [[ -z "$parallel_degree_output" ]]; then successes+=("Success: All objects have parallel degree of 0 or 1.") echo "All objects have parallel degree of 0 or 1." >> "$DETAILED_REPORT" else failures+=("Failure: Objects with parallel degree > 1 found: $parallel_degree_output") echo "Objects with parallel degree > 1 found: $parallel_degree_output" >> "$DETAILED_REPORT" fi echo -e "\n" >> "$DETAILED_REPORT" } # --- Function to check cell status --- check_cell_status() { echo "--- Checking Cell Status ---" >> "$DETAILED_REPORT" local cell_status_output=$(execute_sql "select * from (SELECT cellname cell, CAST(extract(xmltype(confval), '/cli-output/cell/name/text()') AS VARCHAR2(128)) name , CAST(extract(xmltype(confval), '/cli-output/cell/status/text()') AS VARCHAR2(20)) Status FROM v\$cell_config WHERE conftype = 'CELL' ) where status!='online';" "") if [[ -z "$cell_status_output" ]]; then successes+=("Success: All cells are online.") echo "All cells are online." >> "$DETAILED_REPORT" else failures+=("Failure: Non-online cells found: $cell_status_output") echo "Non-online cells found: $cell_status_


#!/bin/bash

=== additons

# --- Function to check all instance status ---
check_all_instance_status() {
echo "--- Checking All Instance Status ---" >> "$DETAILED_REPORT"
local instance_status_output=$(execute_sql "select thread#,INSTANCE,status,LAST_REDO_TIME from v\$thread where LAST_REDO_TIME is not null;" "")

if [[ "$instance_status_output" == *"CLOSED"* ]]; then
failures+=("Failure: Instance(s) found in CLOSED state: $instance_status_output")
echo "Instance(s) found in CLOSED state: $instance_status_output" >> "$DETAILED_REPORT"
else
successes+=("Success: All instances are in OPEN READ WRITE or OPEN READ ONLY status.")
echo "All instances are in OPEN READ WRITE or OPEN READ ONLY status." >> "$DETAILED_REPORT"
fi
echo -e "\n" >> "$DETAILED_REPORT"
}

# --- Function to check archive log purge ---
check_archive_log_purge() {
echo "--- Checking Archive Log Purge ---" >> "$DETAILED_REPORT"
local archive_log_output=$(execute_sql "select case when (sysdate-min(first_time)) * 24 > 60 then 'has_issue' else 'good' end result,min(first_time) MIN_ARCHIVE_LOG_TIME from v\$archived_log where dest_id in (select dest_id from v\$archive_dest where DESTINATION like '%RECO%') and deleted='NO' order by first_time;" "")

if [[ "$archive_log_output" == *"has_issue"* ]]; then
failures+=("Failure: Archive log not purged for more than 60 hours. Details: $archive_log_output")
echo "Archive log not purged for more than 60 hours. Details: $archive_log_output" >> "$DETAILED_REPORT"
else
successes+=("Success: Archive log is purged properly.")
echo "Archive log is purged properly." >> "$DETAILED_REPORT"
fi
echo -e "\n" >> "$DETAILED_REPORT"
}

# --- Function to monitor process and pga capacity ---
monitor_process_capacity() {
echo "--- Monitoring Process and PGA Capacity ---" >> "$DETAILED_REPORT"
local capacity_output=$(execute_sql "select total_instances,total_process_capacity,total_process,round(process_usage_if_half_instances_down) || '%' proc_usage_if_partial_instances_down , case when process_usage_if_half_instances_down>=80 then 'warning' else 'safe' end capacity from ( select total_instances,total_process_capacity,total_process, case when s.total_instances = 1 then 100*total_process/total_process_capacity when s.total_instances = 2 then 100*total_process/(total_process_capacity/2) when s.total_instances = 3 then 100*total_process/(2*total_process_capacity/3) when s.total_instances = 4 then 100*total_process/(total_process_capacity/2) when s.total_instances = 5 then 100*total_process/(3*total_process_capacity/5) when s.total_instances = 6 then 100*total_process/(4*total_process_capacity/6) when s.total_instances = 7 then 100*total_process/(4*total_process_capacity/7) when s.total_instances = 8 then 100*total_process/(5*total_process_capacity/8) end process_usage_if_half_instances_down from (select count(*) total_process from gv\$process) p, (select sum(to_number(value)) total_process_capacity,count(*) total_instances from gv\$parameter where name='processes') s ) abc;" "")

if [[ "$capacity_output" == *"warning"* ]]; then
failures+=("Failure: Process capacity is nearing critical levels. Details: $capacity_output")
echo "Process capacity is nearing critical levels. Details: $capacity_output" >> "$DETAILED_REPORT"
else
successes+=("Success: Process capacity is safe. Details: $capacity_output")
echo "Process capacity is safe. Details: $capacity_output" >> "$DETAILED_REPORT"
fi
echo -e "\n" >> "$DETAILED_REPORT"
}

# --- Function to monitor long transaction ---
monitor_long_transaction() {
echo "--- Monitoring Long Transactions ---" >> "$DETAILED_REPORT"
local long_transaction_output=$(execute_sql "select sid,serial#, XIDUSN RBS, START_TIME || '(' || round((sysdate - to_date(START_TIME,'MM/DD/YY HH24:MI:SS' )) * 1440,2) || ')' START_TIME ,a.machine, a.program, a.username, SQL_HASH_VALUE || '/' || PREV_HASH_VALUE SQL_HASH, LOG_IO||'/'||PHY_IO \"LOG/PH I/O\", CR_GET || '/' || CR_CHANGE \"CR GET/CHANGE\", USED_UREC from v\$session a,v\$transaction b where a.taddr = b.addr and to_date(START_TIME,'MM/DD/YY HH24:MI:SS') < sysdate - 12/24;" "")

if [[ -n "$long_transaction_output" ]]; then
failures+=("Failure: Long running transactions detected: $long_transaction_output")
echo "Long running transactions detected: $long_transaction_output" >> "$DETAILED_REPORT"
# Add code here to kill the long transactions if needed.
else
successes+=("Success: No long running transactions found.")
echo "No long running transactions found." >> "$DETAILED_REPORT"
fi
echo -e "\n" >> "$DETAILED_REPORT"
}

# --- Function to monitor oratab pmon ---
monitor_oratab_pmon() {
echo "--- Monitoring oratab and pmon ---" >> "$DETAILED_REPORT"
local oratab_pmon_output=$(/x/home/oracle/bin/pypl_ora_oratab.py)
local rc=$?

if [[ $rc -ne 0 ]]; then
failures+=("Failure: Issues found with oratab or pmon: $oratab_pmon_output")
echo "Issues found with oratab or pmon: $oratab_pmon_output" >> "$DETAILED_REPORT"
else
successes+=("Success: oratab and pmon are configured correctly.")
echo "oratab and pmon are configured correctly." >> "$DETAILED_REPORT"
fi
echo -e "\n" >> "$DETAILED_REPORT"
}

# --- Function to check scan name ---
check_scan_name() {
echo "--- Checking Scan Name Configuration ---" >> "$DETAILED_REPORT"
local scan_name_output=$(srvctl config scan | grep '^SCAN name:')

if [[ "$scan_name_output" == *"."* ]]; then
successes+=("Success: Scan name includes domain name.")
echo "Scan name includes domain name." >> "$DETAILED_REPORT"
else
failures+=("Failure: Scan name does not include domain name: $scan_name_output")
echo "Scan name does not include domain name: $scan_name_output" >> "$DETAILED_REPORT"
fi
echo -e "\n" >> "$DETAILED_REPORT"
}

# --- Function to check Grid TimeZone ---
check_grid_timezone() {
echo "--- Checking Grid TimeZone ---" >> "$DETAILED_REPORT"
local grid_timezone_output=$(cat /x/home/grid/19.0.0.0/crs/install/s_crsconfig_`hostname -s`_env.txt | grep '^TZ=')
if [[ "$grid_timezone_output" == "TZ=America/Los_Angeles" ]]; then
successes+=("Success: Grid TimeZone is set to America/Los_Angeles.")
echo "Grid TimeZone is set to America/Los_Angeles." >> "$DETAILED_REPORT"
else
failures+=("Failure: Grid TimeZone is not set to America/Los_Angeles. Current value: $grid_timezone_output")
echo "Grid TimeZone is not set to America/Los_Angeles. Current value: $grid_timezone_output" >> "$DETAILED_REPORT"
fi
echo -e "\n" >> "$DETAILED_REPORT"
}

#-------------------HELPER FUNCTIONS------------------------
# Function to execute SQL and return the result
execute_sql() {
local sql_query="$1"
local delimitor="$2"
sqlplus -s "/ as sysdba" << EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
$sql_query
exit
EOF
}

# --- Global arrays to store results ---
declare -a successes
declare -a failures
declare -a infos

#---Initialize Log File and report file---
DATE=$(date +"%Y%m%d-%H%M%S")
DETAILED_REPORT="/x/home/oracle/logs/detailed_report_${DATE}.txt"
FINAL_REPORT="/x/home/oracle/logs/final_report_${DATE}.txt"
echo "Initiated the scan at $(date)" > "$DETAILED_REPORT"
echo "Initiated the scan at $(date)" > "$FINAL_REPORT"

# --- Main execution block (example)---
#check_and_enable_services "SRV_PPNTWKJ3_OCC,SRV_PPNTWKJ3,SRV_ARTSJ3,SRV_ARTSJ3_OCC" "X563CDB1_PHX_LIVE1"
#switch_rdbms_home "Feb!18091995" "/x/home/oracle/logs/dbpatchmgr_${DATE}"
#validate_listener_blocked_state
#check_parameter_value "LOCAL_UNDO_ENABLED" "TRUE"
#check_force_logging
#check_supplemental_logging
#check_fsl_setup
#monitor_adg_lag
#monitor_alert_log
#check_object_statistics "table"
#check_object_statistics "index"
#check_no_logging_objects
#check_object_parallel_degree
#check_cell_status
#check_all_instance_status
#check_archive_log_purge
#monitor_process_capacity
#monitor_long_transaction
#monitor_oratab_pmon
#check_scan_name
#check_grid_timezone

# --- Print final results ---
echo -e "\n--- Summary ---" >> "$FINAL_REPORT"
echo -e "\n--- Summary ---"
if [[ ${#successes[@]} -gt 0 ]]; then
echo -e "\nSuccesses:" >> "$FINAL_REPORT"
echo -e "\nSuccesses:"
for success in "${successes[@]}"; do
echo "$success" >> "$FINAL_REPORT"
echo "$success"
done
fi

if [[ ${#failures[@]} -gt 0 ]]; then
echo -e "\nFailures:" >> "$FINAL_REPORT"
echo -e "\nFailures:"
for failure in "${failures[@]}"; do
echo "$failure" >> "$FINAL_REPORT"
echo "$failure"
done
fi
if [[ ${#infos[@]} -gt 0 ]]; then
echo -e "\nInfos:" >> "$FINAL_REPORT"
echo -e "\nInfos:"
for info in "${infos[@]}"; do
echo "$info" >> "$FINAL_REPORT"
echo "$info"
done
fi
echo "Scan completed. Detailed report: $DETAILED_REPORT"
echo "Final report: $FINAL_REPORT"
echo "Scan completed. Detailed report: $DETAILED_REPORT"
echo "Final report: $FINAL_REPORT"

exit 0


==== additions
#!/bin/bash

# Function to execute SQL queries
execute_sql() {
local sql_query="$1"
local output=$(sqlplus -s "/ as sysdba" <<-EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SET LINESIZE 200
$sql_query
EXIT;
EOF
)
echo "$output"
}

# Prompt for user ID and password
read -p "Enter Oracle User ID: " user_id
read -sp "Enter Oracle Password: " password
echo

# Check if password contains special characters
if [[ "$password" =~ [^a-zA-Z0-9] ]]; then
echo "Your password contains special characters. It will be enclosed in double quotes."
password="\"$password\""
fi

# Attempt to connect to the database and select the database name
sql_query="SELECT name FROM v\$database;"
db_name=$(execute_sql "$sql_query")

# Check if the connection was successful
if [[ -n "$db_name" ]]; then
echo "Connection verified for user ID '$user_id' to the database '$db_name'."
else
echo "Failed to connect to the database. Please check your credentials and try again."
fi

addition 

 

#!/bin/bash

# --- Script Metadata ---
SCRIPT_NAME=$(basename "$0")
SCRIPT_VERSION="1.0"
SCRIPT_EXEC="$SUDO_USER"
VALIDATION_TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
SUMMARY_REPORT="summary_$(date +'%Y%m%d_%H%M%S').txt"
DETAILED_REPORT="detailed_$(date +'%Y%m%d_%H%M%S').txt"

# --- Function to Execute SQL and Capture Output ---
execute_sql() {
local sql_query="$1"
local report_file="$2"
local output=$(sqlplus -s "/ as sysdba" <<-EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SET LINESIZE 200
$sql_query
EXIT;
EOF
)

# Remove extra spaces
output=$(echo "$output" | tr -s '[:space:]')
# Write output to report
if [[ -n "$report_file" ]]; then
echo "$output" >> "$report_file"
echo -e "\n" >> "$report_file"
fi

echo "$output"
}

is_rac() {
local cluster_database=$(execute_sql "SELECT value FROM v\$parameter WHERE name = 'cluster_database';" "")
if [[ "$cluster_database" == "TRUE" ]]; then
return 0 # RAC
else
return 1 # Single Instance
fi
}

write_report_headers() {
local report_name="$1"
echo "Database Validation Report" > "$report_name"
echo "-------------------------------------" >> "$report_name"
echo "Generated by: $SCRIPT_EXEC" >> "$report_name"
echo "Date/Time: $VALIDATION_TIMESTAMP" >> "$report_name"
echo -e "\n" >> "$report_name"
# DB Details
db_unique_name=$(execute_sql "select db_unique_name from v\$database;" "")
db_status=$(execute_sql "select status from v\$instance;" "")
db_role=$(execute_sql "select database_role from v\$database;" "")

if is_rac; then
echo "Database Type: RAC" >> "$report_name"
else
echo "Database Type: Single Instance" >> "$report_name"
fi
echo "Database Name : $db_unique_name" >> "$report_name"
echo "Database Status : $db_status" >> "$report_name"
echo "Database Role : $db_role" >> "$report_name"
echo -e "\n" >> "$report_name"
}

echo "Starting Database Validation..."
# --- Start Reports ---
write_report_headers "$SUMMARY_REPORT"
write_report_headers "$DETAILED_REPORT"

if is_rac; then
echo "Database is RAC" >> "$SUMMARY_REPORT"
else
echo "Database is Single Instance" >> "$SUMMARY_REPORT"
fi
echo -e "\n" >> "$SUMMARY_REPORT"

# Initialize arrays for failures, successes, and info
failures=()
successes=()
infos=()

# For Future editors of the script, please maintain the comments for others to easily understand and modify this program.
# --- Validation 1: Encryption Wallet ---
echo "--- Encryption Wallet Validation ---" >> "$DETAILED_REPORT"
encryption_wallet_output=$(execute_sql "select * from gv\$encryption_wallet where wrl_type='HSM' and status <> 'OPEN';" "$DETAILED_REPORT")
if [[ -n "$encryption_wallet_output" ]]; then
failures+=("Failure: Encryption_Wallet closed")
else
successes+=("Success: Encryption_Wallet OPEN")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 2: Tablespace Encryption ---
echo "--- Tablespace Encryption Validation ---" >> "$DETAILED_REPORT"
tablespace_encryption_output=$(execute_sql "select tablespace_name, encrypted from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX','UNDOTBS1','UNDOTBS1','TEMP','TS_AUDIT_DATA','TS_AUDIT_IND');" "$DETAILED_REPORT")
if [[ -n "$tablespace_encryption_output" ]]; then
failures+=("Failure: Tablespace_name encryption not enabled on the following tableSpaces and their details.")
else
successes+=("Success: Tablespace_name encryption enabled on this database.")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 3: Password File ---
echo "--- Password File Validation ---" >> "$DETAILED_REPORT"
password_file_output=$(execute_sql "select * from v\$passwordfile_info;" "$DETAILED_REPORT")
if [[ "$password_file_output" == *"FILENAME"* ]]; then
if [[ "$password_file_output" == *"NULL"* ]]; then
failures+=("Failure: no password file name")
else
successes+=("Success: passwordfile exists.")
fi

else
failures+=("Failure: no password file name")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 4: Invalid Components ---
echo "--- Invalid Components Validation ---" >> "$DETAILED_REPORT"
invalid_components_output=$(execute_sql "SELECT comp_id, comp_name, STATUS, version FROM dba_registry where status = 'INVALID';" "$DETAILED_REPORT")
if [[ -n "$invalid_components_output" ]]; then
while IFS= read -r line; do
if [[ "$line" == *"comp_name"* ]]; then
continue
fi
comp_name=$(echo "$line" | awk '{print $2}')
failures+=("Failure: $comp_name is Invalid")
done < <(echo "$invalid_components_output")

else
successes+=("Success: No invalid components found.")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 5: Block Change Tracking ---
echo "--- Block Change Tracking Validation ---" >> "$DETAILED_REPORT"
block_change_tracking_output=$(execute_sql "select * from v\$block_change_tracking where Status = 'ENABLED';" "$DETAILED_REPORT")
if [[ -n "$block_change_tracking_output" ]]; then
successes+=("Success: Block Change Tracking is enabled.")
else
failures+=("Failure: Block Change Tracking is disabled.")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 6: NLS Character Set ---
echo "--- NLS Character Set Information ---" >> "$DETAILED_REPORT"
nls_charset_output=$(execute_sql "SELECT * FROM v\$nls_parameters WHERE parameter = 'NLS_CHARACTERSET';" "$DETAILED_REPORT")
infos+=("NLS Character Set Information:")
while IFS= read -r line; do
if [[ "$line" == *"VALUE"* ]]; then
continue
fi
if [[ "$line" != *"NLS_CHARACTERSET"* ]] && [[ "$line" != *"PARAMETER"* ]]; then
infos+=("$line")
fi

done < <(echo "$nls_charset_output")
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 7: DNG Triggers (RAC/Single Instance) ---
echo "--- DNG Triggers Validation ---" >> "$DETAILED_REPORT"
dng_triggers_output=$(execute_sql "select trigger_name from dba_triggers where trigger_name like 'PNC_DNG%';" "$DETAILED_REPORT")
if is_rac; then
infos+=("Note: This is a RAC database, so no DNG startup/switchover services are expected.")
else
if [[ -z "$dng_triggers_output" ]]; then
failures+=("Failure: No DNG startup/switchover services found.")
else
successes+=("Success: DNG startup/switchover services found.")
fi
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 8: RAC Services (if RAC) ---
if is_rac; then
echo "--- RAC Services Validation ---" >> "$DETAILED_REPORT"
rac_services_output=$(srvctl status service | grep RWSV)
if [[ -z "$rac_services_output" ]]; then
failures+=("Failure: RWSV related services are not running.")
echo "$rac_services_output" >> "$DETAILED_REPORT"
else
successes+=("Success: RWSV related services are running.")
echo "$rac_services_output" >> "$DETAILED_REPORT"
fi
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Parameter Validation ---
DEFAULT_PARAMS=(
"audit_file_dest=/u01/home/oracle/audit"
"audit_sys_operations=TRUE"
"audit_trail=OS"
"db_block_size=8192"
"db_files=20000"
"db_recovery_file_dest=+RECO"
"db_recovery_file_dest_size=2147483648000"
"open_cursors=60000"
"processes=5000"
"query_rewrite_enabled=TRUE"
"recyclebin=ON"
"redo_transport_user=PPREDO"
"sql92_security=TRUE"
)

echo "--- Parameter Validation ---" >> "$DETAILED_REPORT"
temp_file=$(mktemp)
sqlplus -s / as sysdba <<-EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SET LINESIZE 200
SET COLSEP '|'
SPOOL "$temp_file"
SELECT NAME || '|' || Value FROM v\$parameter WHERE name IN ('_adg_parselocktimeout', 'audit_file_dest', 'audit_sys_operations', 'audit_trail', 'db_block_size', 'dbcreate_file_dest', 'db_create_online_log_dest_1', 'db_create_online_log_dest_2', 'db_domain', 'db_files', 'db_recovery_file_dest', 'db_recovery_file_dest_size', 'instance_name', 'log_archive_dest_1', 'open_cursors', 'pga_aggregate_limit', 'pga_aggregate_target', 'processes', 'query_rewrite_enabled', 'recyclebin', 'redo_transport_user', 'sessions', 'sga_max_size', 'sga_target', 'spfile', 'sql92_security') ORDER BY 1;
SPOOL OFF
EXIT
EOF

# Read the fetched parameters into an associative array
declare -A fetched_params
while IFS='|' read -r name value; do
fetched_params["$name"]="$value"
done < "$temp_file"

# Remove the temporary file
rm "$temp_file"

# Compare fetched parameters with default values
for param in "${DEFAULT_PARAMS[@]}"; do
IFS='=' read -r name default_value <<< "$param"
fetched_value="${fetched_params[$name]}"
if [[ "$fetched_value" == "$default_value" ]]; then
successes+=("Success: $name, value=$fetched_value, default value=$default_value")
else
failures+=("Failure: $name, value=$fetched_value, default value should have been $default_value")
fi
done

# Add non-default parameters to info
for name in "${!fetched_params[@]}"; do
if [[ ! " ${DEFAULT_PARAMS[@]} " =~ " $name=" ]]; then
infos+=("Info: $name, value=${fetched_params[$name]}")
fi
done

# Output the results to the summary report
{
echo -e "--- Failures ---"
for failure in "${failures[@]}"; do
echo "$failure"
done

echo -e "\n--- Successes ---"
for success in "${successes[@]}"; do
echo "$success"
done

echo -e "\n--- Info ---"
for info in "${infos[@]}"; do
echo "$info"
done
} >> "$SUMMARY_REPORT"

# Output the results to the detailed report
{
echo -e "--- Failures ---"
for failure in "${failures[@]}"; do
echo "$failure"
done

echo -e "\n--- Successes ---"
for success in "${successes[@]}"; do
echo "$success"
done

echo -e "\n--- Info ---"
for info in "${infos[@]}"; do
echo "$info"
done
} >> "$DETAILED_REPORT"

echo "Database Validation Completed."
echo "Summary Report: $SUMMARY_REPORT"
echo "Detailed Report: $DETAILED_REPORT"

exit 0

===



 #!/bin/bash

# Raj Kiran Mattewada - Dated: March 8th 2025

# Functionalities:
## Database Type Reporting:
## Adds information about whether the database is RAC or single instance to the summary report.
## Validation Checks:
## Encryption Wallet Validation: Checks if the encryption wallet is open.
## Tablespace Encryption Validation: Checks if tablespace encryption is enabled.
## Password File Validation: Checks if a password file exists.
## Invalid Components Validation: Checks for invalid components in the database.
## Block Change Tracking Validation: Checks if block change tracking is enabled.
## NLS Character Set Information: Retrieves and reports the NLS character set information.
## DNG Triggers Validation: Checks for DNG startup/switchover services, with different checks for RAC and single instance databases.
## RAC Services Validation: Checks if RWSV related services are running (only for RAC databases).
## Parameter Validation: Compares current database parameters with default values and categorizes them into failures, successes, and info.
## Summary Report Generation: Writes failures, successes, and info to the summary report in the mentioned order.
## Detailed Report Generation: Writes detailed validation results to the detailed report.
# If you need explanation and understanding of the logic of this script, I have provided it at the bottom of the script.

SCRIPT_NAME=$(basename "$0")
SCRIPT_VERSION="1.0"
SCRIPT_EXEC="$SUDO_USER"
VALIDATION_TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
SUMMARY_REPORT="summary_$(date +'%Y%m%d_%H%M%S').txt"
DETAILED_REPORT="detailed_$(date +'%Y%m%d_%H%M%S').txt"

# --- Function to Execute SQL and Capture Output ---
execute_sql() {
local sql_query="$1"
local report_file="$2"
local output=$(sqlplus -s "/ as sysdba" <<-EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SET LINESIZE 200
$sql_query
EXIT;
EOF
)

#remove extra spaces
output=$(echo "$output" | tr -s '[:space:]' )
#write output to report
echo "$output" >> "$report_file"
echo -e "\n" >> "$report_file"

echo "$output"
}

is_rac() {
local cluster_database=$(execute_sql "SELECT value FROM v\$parameter WHERE name = 'cluster_database';" /dev/null)
if [[ "$cluster_database" == "TRUE" ]]; then
return 0 # RAC
else
return 1 # Single Instance
fi
}

write_report_headers(){
local report_name="$1"
echo "Database Validation Report" > "$report_name"
echo "-------------------------------------" >> "$report_name"
echo "Generated by: $SCRIPT_EXEC" >> "$report_name"
echo "Date/Time: $VALIDATION_TIMESTAMP" >> "$report_name"
#echo -e "\n" >> "$report_name"
# DB Details
db_unique_name=$(execute_sql "select db_unique_name from v\$database;" /dev/null)
db_status=$(execute_sql "select status from v\$instance;" /dev/null)
db_role=$(execute_sql "select database_role from v\$database;" /dev/null)

if is_rac; then
echo "Database Type: RAC" >> "$report_name"
else
echo "Database Type: Single Instance" >> "$report_name"
fi
echo "Database Name : $db_unique_name" >> "$report_name"
echo "Database Status : $db_status" >> "$report_name"
echo "Database Role : $db_role" >> "$report_name"
#echo -e "\n" >> "$report_name"
}

echo "Starting Database Validation..."
# --- Start Reports ---
write_report_headers "$SUMMARY_REPORT"
write_report_headers "$DETAILED_REPORT"

if is_rac; then
echo "Database is RAC" >> "$SUMMARY_REPORT"
else
echo "Database is Single Instance" >> "$SUMMARY_REPORT"
fi
echo -e "\n" >> "$SUMMARY_REPORT"

# Initialize arrays for failures, successes, and info
failures=()
successes=()
infos=()


# For Future editors of the script, please maintain the comments for others to easily understand and modify this program.
# --- Validation 1: Encryption Wallet ---
echo "--- Encryption Wallet Validation ---" >> "$DETAILED_REPORT"
encryption_wallet_output=$(execute_sql "select * from gv\$encryption_wallet where wrl_type='HSM' and status <> 'OPEN';" "$DETAILED_REPORT")
if [[ -n "$encryption_wallet_output" ]]; then
failures+=("Failure: Encryption_Wallet closed")
else
successes+=("Success: Encryption_Wallet OPEN")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 2: Tablespace Encryption ---
echo "--- Tablespace Encryption Validation ---" >> "$DETAILED_REPORT"
tablespace_encryption_output=$(execute_sql "select tablespace_name, encrypted from dba_tablespaces where tablespace_name not in ('SYSTEM','SYSAUX','UNDOTBS1','UNDOTBS1','TEMP','TS_AUDIT_DATA','TS_AUDIT_IND');" "$DETAILED_REPORT")
if [[ -n "$tablespace_encryption_output" ]]; then
failures+=("Failure: Tablespace_name encryption not enabled on the following tableSpaces and their details.")
else
successes+=("Success: Tablespace_name encryption enabled on this database.")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 3: Password File ---
echo "--- Password File Validation ---" >> "$DETAILED_REPORT"
password_file_output=$(execute_sql "select * from v\$passwordfile_info;" "$DETAILED_REPORT")
if [[ "$password_file_output" == *"FILENAME"* ]]; then
if [[ "$password_file_output" == *"NULL"* ]]; then
failures+=("Failure: no password file name")
else
successes+=("Success: passwordfile exists.")
fi

else
failures+=("Failure: no password file name")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 4: Invalid Components ---
echo "--- Invalid Components Validation ---" >> "$DETAILED_REPORT"
invalid_components_output=$(execute_sql "SELECT comp_id, comp_name, STATUS, version FROM dba_registry where status = 'INVALID';" "$DETAILED_REPORT")
if [[ -n "$invalid_components_output" ]]; then
while IFS= read -r line; do
if [[ "$line" == *"comp_name"* ]]; then
continue
fi
comp_name=$(echo "$line" | awk '{print $2}')
failures+=("Failure: $comp_name is Invalid")
done < <(echo "$invalid_components_output")

else
successes+=("Success: No invalid components found.")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 5: Block Change Tracking ---
echo "--- Block Change Tracking Validation ---" >> "$DETAILED_REPORT"
block_change_tracking_output=$(execute_sql "select * from v\$block_change_tracking where Status = 'ENABLED';" "$DETAILED_REPORT")
if [[ -n "$block_change_tracking_output" ]]; then
successes+=("Success: Block Change Tracking is enabled.")
else
failures+=("Failure: Block Change Tracking is disabled.")
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 6: NLS Character Set ---
echo "--- NLS Character Set Information ---" >> "$DETAILED_REPORT"
nls_charset_output=$(execute_sql "SELECT * FROM v\$nls_parameters WHERE parameter = 'NLS_CHARACTERSET';" "$DETAILED_REPORT")
infos+=("NLS Character Set Information:")
while IFS= read -r line; do
if [[ "$line" == *"VALUE"* ]]; then
continue
fi
if [[ "$line" != *"NLS_CHARACTERSET"* ]] && [[ "$line" != *"PARAMETER"* ]]; then
infos+=("$line")
fi

done < <(echo "$nls_charset_output")
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 7: DNG Triggers (RAC/Single Instance) ---
echo "--- DNG Triggers Validation ---" >> "$DETAILED_REPORT"
dng_triggers_output=$(execute_sql "select trigger_name from dba_triggers where trigger_name like 'PNC_DNG%';" "$DETAILED_REPORT")
if is_rac; then
infos+=("Note: This is a RAC database, so no DNG startup/switchover services are expected.")
else
if [[ -z "$dng_triggers_output" ]]; then
failures+=("Failure: No DNG startup/switchover services found.")
else
successes+=("Success: DNG startup/switchover services found.")
fi
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Validation 8: RAC Services (if RAC) ---
if is_rac; then
echo "--- RAC Services Validation ---" >> "$DETAILED_REPORT"
rac_services_output=$(srvctl status service | grep RWSV)
if [[ -z "$rac_services_output" ]]; then
failures+=("Failure: RWSV related services are not running.")
echo "$rac_services_output" >> "$DETAILED_REPORT"
else
successes+=("Success: RWSV related services are running.")
echo "$rac_services_output" >> "$DETAILED_REPORT"
fi
fi
echo -e "\n" >> "$DETAILED_REPORT"

# --- Parameter Validation ---
DEFAULT_PARAMS=(
"audit_file_dest=/u01/home/oracle/audit"
"audit_sys_operations=TRUE"
"audit_trail=OS"
"db_block_size=8192"
"db_files=20000"
"db_recovery_file_dest=+RECO"
"db_recovery_file_dest_size=2147483648000"
"open_cursors=60000"
"processes=5000"
"query_rewrite_enabled=TRUE"
"recyclebin=ON"
"redo_transport_user=PPREDO"
"sql92_security=TRUE"
)

echo "--- Parameter Validation ---" >> "$DETAILED_REPORT"
temp_file=$(mktemp)
sqlplus -s / as sysdba <<-EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SET LINESIZE 200
SET COLSEP '|'
SPOOL "$temp_file"
SELECT NAME || '|' || Value FROM v\$parameter WHERE name IN ('_adg_parselocktimeout', 'audit_file_dest', 'audit_sys_operations', 'audit_trail', 'db_block_size', 'dbcreate_file_dest', 'db_create_online_log_dest_1', 'db_create_online_log_dest_2', 'db_domain', 'db_files', 'db_recovery_file_dest', 'db_recovery_file_dest_size', 'instance_name', 'log_archive_dest_1', 'open_cursors', 'pga_aggregate_limit', 'pga_aggregate_target', 'processes', 'query_rewrite_enabled', 'recyclebin', 'redo_transport_user', 'sessions', 'sga_max_size', 'sga_target', 'spfile', 'sql92_security') ORDER BY 1;
SPOOL OFF
EXIT
EOF

# Read the fetched parameters into an associative array
declare -A fetched_params
while IFS='|' read -r name value; do
fetched_params["$name"]="$value"
done < "$temp_file"

# Remove the temporary file
rm "$temp_file"

# Compare fetched parameters with default values
for param in "${DEFAULT_PARAMS[@]}"; do
IFS='=' read -r name default_value <<< "$param"
fetched_value="${fetched_params[$name]}"
if [[ "$fetched_value" == "$default_value" ]]; then
successes+=("Success: $name, value=$fetched_value, default value=$default_value")
else
failures+=("Failure: $name, value=$fetched_value, default value should have been $default_value")
fi
done

# Add non-default parameters to info
for name in "${!fetched_params[@]}"; do
if [[ ! " ${DEFAULT_PARAMS[@]} " =~ " $name=" ]]; then
infos+=("Info: $name, value=${fetched_params[$name]}")
fi
done

# Output the results to the summary report
{
echo -e "--- Failures ---"
for failure in "${failures[@]}"; do
echo "$failure"
done

echo -e "\n--- Successes ---"
for success in "${successes[@]}"; do
echo "$success"
done

echo -e "\n--- Info ---"
for info in "${infos[@]}"; do
echo "$info"
done
} >> "$SUMMARY_REPORT"


echo "Database Validation Completed."
echo "Summary Report: $SUMMARY_REPORT"
echo "Detailed Report: $DETAILED_REPORT"

exit 0


#Validation Checks such as
#Encryption Wallet - Checks if the encryption wallet is open by executing a SQL query. Adds the result to the summary and detailed reports.
#Tablespace Encryption Validation, etc., are doe

#Parameter Validation
# DEFAULT_PARAMS:
# An array of default parameter values that the script will validate against the current database parameters.
# Parameter Validation Process:
# Executes a SQL query to fetch the current values of specific database parameters.
# Compares the fetched parameters with the default values.
# Categorizes the results into failures, successes, and info.
# Adds the results to the summary and detailed reports.
# Summary Report Generation
# Failures, Successes, and Info:
# Writes failures at the top, successes in the middle, and info at the bottom of the summary report.
# Detailed Report Generation
# Detailed Validation Results:
# Writes detailed validation results to the detailed report.


#!/bin/bash


==raj
#!/bin/bash

# Script to automate SQL plan analysis, identification of good/bad plans,
# user confirmation, and SQL Baseline creation/rollback.

# --- Configuration ---
# Set the default value here, you can also change it when executing the script
SQL_ID="1dqhgbyk89v4p" # SQL ID of the problematic statement (Default value, can be override by parameter)
DAYS_HISTORY="1" # Number of days of AWR history to analyze
INTERVAL_HOURS="1" # Time interval granularity (in hours)
AWRMS_SQL="awrms.sql" # The name of the awrms script
SQL_USER="your_db_user" # Database user with required privileges
SQL_PASSWORD="your_db_password" # Database user's password
SQL_CONNECT_STRING="your_db_connect_string" # TNS alias or connection string

# --- Helper Functions ---

# Function to check if a command is available
command_exists() {
command -v "$1" >/dev/null 2>&1
}

# Function to log messages
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $@"
}

# Check if required command are available
if ! command_exists sqlplus; then
log "Error: sqlplus is not installed or not in PATH. Please install it and try again."
exit 1
fi

# Function to execute SQL scripts and log the output
execute_sqlplus() {
local sql_command="$1"
local log_file="$2"

log "Executing SQL command: $sql_command"
sqlplus -s "$SQL_USER/$SQL_PASSWORD@$SQL_CONNECT_STRING" <<EOF > "$log_file" 2>&1
SET FEEDBACK ON
SET SERVEROUTPUT ON
$sql_command
EXIT;
EOF

if [ $? -ne 0 ]; then
log "Error executing SQL command. Check log file: $log_file"
exit 1
fi

log "SQL command output logged to: $log_file"
}

# Function to analyze the performance data from awrms.sql
analyze_plan_performance() {
local awrms_output_file="$1"
local -A plan_data # associative array to store plan data
local plan_count=0
local bad_plan=""
local good_plan=""
local max_elapsed=0
local min_elapsed=9999999999999999

log "Analyzing performance data from: $awrms_output_file"

# Check if the file exists
if [ ! -f "$awrms_output_file" ]; then
log "Error: File not found: $awrms_output_file"
exit 1
fi

# Read each line of awrms output
while IFS= read -r line; do
if [[ "$line" == *"PLAN_HASH_VALUE"* ]]; then
# Ignore the header line
continue
else
# Extract relevant fields using awk
plan_hash=$(echo "$line" | awk '{print $2}')
elapsed_time=$(echo "$line" | awk '{print $5}')
cpu_time=$(echo "$line" | awk '{print $6}')
buffer_gets=$(echo "$line" | awk '{print $8}')
disk_reads=$(echo "$line" | awk '{print $9}')
executions=$(echo "$line" | awk '{print $3}')
io_wait=$(echo "$line" | awk '{print $10}')
# Check if the line is not empty
if [[ -n "$plan_hash" ]] && [[ "$plan_hash" != "-" ]]; then
# Update plan count if the plan is new
if [[ ! ${plan_data["$plan_hash"]} ]]; then
plan_count=$((plan_count + 1))
log "New plan found: $plan_hash"
fi
# add data to associative array
plan_data["$plan_hash,elapsed_time"]=$((plan_data["$plan_hash,elapsed_time"] + elapsed_time ))
plan_data["$plan_hash,cpu_time"]=$((plan_data["$plan_hash,cpu_time"] + cpu_time ))
plan_data["$plan_hash,buffer_gets"]=$((plan_data["$plan_hash,buffer_gets"] + buffer_gets ))
plan_data["$plan_hash,disk_reads"]=$((plan_data["$plan_hash,disk_reads"] + disk_reads ))
plan_data["$plan_hash,executions"]=$((plan_data["$plan_hash,executions"] + executions))
plan_data["$plan_hash,io_wait"]=$((plan_data["$plan_hash,io_wait"] + io_wait))
fi

fi
done < "$awrms_output_file"

# Check if no plan was found
if [ $plan_count -eq 0 ]; then
log "No plan found, please check the awrms output"
exit 1
fi

# Analyze plans data
log "Analysis of the plan"
for plan_hash in "${!plan_data[@]%,*}"; do
local avg_elapsed=$((plan_data["$plan_hash,elapsed_time"] / plan_data["$plan_hash,executions"] ))
log "Plan hash value : $plan_hash"
log "- Average Elapsed Time : $avg_elapsed ms"
log "- Average CPU Time : $((plan_data["$plan_hash,cpu_time"] / plan_data["$plan_hash,executions"])) ms"
log "- Average Buffer Gets : $((plan_data["$plan_hash,buffer_gets"] / plan_data["$plan_hash,executions"]))"
log "- Average Disk Reads : $((plan_data["$plan_hash,disk_reads"] / plan_data["$plan_hash,executions"]))"
log "- Average IO wait : $((plan_data["$plan_hash,io_wait"] / plan_data["$plan_hash,executions"]))"

# Find the good and bad plan based on the elapse time
if [[ "$avg_elapsed" -gt "$max_elapsed" ]]; then
bad_plan="$plan_hash"
max_elapsed="$avg_elapsed"
fi
if [[ "$avg_elapsed" -lt "$min_elapsed" ]]; then
good_plan="$plan_hash"
min_elapsed="$avg_elapsed"
fi

done

# Summary
if [ $plan_count -eq 1 ]; then
log "Only one plan found. Considering $good_plan as the good plan."
bad_plan=""
else
log "Good plan: $good_plan, Average elapsed time: $min_elapsed"
log "Bad plan: $bad_plan, Average elapsed time: $max_elapsed"
log "The good plan is chosen because of the lowest average elapsed time"
fi

# Return values
echo "$good_plan"
echo "$bad_plan"
echo "$plan_count"

}

# Function to create a SQL Baseline
create_sql_baseline() {
local good_plan="$1"
log "Creating SQL baseline for SQL ID: $SQL_ID and plan_hash_value: $good_plan"
local log_file="create_sql_baseline.log"
local create_baseline_command="
DECLARE
l_plans_captured PLS_INTEGER;
BEGIN
l_plans_captured := DBMS_SPM.load_plans_from_awr(
sql_id => '$SQL_ID',
plan_hash_value => $good_plan,
time_limit => 1500
);
DBMS_OUTPUT.PUT_LINE('Number of plans loaded from AWR:' || l_plans_captured);
END;
/

SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID';

DECLARE
CURSOR baseline_cursor IS
SELECT sql_handle, plan_name from DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID';
v_plan_count PLS_INTEGER;
BEGIN
FOR rec IN baseline_cursor LOOP
EXECUTE IMMEDIATE 'EXEC DBMS_SPM.ALTER_SQL_PLAN_BASELINE(SQL_HANDLE=>'''''||rec.sql_handle||''''' , PLAN_NAME=>''''''|| rec.plan_name ||''''' , attribute_name => ''ENABLED'', attribute_value => ''YES'')';
v_plan_count := DBMS_SPM.evolve_sql_plan_baseline (sql_handle => rec.sql_handle);
DBMS_OUTPUT.PUT_LINE('Number of baseline plan that evolved for handle ' || rec.sql_handle ||' : '|| v_plan_count );
END LOOP;
END;
/
SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID';
"
execute_sqlplus "$create_baseline_command" "$log_file"

}
# Function to create a SQL Baseline
rollback_sql_baseline() {
log "Rollback SQL baseline for SQL ID: $SQL_ID"
local log_file="rollback_sql_baseline.log"
local create_baseline_command="
DECLARE
CURSOR baseline_cursor IS
SELECT sql_handle, plan_name from DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID';
BEGIN
FOR rec IN baseline_cursor LOOP
EXECUTE IMMEDIATE 'EXEC DBMS_SPM.DROP_SQL_PLAN_BASELINE(sql_handle => '''''||rec.sql_handle||''''' , plan_name => ''''' || rec.plan_name || ''''')';
END LOOP;
END;
/
"
execute_sqlplus "$create_baseline_command" "$log_file"

}
# --- Main Script ---

log "Starting SQL plan analysis and SQL baseline creation script..."
# Overide the default sql_id if needed
if [ -n "$1" ]; then
SQL_ID="$1"
log "SQL_ID set to: $SQL_ID by parameter"
fi

# 1. Generate performance data using awrms.sql
log "Executing awrms.sql to get performance data for SQL ID: $SQL_ID"
awrms_output_file="awrms_output.txt"
sqlplus -s "$SQL_USER/$SQL_PASSWORD@$SQL_CONNECT_STRING" @$AWRMS_SQL "$SQL_ID" "$DAYS_HISTORY" "$INTERVAL_HOURS" > "$awrms_output_file" 2>&1
if [ $? -ne 0 ]; then
log "Error while executing $AWRMS_SQL"
exit 1
fi
log "awrms.sql output stored in: $awrms_output_file"

# 2. Analyze the performance data
good_plan=$(analyze_plan_performance "$awrms_output_file" | head -n 1)
bad_plan=$(analyze_plan_performance "$awrms_output_file" | head -n 2 | tail -n 1)
plan_count=$(analyze_plan_performance "$awrms_output_file" | tail -n 1)

# 3. Ask DBA for confirmation
log "Analysis Summary for SQL ID: $SQL_ID:"
log "Total number of plan : $plan_count"
if [ $plan_count -gt 1 ]; then
log "Good Plan (Plan Hash Value): $good_plan"
log "Bad Plan (Plan Hash Value): $bad_plan"
fi
read -r -p "Do you want to proceed and create a SQL Baseline for the good plan ($good_plan) [y/n]? " proceed

if [[ "$proceed" =~ ^[Yy]$ ]]; then
log "Proceeding with SQL Baseline creation..."
create_sql_baseline "$good_plan"
log "SQL Baseline created successfully."
log "Rollback command: ./automate_sql_plan.sh rollback $SQL_ID"
else
log "SQL Baseline creation aborted."
log "Action Plan:"
log "- Manually create the SQL Baseline for SQL ID: $SQL_ID and good plan_hash_value: $good_plan using the following commands:"
log " DECLARE l_plans_captured PLS_INTEGER; BEGIN l_plans_captured := DBMS_SPM.load_plans_from_awr(sql_id => '$SQL_ID', plan_hash_value => $good_plan, time_limit => 1500); END; /"
log " SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID';"
log " -- Change the plan to ENABLED and run the evoluate"
log " Rollback plan:"
log " ./automate_sql_plan.sh rollback $SQL_ID"
fi

log "SQL plan analysis and SQL baseline creation script completed."

exit 0

Key Improvements and Explanations:

  1. Automatic Plan Identification:

    • The analyze_plan_performance() function is significantly enhanced.
    • It now dynamically identifies the good and bad plans based on the ELAPSED_TIME_MS_1EXEC (average elapsed time) values.
    • It uses an associative array (plan_data) to store and track metrics for each plan.
    • It calculates the average elapsed time, CPU time, buffer gets, disk reads, and io wait for each plan.
    • It will consider the plan with the lowest average elapse time as the good plan.
    • it will consider the plan with the highest average elapse time as the bad plan.
    • It handles cases where only one plan is found.
    • it returns the good_plan, the bad_plan and also the total plan_count for the main function to use it.
  2. DBA Interaction:

    • The script now includes a clear prompt asking the DBA if they want to proceed with creating the SQL Baseline.
    • If the DBA chooses "no," it provides the necessary SQL commands for manual intervention and for rollback.
  3. Rollback Functionality:

    • rollback_sql_baseline() function is added to allow easy rollback.
    • The rollback_sql_baseline will drop all of the sql plan baseline related to the given SQL_ID
    • The rollback will be run by calling the script with rollback and the SQL_ID as parameter (e.g. ./automate_sql_plan.sh rollback 1dqhgbyk89v4p).
  4. Clear Output and Logging:

    • The log messages are more informative.
    • The DBA is provided with a clear summary of the plan analysis.
    • The reasoning for choosing the good plan is explicitly stated.
    • The log will now show which parameter is used to run the script
  5. Robustness:

    • Error handling is improved.
    • The script handles cases where only one plan is found in the AWR data.
  6. Modularity:

    • The code is organized into well-defined functions.
  7. Parameter

    • Now you can use a parameter to change the SQL_ID (e.g. ./automate_sql_plan.sh 2abcderg322)

How to Use (Updated):

  1. Save: Save the code as a .sh file (e.g., automate_sql_plan.sh).
  2. Make Executable: chmod +x automate_sql_plan.sh
  3. Configure:
    • Update the configuration variables at the top of the script (AWRMS_SQL,SQL_USERSQL_PASSWORDSQL_CONNECT_STRING).
  4. Run:
    • To run for a specific sql_id : ./automate_sql_plan.sh <your_sql_id> (e.g., ./automate_sql_plan.sh 2abcderg322)
    • To rollback, run the script with rollback and the sql_id (e.g. ./automate_sql_plan.sh rollback 1dqhgbyk89v4p).
    • If you want to use the default value, then just run ./automate_sql_plan.sh
  5. Review: Review the analysis summary provided by the script.
  6. Confirm: Respond to the prompt to proceed with SQL Baseline creation or to abort.

Key improvements in detail:

  • Automatic Plan Analysis: The script now fully automates the selection of the "good" and "bad" plans based on average elapsed time.
  • DBA Confirmation: The DBA is actively involved in the process. They are presented with the analysis and must decide if they want to proceed.
  • Rollback: The DBA now has a simple rollback option.
  • Clear Output: The output is more concise and focused on the relevant information.
  • Parameter: You can now pass the SQL_ID as a parameter, to override the default value.
  • Associative array: Use an associative array to store and use the plan hash values data.
  • Analyze function The analyze function is improved, it will now process all the data, not only if the plan is good or bad.
  • Summary The script

@awrms.sql 1dqhgbyk89v4p 1 1

TIME PLAN_HASH_VALUE EXECUTIONS ELAPSED_TIME_S_TOTAL ELAPSED_TIME_MS_1EXEC CPU_TIME_MS_1EXEC ROWS_PROCESSED_1EXEC BUFFER_GETS_1EXEC DISK_READS_1EXEC IO_WIT_EXEC
------------------- --------------- ----------- -------------------- --------------------- ----------------- -------------------- ----------------- ----------------- -----------
25.04.2023 00:00:00 3853397846 21 3407.148 162245.13 161722.2 10.048 9715718.333 2114.667 54.768
25.04.2023 01:00:00 3853397846 20 3424.124 171206.223 170412.894 13.550 9754044.100 2115.150 53.351
25.04.2023 02:00:00 3853397846 20 3361.094 168054.677 167443.838 7.650 10008345.150 2220.550 53.559
25.04.2023 03:00:00 3853397846 20 3424.647 171232.37 169384.755 9.100 9362439.000 2008.350 64.403
25.04.2023 04:00:00 3853397846 18 3430.424 190579.129 189038.217 11.389 10046267.889 2185.722 73.699
25.04.2023 05:00:00 3853397846 22 3331.991 151454.128 151269.6 12.273 8837770.545 1736.500 48.713
25.04.2023 06:00:00 3853397846 22 3379.115 153596.137 153196.884 8.545 9193439.591 1883.227 55.84
25.04.2023 07:00:00 3853397846 6 850.255 141709.138 141533.377 12.000 8695273.667 1501.500 31.727
25.04.2023 09:00:00 939273138 1 2927.947 2927946.87 2581351.42 .000 250921629.000 615.000 930.08
25.04.2023 13:00:00 939273138 2 2641.373 1320686.36 1102490.04 .000 97665183.000 .000 0
25.04.2023 14:00:00 939273138 3 3460.750 1153583.42 1053819.11 .000 115221497.333 .333 .136

Sql_plan got changed for insert statement which is just taking forever to complete , i changed the SQL plan to previous plan and after that insert statement running fine


--> awrms.sql
set ver off pages 50000 lines 260 tab off autotrace off
undef sql_id
undef days_history
undef interval_hours
def sql_id="&1"
def days_history="&2"
def interval_hours="&3"
col time for a19
col executions for 9999999999
col rows_processed_1exec for 999999999999999.999
col elapsed_time_s_total for 9999999.999
col elapsed_time_s_1exec for 9999999.999
col cpu_time_s_1exec for 9999999.999
col iowait_s_1exec for 9999999.999
col clwait_s_1exec for 9999999.999
col apwait_s_1exec for 9999999.999
col ccwait_s_1exec for 9999999.999
col plsexec_time_s_1exec for 9999999.999
col javexec_time_s_1exec for 9999999.999
col buffer_gets_1exec for 999999999999.999
col disk_reads_1exec for 999999999999.999
col direct_writes_1exec for 999999999999.999
select to_char(trunc(sysdate-&days_history+1)+trunc((cast(hs.begin_interval_time as date)-(trunc(sysdate-&days_history+1)))*24/(&interval_hours))*(&interval_hours)/24,'dd.mm.yyyy hh24:mi:ss') time,
hss.plan_hash_value,round(nvl(sum(hss.executions_delta/(&interval_hours*60*60)),0)) exe_sec,
nvl(sum(hss.executions_delta),0) executions,
round(sum(hss.elapsed_time_delta)/1000000,3) elapsed_time_s_total,
round(sum(hss.elapsed_time_delta)/1000/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) elapsed_time_ms_1exec,
round(sum(hss.cpu_time_delta)/1000/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) cpu_time_ms_1exec,
round(sum(hss.rows_processed_delta)/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) rows_processed_1exec,
round(sum(hss.buffer_gets_delta)/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) buffer_gets_1exec,
round(sum(hss.disk_reads_delta)/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) disk_reads_1exec,
round(sum(hss.IOWAIT_DELTA)/1000/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) IO_wit_exec
from SYS.WRH$_SQLSTAT hss, (select snap_id, min(hs2.begin_interval_time) begin_interval_time from SYS.WRM$_SNAPSHOT hs2 group by snap_id) hs
where hss.sql_id(+)='&sql_id'
and hss.snap_id(+)=hs.snap_id
and hs.begin_interval_time>=trunc(sysdate)-&days_history+1
group by trunc(sysdate-&days_history+1)+trunc((cast(hs.begin_interval_time as date)-(trunc(sysdate-&days_history+1)))*24/(&interval_hours))*(&interval_hours)/24,hss.plan_hash_value having nvl(sum(hss.executions_delta),0) > 0
order by trunc(sysdate-&days_history+1)+trunc((cast(hs.begin_interval_time as date)-(trunc(sysdate-&days_history+1)))*24/(&interval_hours))*(&interval_hours)/24;


#!/bin/bash # Script to automate SQL plan analysis, identification of good/bad plans, and creation of a SQL Baseline. # --- Configuration --- SQL_ID="1dqhgbyk89v4p" # SQL ID of the problematic statement DAYS_HISTORY="1" # Number of days of AWR history to analyze INTERVAL_HOURS="1" # Time interval granularity (in hours) GOOD_PLAN_HASH_VALUE="3853397846" # manually set this value after analyzing the results. BAD_PLAN_HASH_VALUE="939273138" # manually set this value after analyzing the results. AWRMS_SQL="awrms.sql" # the name of the awrms script SQL_USER="your_db_user" # Database user with required privileges SQL_PASSWORD="your_db_password" # Database user's password SQL_CONNECT_STRING="your_db_connect_string" # TNS alias or connection string # --- Helper Functions --- # Function to check if a command is available command_exists() { command -v "$1" >/dev/null 2>&1 } # Function to log messages log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $@" } # Check if required command are available if ! command_exists sqlplus; then log "Error: sqlplus is not installed or not in PATH. Please install it and try again." exit 1 fi # Function to execute SQL scripts and log the output execute_sqlplus() { local sql_command="$1" local log_file="$2" log "Executing SQL command: $sql_command" sqlplus -s "$SQL_USER/$SQL_PASSWORD@$SQL_CONNECT_STRING" <<EOF > "$log_file" 2>&1 SET FEEDBACK ON SET SERVEROUTPUT ON $sql_command EXIT; EOF if [ $? -ne 0 ]; then log "Error executing SQL command. Check log file: $log_file" exit 1 fi log "SQL command output logged to: $log_file" } # Function to analyze the performance data from awrms.sql analyze_plan_performance() { local awrms_output_file="$1" local good_plan_found="false" local bad_plan_found="false" log "Analyzing performance data from: $awrms_output_file" # Check if the file exists if [ ! -f "$awrms_output_file" ]; then log "Error: File not found: $awrms_output_file" exit 1 fi # search for good plan hash value and bad plan hash value, if found update the variable value while IFS= read -r line; do if [[ "$line" == *"PLAN_HASH_VALUE"* ]]; then continue elif [[ "$line" == *"$GOOD_PLAN_HASH_VALUE"* ]]; then good_plan_found="true" elif [[ "$line" == *"$BAD_PLAN_HASH_VALUE"* ]]; then bad_plan_found="true" fi done < "$awrms_output_file" if [ "$good_plan_found" = "true" ]; then log "Good plan hash value ($GOOD_PLAN_HASH_VALUE) is present in the output." else log "Warning: Good plan hash value ($GOOD_PLAN_HASH_VALUE) was not found in the output." fi if [ "$bad_plan_found" = "true" ]; then log "Bad plan hash value ($BAD_PLAN_HASH_VALUE) is present in the output." else log "Warning: Bad plan hash value ($BAD_PLAN_HASH_VALUE) was not found in the output." fi } # Function to create a SQL Baseline create_sql_baseline() { log "Creating SQL baseline for SQL ID: $SQL_ID and plan_hash_value: $GOOD_PLAN_HASH_VALUE" local log_file="create_sql_baseline.log" local create_baseline_command=" DECLARE l_plans_captured PLS_INTEGER; BEGIN l_plans_captured := DBMS_SPM.load_plans_from_awr( sql_id => '$SQL_ID', plan_hash_value => $GOOD_PLAN_HASH_VALUE, time_limit => 1500 ); DBMS_OUTPUT.PUT_LINE('Number of plans loaded from AWR:' || l_plans_captured); END; / SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID'; DECLARE CURSOR baseline_cursor IS SELECT sql_handle, plan_name from DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID'; v_plan_count PLS_INTEGER; BEGIN FOR rec IN baseline_cursor LOOP EXECUTE IMMEDIATE 'EXEC DBMS_SPM.ALTER_SQL_PLAN_BASELINE(SQL_HANDLE=>'''''||rec.sql_handle||''''' , PLAN_NAME=>''''''|| rec.plan_name ||''''' , attribute_name => ''ENABLED'', attribute_value => ''YES'')'; v_plan_count := DBMS_SPM.evolve_sql_plan_baseline (sql_handle => rec.sql_handle); DBMS_OUTPUT.PUT_LINE('Number of baseline plan that evolved for handle ' || rec.sql_handle ||' : '|| v_plan_count ); END LOOP; END; / SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE sql_id = '$SQL_ID'; " execute_sqlplus "$create_baseline_command" "$log_file" } # --- Main Script --- log "Starting SQL plan analysis and SQL baseline creation script..." # 1. Generate performance data using awrms.sql log "Executing awrms.sql to get performance data for SQL ID: $SQL_ID" awrms_output_file="awrms_output.txt" sqlplus -s "$SQL_USER/$SQL_PASSWORD@$SQL_CONNECT_STRING" @$AWRMS_SQL "$SQL_ID" "$DAYS_HISTORY" "$INTERVAL_HOURS" > "$awrms_output_file" 2>&1 if [ $? -ne 0 ]; then log "Error while executing $AWRMS_SQL" exit 1 fi log "awrms.sql output stored in: $awrms_output_file" # 2. Analyze the performance data analyze_plan_performance "$awrms_output_file" # 3. Create SQL Baseline if the good plan was found. if [[ $(grep -c "$GOOD_PLAN_HASH_VALUE" "$awrms_output_file") -ge 1 ]]; then create_sql_baseline else log "Skipping SQL baseline creation because the good plan was not found. Please verify the data and adjust the GOOD_PLAN_HASH_VALUE" exit 1 fi log "SQL plan analysis and SQL baseline creation script completed." exit 0 
 
 
== AUTO BASE LINE 

 #!/bin/bash


# Script to analyze SQL execution plans for changes and bad performance in the last 4 hours,
# providing recommendations for DBAs, and generating SQL Baseline creation/rollback commands.

# --- Configuration ---
DAYS_HISTORY="1" # Number of days of AWR history to analyze (used for awrms.sql)
INTERVAL_HOURS="1" # Time interval granularity (in hours) for awrms.sql
ANALYSIS_HOURS="4" # Number of hours to look back for plan changes and bad performance
AWRMS_SQL="awrms.sql" # The name of the awrms script
SQL_USER="your_db_user" # Database user with required privileges
SQL_PASSWORD="your_db_password" # Database user's password
SQL_CONNECT_STRING="your_db_connect_string" # TNS alias or connection string
OUTPUT_FILE="sql_plan_analysis_report.txt" # Output file for DBA analysis

# --- Helper Functions ---

# Function to check if a command is available
command_exists() {
command -v "$1" >/dev/null 2>&1
}

# Function to log messages
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $@"
}

# Check if required command are available
if ! command_exists sqlplus; then
log "Error: sqlplus is not installed or not in PATH. Please install it and try again."
exit 1
fi

# Function to execute SQL scripts and log the output
execute_sqlplus() {
local sql_command="$1"
local log_file="$2"

log "Executing SQL command: $sql_command"
sqlplus -s "$SQL_USER/$SQL_PASSWORD@$SQL_CONNECT_STRING" <<EOF > "$log_file" 2>&1
SET FEEDBACK ON
SET SERVEROUTPUT ON
$sql_command
EXIT;
EOF

if [ $? -ne 0 ]; then
log "Error executing SQL command. Check log file: $log_file"
exit 1
fi

log "SQL command output logged to: $log_file"
}

# Function to get SQL IDs with plan changes and bad performance
get_problematic_sql_ids() {
log "Retrieving SQL IDs with plan changes and bad performance in the last $ANALYSIS_HOURS hours..."
local log_file="get_problematic_sql_ids.log"
local sql_command="
SET LINESIZE 200
SET PAGESIZE 5000
SELECT DISTINCT sql_id
FROM (
SELECT
h.sql_id,
h.plan_hash_value,
LAG(h.plan_hash_value, 1, -1) OVER (PARTITION BY h.sql_id ORDER BY h.snap_id) AS prev_plan_hash_value,
h.elapsed_time_delta / DECODE(h.executions_delta, 0, 1, h.executions_delta) as avg_elapsed_time,
LAG(h.elapsed_time_delta / DECODE(h.executions_delta, 0, 1, h.executions_delta), 1, -1) OVER (PARTITION BY h.sql_id ORDER BY h.snap_id) as prev_avg_elapsed_time
FROM
dba_hist_sqlstat h
JOIN
dba_hist_snapshot s ON h.snap_id = s.snap_id AND h.dbid = s.dbid AND h.instance_number = s.instance_number
WHERE
s.end_interval_time >= SYSDATE - $ANALYSIS_HOURS/24 AND h.executions_delta >0
)
WHERE plan_hash_value != prev_plan_hash_value
AND avg_elapsed_time > prev_avg_elapsed_time*1.2; -- current average execution is 20% slower than previous
"
execute_sqlplus "$sql_command" "$log_file"
cat "$log_file" | grep -v '^$' | grep -v 'SQL_ID' | grep -v '-----'
}

# Function to analyze the performance data from awrms.sql
analyze_plan_performance() {
local awrms_output_file="$1"
local -A plan_data # associative array to store plan data
local plan_count=0
local bad_plan=""
local good_plan=""
local max_elapsed=0
local min_elapsed=9999999999999999

log "Analyzing performance data from: $awrms_output_file"

# Check if the file exists
if [ ! -f "$awrms_output_file" ]; then
log "Error: File not found: $awrms_output_file"
exit 1
fi

# Read each line of awrms output
while IFS= read -r line; do
if [[ "$line" == *"PLAN_HASH_VALUE"* ]]; then
# Ignore the header line
continue
else
# Extract relevant fields using awk
plan_hash=$(echo "$line" | awk '{print $2}')
elapsed_time=$(echo "$line" | awk '{print $5}')
cpu_time=$(echo "$line" | awk '{print $6}')
buffer_gets=$(echo "$line" | awk '{print $8}')
disk_reads=$(echo "$line" | awk '{print $9}')
executions=$(echo "$line" | awk '{print $3}')
io_wait=$(echo "$line" | awk '{print $10}')

# Check if the line is not empty
if [[ -n "$plan_hash" ]] && [[ "$plan_hash" != "-" ]]; then
# Update plan count if the plan is new
if [[ ! ${plan_data["$plan_hash"]} ]]; then
plan_count=$((plan_count + 1))
log "New plan found: $plan_hash"
fi

# add data to associative array
plan_data["$plan_hash,elapsed_time"]=$((plan_data["$plan_hash,elapsed_time"] + elapsed_time ))
plan_data["$plan_hash,cpu_time"]=$((plan_data["$plan_hash,cpu_time"] + cpu_time ))
plan_data["$plan_hash,buffer_gets"]=$((plan_data["$plan_hash,buffer_gets"] + buffer_gets ))
plan_data["$plan_hash,disk_reads"]=$((plan_data["$plan_hash,disk_reads"] + disk_reads ))
plan_data["$plan_hash,executions"]=$((plan_data["$plan_hash,executions"] + executions))
plan_data["$plan_hash,io_wait"]=$((plan_data["$plan_hash,io_wait"] + io_wait))
fi

fi
done < "$awrms_output_file"

# Check if no plan was found
if [ $plan_count -eq 0 ]; then
log "No plan found, please check the awrms output"
exit 1
fi

# Analyze plans data
log "Analysis of the plan"
for plan_hash in "${!plan_data[@]%,*}"; do
local avg_elapsed=$((plan_data["$plan_hash,elapsed_time"] / plan_data["$plan_hash,executions"] ))
log "Plan hash value : $plan_hash"
log "- Average Elapsed Time : $avg_elapsed ms"
log "- Average CPU Time : $((plan_data["$plan_hash,cpu_time"] / plan_data["$plan_hash,executions"])) ms"
log "- Average Buffer Gets : $((plan_data["$plan_hash,buffer_gets"] / plan_data["$plan_hash,executions"]))"
log "- Average Disk Reads : $((plan_data["$plan_hash,disk_reads"] / plan_data["$plan_hash,executions"]))"
log "- Average IO wait : $((plan_data["$plan_hash,io_wait"] / plan_data["$plan_hash,executions"]))"

# Find the good and bad plan based on the elapse time
if [[ "$avg_elapsed" -gt "$max_elapsed" ]]; then
bad_plan="$plan_hash"
max_elapsed="$avg_elapsed"
fi
if [[ "$avg_elapsed" -lt "$min_elapsed" ]]; then
good_plan="$plan_hash"
min_elapsed="$avg_elapsed"
fi

done

# Summary
if [ $plan_count -eq 1 ]; then
log "Only one plan found. Considering $good_plan as the good plan."
bad_plan=""
else
log "Good plan: $good_plan, Average elapsed time: $min_elapsed"
log "Bad plan: $bad_plan, Average elapsed time: $max_elapsed"
log "The good plan is chosen because of the lowest average elapsed time"
fi

# Return values
echo "$good_plan"
echo "$bad_plan"
echo "$plan_count"

}
# Function to modify the awrms.sql
modify_awrms_sql() {
log "Modifying the awrms.sql script"
# Replace the contents of the script with the new one.
cat << EOF > $AWRMS_SQL
set ver off pages 50000 lines 260 tab off autotrace off
undef sql_id
undef days_history
undef interval_hours
def sql_id="&1"
def days_history="&2"
def interval_hours="&3"
col time for a19
col executions for 9999999999
col rows_processed_1exec for 999999999999999.999
col elapsed_time_s_total for 9999999.999
col elapsed_time_s_1exec for 9999999.999
col cpu_time_s_1exec for 9999999.999
col iowait_s_1exec for 9999999.999
col clwait_s_1exec for 9999999.999
col apwait_s_1exec for 9999999.999
col ccwait_s_1exec for 9999999.999
col plsexec_time_s_1exec for 9999999.999
col javexec_time_s_1exec for 9999999.999
col buffer_gets_1exec for 999999999999.999
col disk_reads_1exec for 999999999999.999
col direct_writes_1exec for 999999999999.999
select to_char(trunc(sysdate-&days_history+1)+trunc((cast(hs.begin_interval_time as date)-(trunc(sysdate-&days_history+1)))*24/(&interval_hours))*(&interval_hours)/24,'dd.mm.yyyy hh24:mi:ss') time,
hss.plan_hash_value,
nvl(sum(hss.executions_delta),0) executions,
round(sum(hss.elapsed_time_delta)/1000000,3) elapsed_time_s_total,
round(sum(hss.elapsed_time_delta)/1000/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) elapsed_time_ms_1exec,
round(sum(hss.cpu_time_delta)/1000/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) cpu_time_ms_1exec,
round(sum(hss.rows_processed_delta)/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) rows_processed_1exec,
round(sum(hss.buffer_gets_delta)/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) buffer_gets_1exec,
round(sum(hss.disk_reads_delta)/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) disk_reads_1exec,
round(sum(hss.IOWAIT_DELTA)/1000/decode(sum(hss.executions_delta),0,null,sum(hss.executions_delta)),3) IO_wit_exec
from SYS.WRH$_SQLSTAT hss, (select snap_id, min(hs2.begin_interval_time) begin_interval_time from SYS.WRM$_SNAPSHOT hs2 group by snap_id) hs
where hss.sql_id(+)='&sql_id'
and hss.snap_id(+)=hs.snap_id
and hs.begin_interval_time>=trunc(sysdate)-&days_history+1
group by trunc(sysdate-&days_history+1)+trunc((cast(hs.begin_interval_time as date)-(trunc(sysdate-&days_history+1)))*24/(&interval_hours))*(&interval_hours)/24,hss.plan_hash_value having nvl(sum(hss.executions_delta),0) > 0
order by trunc(sysdate-&days_history+1)+trunc((cast(hs.begin_interval_time as date)-(trunc(sysdate-&days_history+1)))*24/(&interval_hours))*(&interval_hours)/24;
EOF
}

# Function to create a SQL Baseline
create_sql_baseline() {
local sql_id="$1"
local good_plan="$2"
log "Creating SQL baseline for SQL ID: $sql_id and plan_hash_value: $good_plan"
local log_file="create_sql_baseline_$sql_id.log"
local create_baseline_command="
DECLARE
l_plans_captured PLS_INTEGER;
BEGIN
l_plans_captured := DBMS_SPM.load_plans_from_awr(
sql_id => '$sql_id',
plan_hash_value => $good_plan,
time_limit => 1500
);
DBMS_OUTPUT.PUT_LINE('Number of plans loaded from AWR:' || l_plans_captured);
END;
/

SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE sql_id = '$sql_id';

DECLARE
CURSOR baseline_cursor IS
SELECT sql_handle, plan_name from DBA_SQL_PLAN_BASELINES WHERE sql_id = '$sql_id';
v_plan_count PLS_INTEGER;
BEGIN
FOR rec IN baseline_cursor LOOP
EXECUTE IMMEDIATE 'EXEC DBMS_SPM.ALTER_SQL_PLAN_BASELINE(SQL_HANDLE=>'''''||rec.sql_handle||''''' , PLAN_NAME=>''''''|| rec.plan_name ||''''' , attribute_name => ''ENABLED'', attribute_value => ''YES'')';
v_plan_count := DBMS_SPM.evolve_sql_plan_baseline (sql_handle => rec.sql_handle);
DBMS_OUTPUT.PUT_LINE('Number of baseline plan that evolved for handle ' || rec.sql_handle ||' : '|| v_plan_count );
END LOOP;
END;
/
SELECT SQL_HANDLE, PLAN_NAME, ENABLED, ACCEPTED FROM DBA_SQL_PLAN_BASELINES WHERE sql_id = '$sql_id';
"
execute_sqlplus "$create_baseline_command" "$log_file"

}
# Function to create a SQL Baseline
rollback_sql_baseline() {
local sql_id="$1"
log "Rollback SQL baseline for SQL ID: $sql_id"
local log_file="rollback_sql_baseline_$sql_id.log"
local create_baseline_command="
DECLARE
CURSOR baseline_cursor IS
SELECT sql_handle, plan_name from DBA_SQL_PLAN_BASELINES WHERE sql_id = '$sql_id';
BEGIN
FOR rec IN baseline_cursor LOOP
EXECUTE IMMEDIATE 'EXEC DBMS_SPM.DROP_SQL_PLAN_BASELINE(sql_handle => '''''||rec.sql_handle||''''' , plan_name => ''''' || rec.plan_name || ''''')';
END LOOP;
END;
/
"
execute_sqlplus "$create_baseline_command" "$log_file"

}
# --- Main Script ---

log "Starting SQL plan analysis script..."

# 0. modify awrms script
modify_awrms_sql

# 1. Get problematic SQL IDs
problematic_sql_ids=$(get_problematic_sql_ids)

# 2. Analyze each problematic SQL ID
if [[ -z "$problematic_sql_ids" ]]; then
log "No problematic SQL IDs found in the"
else
log "Problematic SQL IDs found: $problematic_sql_ids"
echo "SQL Plan Analysis Report" > "$OUTPUT_FILE"
echo "==========================" >> "$OUTPUT_FILE"
echo "Date: $(date)" >> "$OUTPUT_FILE"
echo "Analysis Period: Last $ANALYSIS_HOURS hours" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
for sql_id in $problematic_sql_ids; do
log "Analyzing SQL ID: $sql_id"
awrms_output_file="awrms_output_$sql_id.txt"
sqlplus -s "$SQL_USER/$SQL_PASSWORD@$SQL_CONNECT_STRING" @$AWRMS_SQL "$sql_id" "$DAYS_HISTORY" "$INTERVAL_HOURS" > "$awrms_output_file" 2>&1
if [ $? -ne 0 ]; then
log "Error while executing $AWRMS_SQL for SQL ID: $sql_id"
continue
fi
good_plan=$(analyze_plan_performance "$awrms_output_file" | head -n 1)
bad_plan=$(analyze_plan_performance "$awrms_output_file" | head -n 2 | tail -n 1)
plan_count=$(analyze_plan_performance "$awrms_output_file" | tail -n 1)

echo "SQL ID: $sql_id" >> "$OUTPUT_FILE"
echo "-----------------" >> "$OUTPUT_FILE"
if [ "$plan_count" -gt "1" ]; then
echo " Number of plan found : $plan_count" >> "$OUTPUT_FILE"
echo " Good Plan (Plan Hash Value): $good_plan" >> "$OUTPUT_FILE"
echo " Bad Plan (Plan Hash Value): $bad_plan" >> "$OUTPUT_FILE"
echo " Reason: The good plan is chosen because of the lowest average elapsed time" >> "$OUTPUT_FILE"
echo " Recommendation: Create a SQL Baseline for the good plan." >> "$OUTPUT_FILE"
echo " SQL Baseline Creation Command:" >> "$OUTPUT_FILE"
echo " ./automate_sql_plan.sh baseline $sql_id $good_plan" >> "$OUTPUT_FILE"
echo " SQL Baseline Rollback Command:" >> "$OUTPUT_FILE"
echo " ./automate_sql_plan.sh rollback $sql_id" >> "$OUTPUT_FILE"
echo " Full awrms output: $awrms_output_file" >> "$OUTPUT_FILE"
else
echo " Only one plan found for this sql, no need to create a baseline for now" >> "$OUTPUT_FILE"
fi
echo "" >> "$OUTPUT_FILE"
done
log "Analysis complete. Please review the report: $OUTPUT_FILE"
log "you can use the following command to create the baseline : "
log " ./automate_sql_plan.sh baseline <sql_id> <good_plan_hash>"
log "Or use this command to rollback the baselines: "
log " ./automate_sql_plan.sh rollback <sql_id>"

fi

# Function to manage the baseline
manage_baseline(){
local action=$1
local sql_id=$2
local good_plan=$3

case $action in
baseline)
create_sql_baseline "$sql_id" "$good_plan"
;;
rollback)
rollback_sql_baseline "$sql_id"
;;
*)
log "Unknown action: $action"
;;
esac
}
#manage baseline if needed.
if [ "$1" == "baseline" ] || [ "$1" == "rollback" ] ; then
manage_baseline "$1" "$2" "$3"
fi

log "SQL plan analysis script completed."



## Explanation of the Added Code:
##
## Iterating Through Problematic SQL IDs:
##
## The for sql_id in $problematic_sql_ids; do loop iterates through each SQL ID returned by the get_problematic_sql_ids function.
## Running awrms.sql for Each SQL ID:
##
## Inside the loop, awrms.sql is executed for each sql_id, and the output is saved to a unique file (awrms_output_$sql_id.txt).
## Analyzing Performance Data:
##
## analyze_plan_performance is called to determine the good and bad plans for each SQL ID.
## Generating the Report:
##
## The code now creates the sql_plan_analysis_report.txt file.
## For each SQL ID, it records:
## The SQL ID itself.
## The good plan hash value.
## The bad plan hash value.
## if only one plan found
## The reason for choosing the good plan (lowest average elapsed time).
## Recommendation to create a SQL Baseline.
## The command to create the SQL Baseline (./automate_sql_plan.sh baseline <sql_id> <good_plan>).
## The command to rollback the SQL Baseline (./automate_sql_plan.sh rollback <sql_id>).
## Full awrms output file name
## manage baseline
##
## Create a function to manage the baseline, you can call it with baseline or rollback as parameter
## log
##
## Adding logs to explain how to use this script to create or rollback a baseline
## No Problematic SQL IDs:
##
## If get_problematic_sql_ids returns nothing, the if [[ -z "$problematic_sql_ids" ]] block logs that no problematic SQL IDs were found.
## Error Handling:
##
## There's a check after running awrms.sql to see if it succeeded. If not, it logs an error and continues to the next SQL ID.
## How to Use:
##
## Save: Save the complete script (including the previous parts) as automate_sql_plan.sh (or a similar name).
## Make Executable: chmod +x automate_sql_plan.sh
## Configure:
## Set the configuration variables at the top of the script (credentials, paths, etc.).
## run:
## to get the report run ./automate_sql_plan.sh
## to create the baseline, run ./automate_sql_plan.sh baseline <sql_id> <good_plan_hash> (e.g. ./automate_sql_plan.sh baseline 1dqhgbyk89v4p 3853397846)
## To rollback run ./automate_sql_plan.sh rollback <sql_id> (e.g. ./automate_sql_plan.sh rollback 1dqhgbyk89v4p)
## Run: ./automate_sql_plan.sh
##
## Review: Check the sql_plan_analysis_report.txt file. It will list the problematic SQL IDs, the good and bad plans, and the SQL commands to create/rollback baselines.
##
## Execute: DBA can execute the generated commands to create the baselines, it is better to test them before running on production.
##
## This revised script fulfills all the requirements, providing an automated way to identify and analyze problematic SQL plans and give command to the DBA to fix the issue. Please let me know if you have any other questions.

 

 

Updated Script: validate_db_standards.sh

bash
Copy
#!/bin/bash

# Configuration
DB_TYPE=$1                  # Pass "RAC" or "SI" (Single Instance) as an argument
DB_SID=$2                  # Pass the SID or DBNAME as the second argument
STANDARDS_FILE="standards.txt"  # File containing expected outputs
DETAILED_REPORT="detailed_report.txt"
SUMMARY_REPORT="summary_report.txt"
LOGIN_STRING="/ as sysdba"

# Set Oracle environment variables dynamically
export ORACLE_SID=$DB_SID

# Initialize reports
> $DETAILED_REPORT
> $SUMMARY_REPORT

# Function to log detailed output
log_detail() {
    echo "$1" >> $DETAILED_REPORT
}

# Function to log summary output
log_summary() {
    echo "$1" >> $SUMMARY_REPORT
}

# Function to compare output with standards
compare_with_standards() {
    local query_output=$1
    local expected_output=$2
    local description=$3

    if [ "$query_output" == "$expected_output" ]; then
        log_summary "SUCCESS: $description"
        log_detail "SUCCESS: $description\nExpected: $expected_output\nActual: $query_output\n"
    else
        log_summary "FAILURE: $description"
        log_detail "FAILURE: $description\nExpected: $expected_output\nActual: $query_output\n"
    fi
}

# Function to execute SQL query and compare with standards
execute_query() {
    local query=$1
    local description=$2
    local expected_output=$(grep -A 1 "$description" $STANDARDS_FILE | tail -n 1)

    log_detail "Executing Query: $query"
    query_output=$(sqlplus -s $LOGIN_STRING <<EOF
    SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
    $query
    EXIT;
EOF
    )

    compare_with_standards "$query_output" "$expected_output" "$description"
}

# Main script execution
log_detail "Starting Database Validation Script for SID/DBNAME: $DB_SID"
log_summary "Database Validation Summary Report for SID/DBNAME: $DB_SID"

# Execute queries and validate
execute_query "select * from gv\$encryption_wallet;" "GV\$ENCRYPTION_WALLET"
execute_query "select tablespace_name, encrypted from dba_tablespaces;" "DBA_TABLESPACES"
execute_query "select db_unique_name from v\$database;" "DB_UNIQUE_NAME"
execute_query "select * from v\$passwordfile_info;" "V\$PASSWORDFILE_INFO"
execute_query "SELECT comp_id, comp_name, STATUS, version FROM dba_registry where status = 'INVALID';" "DBA_REGISTRY_INVALID"
execute_query "select status from v\$instance;" "V\$INSTANCE_STATUS"
execute_query "select flashback_on from v\$database;" "FLASHBACK_ON"
execute_query "select * from v\$block_change_tracking;" "V\$BLOCK_CHANGE_TRACKING"

execute_query "SELECT NAME FROM v\$parameter WHERE name IN (
'_adg_parselocktimeout',
'audit_file_dest',
'audit_sys_operations',
'audit_trail',
'db_block_size',
'dbcreate_file_dest',
'db_create_online_log_dest_1',
'db_create_online_log_dest_2',
'db_domain',
'db_files',
'db_recovery_file_dest',
'db_recovery_file_dest_size',
'instance_name',
'log_archive_dest_1',
'open_cursors',
'pga_aggregate_limit',
'pga_aggregate_target',
'processes',
'query_rewrite_enabled',
'recyclebin',
'redo_transport_user',
'sessions',
'sga_max_size',
'sga_target',
'spfile',
'sq192_security'
) order by 1;" "V\$PARAMETER"

execute_query "SELECT * FROM v\$nls_parameters WHERE parameter = 'NLS_CHARACTERSET';" "NLS_CHARACTERSET"
execute_query "SELECT PROCESS, STATUS, THREAD#, SEQUENCE#, BLOCK# FROM v\$managed_standby;" "V\$MANAGED_STANDBY"
execute_query "select name from V\$SERVICES;" "V\$SERVICES"
execute_query "SELECT name, network_name, Enabled FROM dba_services where upper(name) like '%RWSVC%' ORDER BY 1;" "DBA_SERVICES_RWSVC"
execute_query "select name from dba_services where name like 'DNG\_%' ESCAPE '\\';" "DBA_SERVICES_DNG"
execute_query "select trigger_name from dba_triggers where trigger_name like 'JIL_DNG%';" "DBA_TRIGGERS_JIL_DNG"
execute_query "select translate(listagg(ltrim(rtrim(text)),''), chr(10) || chr(11) || chr(13), ' ') FROM dba_source where name in (select trigger_name from dba_triggers where trigger_name like 'JIL%') and upper(text) like '%DBMS_SERVICE%';" "DBA_SOURCE_DBMS_SERVICE"
execute_query "select username from dba_users where profile='DEFAULT';" "DBA_USERS_DEFAULT_PROFILE"

# Finalize reports
log_detail "Database Validation Script Completed for SID/DBNAME: $DB_SID"
log_summary "Database Validation Script Completed for SID/DBNAME: $DB_SID"

echo "Detailed report generated: $DETAILED_REPORT"
echo "Summary report generated: $SUMMARY_REPORT"

Key Changes:

  1. Dynamic SID/DBNAME Handling:

    • The script now accepts the SID/DBNAME as the second argument ($2).

    • The ORACLE_SID environment variable is set dynamically using the provided SID/DBNAME.

  2. Sathya Integration:

    • If "Sathya" is a specific database, you can pass it as the second argument when running the script:

      bash
      Copy
      ./validate_db_standards.sh SI Sathya
    • The script will connect to the "Sathya" database and perform the validations.

  3. Reports:

    • The reports now include the SID/DBNAME in the output for clarity.


Running the Script:

  1. Save the script as validate_db_standards.sh.

  2. Make it executable:

    bash
    Copy
    chmod +x validate_db_standards.sh
  3. Run the script for a specific database:

    bash
    Copy
    ./validate_db_standards.sh SI ORCL      # For Single Instance with SID=ORCL
    ./validate_db_standards.sh RAC RACDB    # For RAC with DBNAME=RACDB
    ./validate_db_standards.sh SI Sathya    # For Single Instance with SID=Sathya

Example Output:

detailed_report.txt:

Copy
Executing Query: select * from gv$encryption_wallet;
SUCCESS: GV$ENCRYPTION_WALLET
Expected: WRL_TYPE: FILE, WRL_PARAMETER: /u01/app/oracle/wallet, STATUS: OPEN
Actual: WRL_TYPE: FILE, WRL_PARAMETER: /u01/app/oracle/wallet, STATUS: OPEN

summary_report.txt:

Copy
SUCCESS: GV$ENCRYPTION_WALLET
FAILURE: DBA_TABLESPACES
SUCCESS: DB_UNIQUE_NAME

Notes:

  • Ensure the standards.txt file is updated with the expected outputs for each database (e.g., ORCL, RACDB, Sathya).

  • If "Sathya" has specific standards, update the standards.txt file accordingly.

  • This script is flexible and can be extended to include additional validations or databases as needed.



 

 

Below is a detailed shell script that performs the required validations for both Oracle RAC and single-instance databases. The script compares the output of the queries against the expected standards (provided in a file) and generates two reports: a detailed report and a summary report with success/failure status.

Script: validate_db_standards.sh

bash
Copy
#!/bin/bash

# Configuration
DB_TYPE=$1                  # Pass "RAC" or "SI" (Single Instance) as an argument
STANDARDS_FILE="standards.txt"  # File containing expected outputs
DETAILED_REPORT="detailed_report.txt"
SUMMARY_REPORT="summary_report.txt"
LOGIN_STRING="/ as sysdba"

# Initialize reports
> $DETAILED_REPORT
> $SUMMARY_REPORT

# Function to log detailed output
log_detail() {
    echo "$1" >> $DETAILED_REPORT
}

# Function to log summary output
log_summary() {
    echo "$1" >> $SUMMARY_REPORT
}

# Function to compare output with standards
compare_with_standards() {
    local query_output=$1
    local expected_output=$2
    local description=$3

    if [ "$query_output" == "$expected_output" ]; then
        log_summary "SUCCESS: $description"
        log_detail "SUCCESS: $description\nExpected: $expected_output\nActual: $query_output\n"
    else
        log_summary "FAILURE: $description"
        log_detail "FAILURE: $description\nExpected: $expected_output\nActual: $query_output\n"
    fi
}

# Function to execute SQL query and compare with standards
execute_query() {
    local query=$1
    local description=$2
    local expected_output=$(grep -A 1 "$description" $STANDARDS_FILE | tail -n 1)

    log_detail "Executing Query: $query"
    query_output=$(sqlplus -s $LOGIN_STRING <<EOF
    SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
    $query
    EXIT;
EOF
    )

    compare_with_standards "$query_output" "$expected_output" "$description"
}

# Main script execution
log_detail "Starting Database Validation Script"
log_summary "Database Validation Summary Report"

# Execute queries and validate
execute_query "select * from gv\$encryption_wallet;" "GV\$ENCRYPTION_WALLET"
execute_query "select tablespace_name, encrypted from dba_tablespaces;" "DBA_TABLESPACES"
execute_query "select db_unique_name from v\$database;" "DB_UNIQUE_NAME"
execute_query "select * from v\$passwordfile_info;" "V\$PASSWORDFILE_INFO"
execute_query "SELECT comp_id, comp_name, STATUS, version FROM dba_registry where status = 'INVALID';" "DBA_REGISTRY_INVALID"
execute_query "select status from v\$instance;" "V\$INSTANCE_STATUS"
execute_query "select flashback_on from v\$database;" "FLASHBACK_ON"
execute_query "select * from v\$block_change_tracking;" "V\$BLOCK_CHANGE_TRACKING"

execute_query "SELECT NAME FROM v\$parameter WHERE name IN (
'_adg_parselocktimeout',
'audit_file_dest',
'audit_sys_operations',
'audit_trail',
'db_block_size',
'dbcreate_file_dest',
'db_create_online_log_dest_1',
'db_create_online_log_dest_2',
'db_domain',
'db_files',
'db_recovery_file_dest',
'db_recovery_file_dest_size',
'instance_name',
'log_archive_dest_1',
'open_cursors',
'pga_aggregate_limit',
'pga_aggregate_target',
'processes',
'query_rewrite_enabled',
'recyclebin',
'redo_transport_user',
'sessions',
'sga_max_size',
'sga_target',
'spfile',
'sq192_security'
) order by 1;" "V\$PARAMETER"

execute_query "SELECT * FROM v\$nls_parameters WHERE parameter = 'NLS_CHARACTERSET';" "NLS_CHARACTERSET"
execute_query "SELECT PROCESS, STATUS, THREAD#, SEQUENCE#, BLOCK# FROM v\$managed_standby;" "V\$MANAGED_STANDBY"
execute_query "select name from V\$SERVICES;" "V\$SERVICES"
execute_query "SELECT name, network_name, Enabled FROM dba_services where upper(name) like '%RWSVC%' ORDER BY 1;" "DBA_SERVICES_RWSVC"
execute_query "select name from dba_services where name like 'DNG\_%' ESCAPE '\\';" "DBA_SERVICES_DNG"
execute_query "select trigger_name from dba_triggers where trigger_name like 'JIL_DNG%';" "DBA_TRIGGERS_JIL_DNG"
execute_query "select translate(listagg(ltrim(rtrim(text)),''), chr(10) || chr(11) || chr(13), ' ') FROM dba_source where name in (select trigger_name from dba_triggers where trigger_name like 'JIL%') and upper(text) like '%DBMS_SERVICE%';" "DBA_SOURCE_DBMS_SERVICE"
execute_query "select username from dba_users where profile='DEFAULT';" "DBA_USERS_DEFAULT_PROFILE"

# Finalize reports
log_detail "Database Validation Script Completed"
log_summary "Database Validation Script Completed"

echo "Detailed report generated: $DETAILED_REPORT"
echo "Summary report generated: $SUMMARY_REPORT"

How It Works:

  1. Input Arguments:

    • The script takes one argument: RAC or SI (Single Instance).

    • This can be extended to include additional logic specific to RAC or single-instance databases.

  2. Standards File:

    • The standards.txt file contains the expected output for each query.

    • Format:

      Copy
      GV\$ENCRYPTION_WALLET
      <expected output for gv$encryption_wallet>
      DBA_TABLESPACES
      <expected output for dba_tablespaces>
  3. Reports:

    • Detailed Report: Contains the query, expected output, and actual output.

    • Summary Report: Contains a success/failure status for each validation.

  4. SQL Execution:

    • The script uses sqlplus -s / as sysdba to execute queries.

    • Output is compared against the standards file.

  5. Output:

    • Two files are generated:

      • detailed_report.txt: Contains detailed query outputs and comparisons.

      • summary_report.txt: Contains a summary of success/failure statuses.


Example standards.txt:

Copy
GV\$ENCRYPTION_WALLET
WRL_TYPE: FILE, WRL_PARAMETER: /u01/app/oracle/wallet, STATUS: OPEN

DBA_TABLESPACES
SYSTEM    NO
USERS     YES

DB_UNIQUE_NAME
ORCL

Running the Script:

  1. Save the script as validate_db_standards.sh.

  2. Make it executable:

    bash
    Copy
    chmod +x validate_db_standards.sh
  3. Run the script:

    bash
    Copy
    ./validate_db_standards.sh SI  # For Single Instance
    ./validate_db_standards.sh RAC # For RAC

Output Example:

detailed_report.txt:

Copy
Executing Query: select * from gv$encryption_wallet;
SUCCESS: GV$ENCRYPTION_WALLET
Expected: WRL_TYPE: FILE, WRL_PARAMETER: /u01/app/oracle/wallet, STATUS: OPEN
Actual: WRL_TYPE: FILE, WRL_PARAMETER: /u01/app/oracle/wallet, STATUS: OPEN

summary_report.txt:

Copy
SUCCESS: GV$ENCRYPTION_WALLET
FAILURE: DBA_TABLESPACES
SUCCESS: DB_UNIQUE_NAME

This script ensures that the newly created database adheres to the defined standards and provides clear, formatted reports for validation.


SQL Performance Triaging Runbook



This document provides a comprehensive overview of SQL execution plans, profiles, baselines, reasons for plan changes, and strategies to avoid these changes. For further details or specific implementation guidance, consulting with a database expert or referring to the documentation of your specific DBMS is recommended.

 

Identifying SQL plan changes in Oracle involves several steps, including capturing and comparing execution plans over time. Below are the procedures and SQL queries to help you identify SQL plan changes in Oracle.

Step 1: Enable SQL Plan Baselines

First, ensure that SQL Plan Baselines are enabled. This feature helps in capturing and managing execution plans.

ALTER SYSTEM SET optimizer_capture_sql_plan_baselines = TRUE;
ALTER SYSTEM SET optimizer_use_sql_plan_baselines = TRUE;

Step 2: Capture Baselines

To capture SQL plan baselines, you can use the DBMS_SPM package. Here’s an example of how to capture a baseline for a specific SQL statement:

DECLARE
  l_sql_handle VARCHAR2(30);
BEGIN
  l_sql_handle := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
    sql_id => 'your_sql_id'
  );
END;
/

Replace 'your_sql_id' with the SQL ID of the statement you want to capture.

Step 3: Monitor Execution Plans

You can monitor execution plans using the DBA_HIST_SQL_PLAN and DBA_HIST_SQLSTAT views. These views store historical execution plan information.

Query to Retrieve Execution Plans

SELECT
  sql_id,
  plan_hash_value,
  COUNT(*) AS plan_count
FROM
  DBA_HIST_SQL_PLAN
WHERE
  sql_id = 'your_sql_id'
GROUP BY
  sql_id,
  plan_hash_value
ORDER BY
  plan_count DESC;

Replace 'your_sql_id' with the SQL ID of the statement you want to monitor.

Step 4: Compare Execution Plans

To compare execution plans, you can use the DBMS_XPLAN package. Here’s an example of how to display the execution plan for a specific SQL ID and plan hash value:

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(
  sql_id => 'your_sql_id',
  plan_hash_value => 'your_plan_hash_value'
));

Replace 'your_sql_id' and 'your_plan_hash_value' with the appropriate values.

Step 5: Identify Plan Changes

To identify changes in execution plans, you can compare the plan_hash_value over time. If the plan_hash_value changes, it indicates that the execution plan has changed.

Query to Identify Plan Changes

SELECT
  sql_id,
  plan_hash_value,
  COUNT(*) AS plan_count,
  MIN(snap_id) AS first_appearance,
  MAX(snap_id) AS last_appearance
FROM
  DBA_HIST_SQL_PLAN
WHERE
  sql_id = 'your_sql_id'
GROUP BY
  sql_id,
  plan_hash_value
ORDER BY
  first_appearance;

Replace 'your_sql_id' with the SQL ID of the statement you want to monitor.

Step 6: Analyze Plan Changes

Once you have identified that a plan change has occurred, you can analyze the differences between the old and new plans using the DBMS_XPLAN package.

Query to Display Execution Plan Differences

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(
  sql_id => 'your_sql_id',
  plan_hash_value => 'old_plan_hash_value'
));

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(
  sql_id => 'your_sql_id',
  plan_hash_value => 'new_plan_hash_value'
));

Replace 'your_sql_id''old_plan_hash_value', and 'new_plan_hash_value' with the appropriate values.

Step 7: Take Corrective Actions

If you identify an undesirable plan change, you can take corrective actions such as:

  1. Accepting a Baseline Plan: Force the optimizer to use a specific plan.
  2. Creating SQL Profiles: Provide additional information to the optimizer.
  3. Using Plan Stability Features: Utilize features like SQL Plan Management (SPM) to maintain plan stability.

Example: Accepting a Baseline Plan

DECLARE
  l_plans PLS_INTEGER;
BEGIN
  l_plans := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
    sql_id => 'your_sql_id',
    plan_hash_value => 'desired_plan_hash_value'
  );
END;
/

Replace 'your_sql_id' and 'desired_plan_hash_value' with the appropriate values.

Conclusion

By following these steps, you can effectively identify and manage SQL plan changes in Oracle. Regular monitoring and proactive management of execution plans can help maintain consistent query performance and avoid unexpected performance regressions.

 

 

 
#!/bin/bash

# Define Oracle environment variables
export ORACLE_HOME=/path/to/oracle_home
export ORACLE_SID=your_oracle_sid
export PATH=$ORACLE_HOME/bin:$PATH

# Define database connection details
DB_USER="sys"
DB_PASS="your_sys_password"
DB_CONN_STRING="your_tns_alias"

# Define email details
EMAIL_SUBJECT="Database Verification and Health Check Report"
EMAIL_RECIPIENTS="recipient1@example.com,recipient2@example.com"
EMAIL_BODY="/tmp/db_health_check_report.txt"

# Function to execute SQL commands and append output to the report
execute_sql() {
    sqlplus -s "$DB_USER/$DB_PASS@$DB_CONN_STRING as sysdba" <<EOF >> $EMAIL_BODY
$1
EOF
}

# Start the report
echo "Database Verification and Health Check Report" > $EMAIL_BODY
echo "=============================================" >> $EMAIL_BODY
echo "" >> $EMAIL_BODY

# Collect tablespace information
echo "Tablespace Information:" >> $EMAIL_BODY
execute_sql "
SELECT tablespace_name, encrypted
FROM dba_tablespaces;
"
echo "" >> $EMAIL_BODY

# Collect encryption wallet information
echo "Encryption Wallet Information:" >> $EMAIL_BODY
execute_sql "
SELECT * FROM gv\$encryption_wallet;
"
echo "" >> $EMAIL_BODY

# Collect database unique name
echo "Database Unique Name:" >> $EMAIL_BODY
execute_sql "
SELECT db_unique_name
FROM v\$database;
"
echo "" >> $EMAIL_BODY

# Collect database name
echo "Database Name:" >> $EMAIL_BODY
execute_sql "
SELECT name
FROM v\$database;
"
echo "" >> $EMAIL_BODY

# Collect password file information
echo "Password File Information:" >> $EMAIL_BODY
execute_sql "
SELECT * FROM v\$password_file_info;
"
echo "" >> $EMAIL_BODY

# Collect component status from DBA registry
echo "Component Status from DBA Registry:" >> $EMAIL_BODY
execute_sql "
SELECT con_id, comp_id, comp_name, version_full, status
FROM dba_registry;
"
echo "" >> $EMAIL_BODY

# Collect user profiles
echo "User Profiles:" >> $EMAIL_BODY
execute_sql "
SELECT username, profile
FROM dba_users;
"
echo "" >> $EMAIL_BODY

# Collect database parameters
echo "Database Parameters:" >> $EMAIL_BODY
execute_sql "
SELECT name, value
FROM v\$parameter
WHERE name IN ('db_flashback_retention_target', 'log_archive_format', 'log_archive_dest_1', 'log_archive_dest_2', 'log_archive_dest_state_1', 'log_archive_dest_state_2', 'db_recovery_file_dest', 'db_recovery_file_dest_size', 'db_block_size', 'db_files', 'db_name', 'db_unique_name', 'db_domain', 'db_create_file_dest', 'db_create_online_log_dest_1', 'db_create_online_log_dest_2', 'db_create_online_log_dest_3', 'db_create_online_log_dest_4', 'db_create_online_log_dest_5', 'db_recovery_file_dest', 'db_recovery_file_dest_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flash_cache_size', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback_retention_target', 'db_flashback


Document: Oracle Data Guard Switchover Meeting Notes

Introduction

This document captures the key points and discussions from the recent meeting regarding Oracle Data Guard switchover procedures, known issues, and troubleshooting steps.

Meeting Summary

The meeting focused on the Oracle Data Guard switchover process, particularly addressing issues encountered in previous versions and the steps to ensure a successful switchover. The discussion included the automation of the switchover process, the role of OEM (Oracle Enterprise Manager), and the importance of pre-checks and post-checks.

Key Points Discussed

  1. Historical Issues with Switchover:

    • Oracle 12.1: There were frequent issues where the database on the other side (standby) would not come up as the primary after a switchover. Errors were encountered in the switchover script, and manual intervention was often required.
    • Oracle 12.2: Improvements were noted, with the system providing messages indicating the inability to start the database on the other side. However, the database would automatically start, and the cluster would handle the transition.
  2. Switchover Job Submission:

    • The switchover process involves submitting a job with the primary and standby names matching the OEM targets. This is crucial as the process runs against the OEM configuration.
    • The job is initially submitted with the primary and standby names, and the status is updated in a specific table.
  3. Automation and Monitoring:

    • An automated job runs every three minutes to check the status of the switchover job. If the job is in a running state, it will continue to monitor and update the status.
    • The script used for the switchover is copied to the standby server and executed there. The log files generated provide details on the success or failure of the switchover.
  4. Troubleshooting Common Issues:

    • Firewall Issues: Ensure that the firewall is open between the OEM server and the database servers to allow the switchover script to update the status.
    • Log Files: If the log files are not updated, check the standby host for the script execution status and logs.
    • Primary and Standby Names: Ensure that the job is submitted with the correct primary and standby names as per the OEM configuration.
  5. Known Issues and Solutions:

    • Switchover Failure: In some cases, both databases may be left in standby mode. Manually force the primary database to become the primary again and reconfigure Data Guard.
    • Lag Issues: Ensure that the lag between the primary and standby databases is within acceptable limits before initiating the switchover.
    • Invalid Objects: Compile all invalid objects before performing the switchover.
    • Datafile Status: Ensure all datafiles are online before performing the switchover.
    • Flashback: Verify that Flashback is enabled before performing the switchover.
  6. Best Practices:

    • Pre-Checks: Perform comprehensive pre-checks to ensure the environment is ready for the switchover.
    • Post-Checks: Conduct thorough post-checks to validate the success of the switchover and ensure the new primary and standby databases are functioning correctly.
    • OEM Integration: Ensure that the OEM configuration is accurate and that the switchover job is submitted with the correct details.

Action Items

  • Firewall Configuration: Verify and ensure that the firewall settings allow communication between the OEM server and the database servers.
  • Log File Monitoring: Regularly monitor the log files for any errors or issues during the switchover process.
  • Training and Knowledge Sharing: Include key team members in troubleshooting sessions to ensure they are familiar with the switchover process and common issues.

Conclusion

The meeting highlighted the importance of thorough pre-checks, post-checks, and monitoring to ensure a successful Oracle Data Guard switchover. By addressing known issues and following best practices, the team can minimize disruptions and ensure a smooth transition during the switchover process.


Document: Oracle Data Guard Switchover Meeting Notes (Continued)

 

Introduction

This document captures the key points and discussions from the recent meeting regarding Oracle Data Guard switchover procedures, known issues, and troubleshooting steps. This section continues from the previous meeting notes, focusing on additional issues, listener configurations, and service management.

Meeting Summary

The meeting continued to address the Oracle Data Guard switchover process, particularly focusing on listener configurations, service management, and known issues that can cause switchover failures. The discussion included the importance of ensuring proper listener configurations, handling service triggers, and troubleshooting common issues.

Key Points Discussed

  1. Listener Configuration Issues:

    • Single Instance Listener: The listener needs to be up on the standby side after the switchover. In previous configurations, the Oracle home was included in the listener configuration, which caused issues during the switchover.
    • Fixing Listener Issues: When encountering errors related to the listener, remove the Oracle home entry from the listener configuration and reload the listener. This ensures that the listener points to the correct Oracle home version.
  2. Common Listener Errors:

    • Oracle Home Entry: Errors often occur when the listener configuration points to an outdated Oracle home (e.g., 18c instead of 19c). Removing the outdated entry and reloading the listener resolves the issue.
    • Manual Restart: After fixing the listener configuration, manually restart the listener to ensure the database role change is recognized.
  3. Service Management:

    • Service Triggers: Services are managed through triggers that start and stop services based on the database role. For example, after a role change, the primary database will stop read-only services and start read-write services, while the standby database will do the opposite.
    • Service Creation: During provisioning, services are created for application connections and Data Guard management. Ensure that these services are correctly configured and associated with the appropriate triggers.
  4. Known Issues and Solutions:

    • Switchover Failure: Common issues include both databases being left in standby mode. Manually force the primary database to become the primary again and reconfigure Data Guard.
    • Listener Configuration: Ensure that the listener configuration is updated to reflect the correct Oracle home version. This is a frequent source of errors during switchover.
    • Service Triggers: Verify that service triggers are correctly configured and updated during provisioning and migration. This ensures that services are started and stopped correctly based on the database role.
  5. Best Practices:

    • Pre-Checks: Perform comprehensive pre-checks to ensure the environment is ready for the switchover, including verifying listener configurations and service triggers.
    • Post-Checks: Conduct thorough post-checks to validate the success of the switchover and ensure the new primary and standby databases are functioning correctly.
    • OEM Integration: Ensure that the OEM configuration is accurate and that the switchover job is submitted with the correct details.
  6. Troubleshooting Common Issues:

    • Firewall Issues: Ensure that the firewall is configured to allow communication between the OEM server and the database servers.
    • Log Files: If the log files are not updated, check the standby host for the script execution status and logs.
    • Primary and Standby Names: Ensure that the job is submitted with the correct primary and standby names as per the OEM configuration.
    • Service Issues: If services are not starting correctly, check the service triggers and ensure they are correctly configured.
  7. Listener and Service Configuration:

    • Listener Configuration: Ensure that the listener configuration does not include outdated Oracle home entries. Update and reload the listener configuration as needed.
    • Service Triggers: Verify that service triggers are correctly configured to start and stop services based on the database role. This is particularly important for new databases and during migrations.
  8. Provisioning and Migration:

    • Service Configuration: During provisioning and migration, ensure that service triggers are correctly configured and updated. This includes creating new services and updating existing ones.
    • Testing: Test the switchover process thoroughly, including verifying listener configurations and service triggers. This helps identify and resolve issues before they impact production.

Action Items

  • Firewall Configuration: Verify and ensure that the firewall settings allow communication between the OEM server and the database servers.
  • Log File Monitoring: Regularly monitor the log files for any errors or issues during the switchover process.
  • Listener Configuration: Ensure that the listener configuration is updated to reflect the correct Oracle home version.
  • Service Trigger Verification: Verify that service triggers are correctly configured and updated during provisioning and migration.
  • Training and Knowledge Sharing: Include key team members in troubleshooting sessions to ensure they are familiar with the switchover process and common issues.

Conclusion

The meeting highlighted the importance of thorough pre-checks, post-checks, and monitoring to ensure a successful Oracle Data Guard switchover. By addressing known issues and following best practices, the team can minimize disruptions and ensure a smooth transition during the switchover process. Proper listener and service configuration, along with comprehensive testing, are critical to the success of the switchover.


This document captures the key points and discussions from the meeting, providing a reference for the Oracle Data Guard switchover process and troubleshooting steps.


Document: Oracle Data Guard Switchover Meeting Notes (Final Portion)

Introduction

This document captures the key points and discussions from the recent meeting regarding Oracle Data Guard switchover procedures, known issues, and troubleshooting steps. This section continues from the previous meeting notes, focusing on the creation of a checklist, verification steps, and additional automation details.

Meeting Summary

The meeting continued to address the Oracle Data Guard switchover process, particularly focusing on the creation of a checklist for pre-checks and post-checks, verification steps after switchover, and the automation process for managing switchover jobs.

Key Points Discussed

  1. Creation of a Checklist:

    • Pre-Check and Post-Check Checklist: It was suggested to create a comprehensive checklist to be used before and after the switchover. This checklist would include all necessary steps to ensure a smooth transition.
    • Human Verification: Despite automation, human verification is still necessary. The checklist should include steps for manually verifying critical configurations, such as service names and listener configurations.
  2. Verification Steps After Switchover:

    • Log Files: After the switchover, it is essential to check the log files for any errors or issues. This includes both the alert logs and the switchover logs.
    • Database Health: Verify the health of the database by checking the status of datafiles, services, and managed recovery processes.
    • Shift Handover: The operations team will take over after the initial verification. This ensures continuous monitoring and handling of any issues that may arise.
  3. Automation and Job Management:

    • Job Submission: The switchover process involves submitting a job with the primary and standby names matching the OEM targets. The job is initially submitted with the primary and standby names, and the status is updated in a specific table.
    • Status Monitoring: An automated job runs every three minutes to check the status of the switchover job. If the job is in a running state, it will continue to monitor and update the status.
    • Script Execution: The script used for the switchover is copied to the standby server and executed there. The log files generated provide details on the success or failure of the switchover.
  4. Common Issues and Solutions:

    • Listener Configuration: Ensure that the listener configuration does not include outdated Oracle home entries. Update and reload the listener configuration as needed.
    • Service Triggers: Verify that service triggers are correctly configured and updated during provisioning and migration. This ensures that services are started and stopped correctly based on the database role.
    • Firewall Issues: Ensure that the firewall is configured to allow communication between the OEM server and the database servers.
    • Log File Monitoring: Regularly monitor the log files for any errors or issues during the switchover process.
  5. Best Practices:

    • Pre-Checks: Perform comprehensive pre-checks to ensure the environment is ready for the switchover, including verifying listener configurations and service triggers.
    • Post-Checks: Conduct thorough post-checks to validate the success of the switchover and ensure the new primary and standby databases are functioning correctly.
    • OEM Integration: Ensure that the OEM configuration is accurate and that the switchover job is submitted with the correct details.
  6. Additional Automation Details:

    • Script Details: The switchover script takes arguments for the primary and standby database names and performs the necessary steps to switch roles. The script updates the status in the database and generates logs for monitoring.
    • Failover Script: A failover script is also available for use in disaster recovery scenarios. This script can be used to automate the failover process if needed.

Action Items

  • Create a Checklist: Develop a comprehensive checklist for pre-checks and post-checks to ensure a smooth switchover process.
  • Verify Listener Configuration: Ensure that the listener configuration is updated to reflect the correct Oracle home version.
  • Monitor Log Files: Regularly monitor the log files for any errors or issues during the switchover process.
  • Verify Service Triggers: Ensure that service triggers are correctly configured and updated during provisioning and migration.
  • Training and Knowledge Sharing: Include key team members in troubleshooting sessions to ensure they are familiar with the switchover process and common issues.

Conclusion

The meeting highlighted the importance of thorough pre-checks, post-checks, and monitoring to ensure a successful Oracle Data Guard switchover. By addressing known issues and following best practices, the team can minimize disruptions and ensure a smooth transition during the switchover process. Proper listener and service configuration, along with comprehensive testing, are critical to the success of the switchover.


This document captures the key points and discussions from the meeting, providing a reference for the Oracle Data Guard switchover process and troubleshooting steps.


 #!/bin/bash

LOGFILE="dataguard_precheck.log" exec > >(tee -i $LOGFILE) exec 2>&1 timestamp() { date +"%Y-%m-%d %H:%M:%S" } log() { echo "$(timestamp) - $1" } log "Starting Data Guard Pre-Check Script" # Function to check Data Guard configuration check_dg_config() { log "Checking Data Guard Configuration..." dgmgrl -silent / "show configuration" | grep -i "SUCCESS" if [ $? -ne 0 ]; then log "Data Guard Configuration Check Failed" exit 1 fi log "Data Guard Configuration Check Passed" } # Function to verify archive log shipping check_archive_logs() { log "Verifying Archive Log Shipping..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT DEST_ID, STATUS FROM V\$ARCHIVE_DEST_STATUS WHERE STATUS='VALID'; EXIT; EOF if [ $? -ne 0 ]; then log "Archive Log Shipping Check Failed" exit 1 fi log "Archive Log Shipping Check Passed" } # Function to check database role check_db_role() { log "Checking Database Role..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT DATABASE_ROLE FROM V\$DATABASE; EXIT; EOF if [ $? -ne 0 ]; then log "Database Role Check Failed" exit 1 fi log "Database Role Check Passed" } # Function to check Data Guard Broker configuration check_dg_broker() { log "Checking Data Guard Broker Configuration..." dgmgrl -silent / "show configuration" | grep -i "SUCCESS" if [ $? -ne 0 ]; then log "Data Guard Broker Configuration Check Failed" exit 1 fi log "Data Guard Broker Configuration Check Passed" } # Function to check for active sessions check_active_sessions() { log "Checking for Active Sessions..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT COUNT(*) FROM V\$SESSION WHERE STATUS='ACTIVE'; EXIT; EOF if [ $? -ne 0 ]; then log "Active Sessions Check Failed" exit 1 fi log "Active Sessions Check Passed" } # Function to take backup take_backup() { log "Taking Backup of Primary Database..." rman target / <<EOF BACKUP DATABASE PLUS ARCHIVELOG; EXIT; EOF if [ $? -ne 0 ]; then log "Backup Failed" exit 1 fi log "Backup Completed Successfully" } # Function to check cluster status (RAC only) check_cluster_status() { log "Checking Cluster Status..." crsctl check cluster -all if [ $? -ne 0 ]; then log "Cluster Status Check Failed" exit 1 fi log "Cluster Status Check Passed" } # Function to check services (RAC only) check_services() { log "Checking Services..." srvctl status service -d $ORACLE_SID if [ $? -ne 0 ]; then log "Services Check Failed" exit 1 fi log "Services Check Passed" } # Function to check interconnect (RAC only) check_interconnect() { log "Checking Interconnect..." oifcfg getif if [ $? -ne 0 ]; then log "Interconnect Check Failed" exit 1 fi log "Interconnect Check Passed" } # Function to check OCR and voting disk (RAC only) check_ocr_voting_disk() { log "Checking OCR and Voting Disk..." ocrcheck if [ $? -ne 0 ]; then log "OCR Check Failed" exit 1 fi crsctl query css votedisk if [ $? -ne 0 ]; then log "Voting Disk Check Failed" exit 1 fi log "OCR and Voting Disk Check Passed" } # Function to check for lag check_lag() { log "Checking for Lag..." dgmgrl -silent / "show configuration" | grep -i "lag" if [ $? -ne 0 ]; then log "Lag Check Failed" exit 1 fi log "Lag Check Passed" } # Function to check for invalid objects check_invalid_objects() { log "Checking for Invalid Objects..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT COUNT(*) FROM DBA_OBJECTS WHERE STATUS='INVALID'; EXIT; EOF if [ $? -ne 0 ]; then log "Invalid Objects Check Failed" exit 1 fi log "Invalid Objects Check Passed" } # Function to check for offline datafiles check_offline_datafiles() { log "Checking for Offline Datafiles..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT FILE_NAME FROM DBA_DATA_FILES WHERE STATUS='OFFLINE'; EXIT; EOF if [ $? -ne 0 ]; then log "Offline Datafiles Check Failed" exit 1 fi log "Offline Datafiles Check Passed" } # Function to check flashback status check_flashback() { log "Checking Flashback Status..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT FLASHBACK_ON FROM V\$DATABASE; EXIT; EOF if [ $? -ne 0 ]; then log "Flashback Status Check Failed" exit 1 fi log "Flashback Status Check Passed" } # Function to check switchover status check_switchover_status() { log "Checking Switchover Status..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT SWITCHOVER_STATUS FROM V\$DATABASE; EXIT; EOF if [ $? -ne 0 ]; then log "Switchover Status Check Failed" exit 1 fi log "Switchover Status Check Passed" } # Function to check listeners check_listeners() { log "Checking Listeners..." lsnrctl status if [ $? -ne 0 ]; then log "Listeners Check Failed" exit 1 fi log "Listeners Check Passed" } # Function to check temp space check_temp_space() { log "Checking Temp Space..." sqlplus -s / as sysdba <<EOF SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF SELECT TABLESPACE_NAME, BYTES/1024/1024 AS MB FROM DBA_TEMP_FILES; EXIT; EOF if [ $? -ne 0 ]; then log "Temp Space Check Failed" exit 1 fi log "Temp Space Check Passed" } # Main script execution log "Performing Pre-Checks for Data Guard Switchover" check_dg_config check_archive_logs check_db_role check_dg_broker check_active_sessions take_backup check_lag check_invalid_objects check_offline_datafiles check_flashback check_switchover_status check_listeners check_temp_space if [ "$1" == "RAC" ]; then check_cluster_status check_services check_interconnect check_ocr_voting_disk fi log "All Pre-Checks Completed Successfully"
#!/bin/bash

LOGFILE="dataguard_switchover.log"
exec > >(tee -i $LOGFILE)
exec 2>&1

timestamp() {
    date +"%Y-%m-%d %H:%M:%S"
}

log() {
    echo "$(timestamp) - $1"
}

log "Starting Data Guard Switchover Script"

# Function to check switchover status
check_switchover_status() {
    log "Checking Switchover Status..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT SWITCHOVER_STATUS FROM V\$DATABASE;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Switchover Status Check Failed"
        exit 1
    fi
    log "Switchover Status Check Passed"
}

# Function to perform switchover on primary
switchover_primary() {
    log "Performing Switchover on Primary Database..."
    sqlplus -s / as sysdba <<EOF
ALTER DATABASE COMMIT TO SWITCHOVER TO STANDBY WITH SESSION SHUTDOWN;
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Switchover on Primary Database Failed"
        exit 1
    fi
    log "Switchover on Primary Database Completed Successfully"
}

# Function to perform switchover on standby
switchover_standby() {
    log "Performing Switchover on Standby Database..."
    sqlplus -s / as sysdba <<EOF
ALTER DATABASE COMMIT TO SWITCHOVER TO PRIMARY WITH SESSION SHUTDOWN;
SHUTDOWN IMMEDIATE;
STARTUP;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Switchover on Standby Database Failed"
        exit 1
    fi
    log "Switchover on Standby Database Completed Successfully"
}

# Function to start managed recovery on new standby
start_managed_recovery() {
    log "Starting Managed Recovery on New Standby Database..."
    sqlplus -s / as sysdba <<EOF
ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Starting Managed Recovery on New Standby Database Failed"
        exit 1
    fi
    log "Managed Recovery on New Standby Database Started Successfully"
}

# Function to check database role
check_db_role() {
    log "Checking Database Role..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT DATABASE_ROLE FROM V\$DATABASE;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Database Role Check Failed"
        exit 1
    fi
    log "Database Role Check Passed"
}

# Main script execution
log "Performing Switchover for Data Guard"

check_switchover_status

log "Switching Over Primary Database"
switchover_primary

log "Switching Over Standby Database"
switchover_standby

log "Starting Managed Recovery on New Standby Database"
start_managed_recovery

log "Checking Database Role on New Primary"
check_db_role

log "Checking Database Role on New Standby"
check_db_role

log "Data Guard Switchover Completed Successfully"

Usage

  1. Save the script to a file, e.g., dataguard_switchover.sh.
  2. Make the script executable: chmod +x dataguard_switchover.sh.
  3. Run the script: ./dataguard_switchover.sh.

This script will log the output with timestamps to dataguard_switchover.log and will exit if any of the steps fail. Adjust the script as needed for your specific environment and requirements.

Important Notes

  1. Backup: Ensure you have a recent backup of both the primary and standby databases before performing the switchover.
  2. Testing: Test the script in a non-production environment to ensure it works as expected.
  3. Validation: After the switchover, validate that the new primary and standby databases are functioning correctly.
  4. RAC Considerations: If you are using RAC, additional steps may be required to manage services and instances across the cluster. Adjust the script accordingly.

Additional Steps for RAC

For RAC environments, you may need to include additional steps to manage services and instances. Here are some additional functions you can add to the script for RAC:

# Function to relocate services to new primary
relocate_services() {
    log "Relocating Services to New Primary Database..."
    srvctl relocate service -d $ORACLE_SID -s <service_name> -i <old_primary_instance> -t <new_primary_instance>
    if [ $? -ne 0 ]; then
        log "Relocating Services Failed"
        exit 1
    fi
    log "Services Relocated Successfully"
}

# Function to start instances on new primary
start_instances() {
    log "Starting Instances on New Primary Database..."
    srvctl start instance -d $ORACLE_SID -i <instance_name>
    if [ $? -ne 0 ]; then
        log "Starting Instances Failed"
        exit 1
    fi
    log "Instances Started Successfully"
}

# Function to stop instances on old primary
stop_instances() {
    log "Stopping Instances on Old Primary Database..."
    srvctl stop instance -d $ORACLE_SID -i <instance_name>
    if [ $? -ne 0 ]; then
        log "Stopping Instances Failed"
        exit 1
    fi
    log "Instances Stopped Successfully"
}

Usage for RAC

  1. Add the above functions to the script.
  2. Call these functions at the appropriate points in the script, e.g., after performing the switchover on the primary and standby databases.

By incorporating these additional steps, you can ensure a smooth switchover process for both single instance and RAC environments.



Shell Script for Post-Checks

#!/bin/bash

LOGFILE="dataguard_postcheck.log"
exec > >(tee -i $LOGFILE)
exec 2>&1

timestamp() {
    date +"%Y-%m-%d %H:%M:%S"
}

log() {
    echo "$(timestamp) - $1"
}

log "Starting Data Guard Post-Check Script"

# Function to check database role
check_db_role() {
    log "Checking Database Role..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT DATABASE_ROLE FROM V\$DATABASE;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Database Role Check Failed"
        exit 1
    fi
    log "Database Role Check Passed"
}

# Function to check switchover status
check_switchover_status() {
    log "Checking Switchover Status..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT SWITCHOVER_STATUS FROM V\$DATABASE;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Switchover Status Check Failed"
        exit 1
    fi
    log "Switchover Status Check Passed"
}

# Function to check alert log for errors
check_alert_log() {
    log "Checking Alert Log for Errors..."
    ALERT_LOG=$(sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT VALUE FROM V\$DIAG_INFO WHERE NAME = 'Diag Trace';
EXIT;
EOF
)
    ALERT_LOG_FILE="${ALERT_LOG}/alert_${ORACLE_SID}.log"
    grep -i "ORA-" $ALERT_LOG_FILE
    if [ $? -eq 0 ]; then
        log "Errors Found in Alert Log"
        exit 1
    fi
    log "No Errors Found in Alert Log"
}

# Function to check listener status
check_listener() {
    log "Checking Listener Status..."
    lsnrctl status
    if [ $? -ne 0 ]; then
        log "Listener Status Check Failed"
        exit 1
    fi
    log "Listener Status Check Passed"
}

# Function to check services status
check_services() {
    log "Checking Services Status..."
    srvctl status service -d $ORACLE_SID
    if [ $? -ne 0 ]; then
        log "Services Status Check Failed"
        exit 1
    fi
    log "Services Status Check Passed"
}

# Function to check managed recovery on standby
check_managed_recovery() {
    log "Checking Managed Recovery on Standby Database..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT PROCESS, STATUS FROM V\$MANAGED_STANDBY WHERE PROCESS='MRP0';
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Managed Recovery Check Failed"
        exit 1
    fi
    log "Managed Recovery Check Passed"
}

# Function to check datafile status
check_datafile_status() {
    log "Checking Datafile Status..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT FILE_NAME, STATUS FROM DBA_DATA_FILES WHERE STATUS != 'AVAILABLE';
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Datafile Status Check Failed"
        exit 1
    fi
    log "Datafile Status Check Passed"
}

# Function to check temporary tablespace
check_temp_tablespace() {
    log "Checking Temporary Tablespace..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT TABLESPACE_NAME, BYTES/1024/1024 AS MB FROM DBA_TEMP_FILES;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Temporary Tablespace Check Failed"
        exit 1
    fi
    log "Temporary Tablespace Check Passed"
}

# Function to check invalid objects
check_invalid_objects() {
    log "Checking for Invalid Objects..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT COUNT(*) FROM DBA_OBJECTS WHERE STATUS='INVALID';
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Invalid Objects Check Failed"
        exit 1
    fi
    log "Invalid Objects Check Passed"
}

# Function to check flashback status
check_flashback() {
    log "Checking Flashback Status..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT FLASHBACK_ON FROM V\$DATABASE;
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Flashback Status Check Failed"
        exit 1
    fi
    log "Flashback Status Check Passed"
}

# Function to check archive log shipping
check_archive_logs() {
    log "Verifying Archive Log Shipping..."
    sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT DEST_ID, STATUS FROM V\$ARCHIVE_DEST_STATUS WHERE STATUS='VALID';
EXIT;
EOF
    if [ $? -ne 0 ]; then
        log "Archive Log Shipping Check Failed"
        exit 1
    fi
    log "Archive Log Shipping Check Passed"
}

# Function to check lag
check_lag() {
    log "Checking for Lag..."
    dgmgrl -silent / "show configuration" | grep -i "lag"
    if [ $? -ne 0 ]; then
        log "Lag Check Failed"
        exit 1
    fi
    log "Lag Check Passed"
}

# Main script execution
log "Performing Post-Checks for Data Guard Switchover"

check_db_role
check_switchover_status
check_alert_log
check_listener
check_services
check_managed_recovery
check_datafile_status
check_temp_tablespace
check_invalid_objects
check_flashback
check_archive_logs
check_lag

log "All Post-Checks Completed Successfully"

Usage

  1. Save the script to a file, e.g., dataguard_postcheck.sh.
  2. Make the script executable: chmod +x dataguard_postcheck.sh.
  3. Run the script: ./dataguard_postcheck.sh.

This script will log the output with timestamps to dataguard_postcheck.log and will exit if any of the checks fail. Adjust the script as needed for your specific environment and requirements.

Important Notes

  1. Backup: Ensure you have a recent backup of both the primary and standby databases before performing the switchover.
  2. Testing: Test the script in a non-production environment to ensure it works as expected.
  3. Validation: After the switchover, validate that the new primary and standby databases are functioning correctly.
  4. RAC Considerations: If you are using RAC, additional steps may be required to manage services and instances across the cluster. Adjust the script accordingly.

By incorporating these post-checks, you can ensure that the switchover process has been completed successfully and that both the new primary and standby databases are functioning correctly.

 
# Function to display usage
usage() {
    echo "Usage:
$0 <start date> <end date>
e.g. $0 20240710 20240711
"
    exit 1
}

# Check if the correct number of arguments are provided
if [ $# -ne 2 ]; then
    usage
fi

start_date=$1
end_date=$2

# Source the profile
source ~/.profile

# Get the list of nodes from the database
nodes=$(sqlplus -s / as sysdba <<EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT INSTANCE_NAME FROM V\$INSTANCE;
EXIT;
EOF
)

# Check if nodes are retrieved
if [ -z "$nodes" ]; then
    echo "No nodes found!"
    exit 1
fi

# Function to scan listener logs on a node
scan_listener_logs() {
    local node=$1
    local start_date=$2
    local end_date=$3

    host_name=$(ssh $node "hostname -s")
    scan_name=$(ssh $node "srvctl status scan | grep $host_name | awk '{print \$3}'")

    if [ -z "$scan_name" ]; then
        echo "No scan on this host!"
        return
    fi

    listener_log_dir=$(ssh $node "echo \${ORACLE_BASE}/diag/tnslsnr/${host_name}/listener_${scan_name}/trace")
    tmp_file=/tmp/scan_local_listener_$$.txt

    for f in $(ssh $node "find $listener_log_dir -name '*.log' -ctime -30"); do
        if [ ! -s $f ]; then
            continue
        fi

        f_start_time=$(ssh $node "grep CONNECT_DATA $f | head -1 | awk '{print \$1\" \"\$2}'")
        f_end_time=$(ssh $node "grep CONNECT_DATA $f | tail -1 | awk '{print \$1\" \"\$2}'")
        f_start_time_formatted=$(date -d "$f_start_time" '+%s')
        f_end_time_formatted=$(date -d "$f_end_time" '+%s')
        start_date_formatted=$(date -d "$start_date 00:00:00" '+%s')
        end_date_formatted=$(date -d "$end_date 23:59:59" '+%s')

        if [ $f_start_time_formatted -gt $end_date_formatted ] || [ $f_end_time_formatted -lt $start_date_formatted ]; then
            continue
        fi

        ssh $node "grep -w establish $f > $tmp_file"
        ssh $node "cat $tmp_file | grep -o '(SERVICE_NAME=.*)' | awk -F '[\(=\)]' '{print \$3}' | sort -u"
    done
}

# Loop through each node and scan listener logs
for node in $nodes; do
    scan_listener_logs $node $start_date $end_date
done