AWS Builder Center: Learn, Build and Connect with builders in the AWS community
AWS Builder Center is the official home for builders on AWS. Share and read what others are working on, follow people who inspire you, explore training and workshops, and find tools to support what you're building.
Build an AI-Powered Performance Advisor for Amazon RDS Using Amazon Bedrock and CloudWatch Database Insights
Learn how to build an automated AI-powered performance advisor that analyzes RDS instances across all engines using Amazon CloudWatch, CloudWatch Database Insights, and Amazon Bedrock to generate actionable tuning recommendations.
Introduction
Database performance tuning is one of the most complex and time-consuming tasks for database administrators. When an Amazon RDS instance experiences slowdowns, you typically need to correlate data from multiple sources—Amazon CloudWatch metrics, database load and wait events (via the Performance Insights API, now part of CloudWatch Database Insights), instance class specifications, storage configuration, and parameter group settings—before you can identify root causes and form recommendations. This process requires deep engine-specific expertise and significant manual effort.
In this article, I show you how to build an AI-powered performance advisor that automates this entire workflow. The solution collects performance telemetry from your RDS instance, analyzes IOPS/throughput/network throttling against your instance class and storage limits, and then uses Amazon Bedrock (Claude) to generate a comprehensive, engine-specific performance assessment with prioritized, actionable recommendations.
The automation:
- Supports all RDS engines: PostgreSQL, Aurora PostgreSQL, MySQL, Aurora MySQL, Oracle, SQL Server, MariaDB, and Db2
- Detects throttling risks: Calculates effective IOPS/throughput limits as the minimum of storage-level and instance-class-level ceilings, and flags when you're approaching those limits
- Generates engine-specific advice: Uses the correct parameter names, views, and tuning approaches for whichever engine you're running
- Runs interactively or in batch: Prompts you to select an instance, or analyzes all instances in a region
Architecture
The solution is a single Python script that orchestrates five AWS API calls in sequence:
+-------------------------------------------------------------------+
| rds_perf_advisor.py |
+-------------------------------------------------------------------+
| |
| 1. RDS DescribeDBInstances API |
| -> Instance class, storage type, provisioned IOPS, |
| engine, version, parameter group, PI resource ID |
| |
| 2. CloudWatch GetMetricData API |
| -> CPUUtilization, FreeableMemory, DatabaseConnections, |
| Read/WriteIOPS, Read/WriteLatency, Read/WriteThroughput, |
| FreeStorageSpace, SwapUsage, NetworkReceive/Transmit |
| -> Both average AND peak values collected |
| |
| 3. Throttling Analysis (local computation) |
| -> Effective IOPS limit = min(storage IOPS, instance IOPS) |
| -> Effective throughput = min(storage TP, instance TP) |
| -> Network utilization vs instance bandwidth |
| -> Identifies the limiting factor (storage vs instance) |
| |
| 4. Performance Insights API - GetResourceMetrics |
| (now part of CloudWatch Database Insights) |
| -> DB load by wait event (top 10) |
| -> DB load by wait event type (top 10) |
| -> Top SQL statements by load (top 5) |
| |
| 5. Amazon Bedrock InvokeModel API |
| -> Sends all collected data as structured context |
| -> Engine-aware prompt generates prioritized recommendations |
| -> Output: Executive Summary, Throttling Assessment, |
| Key Findings, Recommendations, Quick Wins, Monitoring |
| |
+-------------------------------------------------------------------+
Data sources accessed
| Source | API | Data collected | Purpose |
|---|---|---|---|
| Amazon RDS | DescribeDBInstances | Instance class, engine, storage type, provisioned IOPS/throughput, PI enabled, parameter group | Instance configuration and throttle limit calculation |
| Amazon CloudWatch | GetMetricData | 13 metrics with avg + peak: CPU, memory, connections, IOPS, latency, throughput, storage space, swap, network (15 for Aurora — adds ServerlessDatabaseCapacity, ACUUtilization) | Resource utilization baseline and spike detection |
| Performance Insights | GetResourceMetrics | Wait events, wait event types, top SQL by average active sessions | Workload characterization and bottleneck identification |
| Local computation | Instance class limits table | Baseline/max IOPS, throughput, network bandwidth per instance class | Throttle ceiling calculation |
| Amazon Bedrock | InvokeModel, ListInferenceProfiles | AI-generated analysis | Natural language recommendations |
Prerequisites
Before you begin, make sure you have the following:
- An AWS account with at least one RDS instance (any supported engine)
- Python 3.8 or later installed on your local machine
- AWS CLI configured with credentials that have the following IAM permissions:
rds:DescribeDBInstancespi:GetResourceMetricscloudwatch:GetMetricDatabedrock:InvokeModelbedrock:ListInferenceProfiles
- Amazon Bedrock model access enabled for Claude (Sonnet 4 or later) in your region. You can enable model access in the Bedrock console under Model access.
- Performance Insights / CloudWatch Database Insights enabled on the RDS instances you want to analyze (the free tier provides 7-day retention). The console now surfaces this data through CloudWatch Database Insights, while the API remains available for programmatic access.
- boto3 Python library installed (
pip3 install boto3) - Note on CloudWatch Database Insights: As of July 31, 2026, the Performance Insights console experience is replaced by Amazon CloudWatch Database Insights, which consolidates all Performance Insights capabilities with enhanced features. The underlying Performance Insights API (including the pi:GetResourceMetrics operation this script relies on) continues to be supported with no pricing changes. This solution therefore remains fully functional and is forward-compatible with Database Insights.
IAM policy required
Create or attach the following IAM policy to the user or role that will run the script:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "RDSPerfAdvisorReadAccess", "Effect": "Allow", "Action": [ "rds:DescribeDBInstances", "pi:GetResourceMetrics", "cloudwatch:GetMetricData", "bedrock:InvokeModel", "bedrock:ListInferenceProfiles" ], "Resource": "*" } ] }
Note: This policy grants read-only access to RDS metadata, Performance Insights, and CloudWatch metrics. The Bedrock InvokeModel and ListInferenceProfiles permission is required for the AI analysis. No write permissions to your databases are needed.
Step 1: Install dependencies
pip3 install boto3
No other Python dependencies are required. The script uses only boto3, json, argparse, and standard library modules.
Step 2: Download the script
Save the rds_perf_advisor.py script to your local machine. The script is self-contained — no additional configuration files are needed.
Step 3: Configure the script
Open rds_perf_advisor.py and update the configuration section at the top of the file:
# ────────────────────────────────────────────────────────────────────── # Configuration # ────────────────────────────────────────────────────────────────────── REGION = "us-east-1" # Your AWS region BEDROCK_MODEL_ID = "us.anthropic.claude-sonnet-4-6" # Bedrock inference profile LOOKBACK_HOURS = 1 # Analysis window (hours) PI_PERIOD_SECONDS = 60 # Performance Insights granularity CW_PERIOD_SECONDS = 60 # CloudWatch granularity
Finding your Bedrock model ID:
Run the following command to list available Claude inference profiles in your region:
aws bedrock list-inference-profiles \ --query "inferenceProfileSummaries[?contains(inferenceProfileId,'claude')].{Id:inferenceProfileId,Name:inferenceProfileName,Status:status}" \ --output table
Use an active inference profile ID (e.g., us.anthropic.claude-sonnet-4-6).
Step 4: Run the advisor
The script supports four modes of operation:
Interactive mode (recommended for first use)
python3 rds_perf_advisor.py
This discovers all RDS instances in the region and prompts you to enter the instance identifier directly:
======================================================================
AI-Powered Universal Performance Advisor for Amazon RDS
Supports: PostgreSQL | Aurora PostgreSQL | MySQL | Aurora MySQL
Oracle | SQL Server | MariaDB | Db2
======================================================================
Region: us-east-1 | Lookback: 1h | Model: us.anthropic.claude-sonnet-4-6
Found 127 available instance(s) in us-east-1.
Engines: aurora-mysql, aurora-postgresql, mysql, oracle-se2, postgres
Enter the DB instance identifier to analyze (or 'list' to see all, 'all' for batch):
Instance name: prod-orders-pg
You can:
- Type the exact instance name (e.g.,
prod-orders-pg) to analyze a single instance - Type a partial name (e.g.,
prod-orders) — if it uniquely matches one instance, it's used automatically; if multiple match, you're shown the matches and asked to clarify - Type
listto see all available instances with their engine and class - Type
allto run against every instance in the region in batch
Single instance mode
python3 rds_perf_advisor.py --instance pg-perf-advisor-test
Multiple instances
python3 rds_perf_advisor.py --instances pg-perf-advisor-test,mysql-perf-test
All instances in region
python3 rds_perf_advisor.py --all
List instances only (no analysis)
python3 rds_perf_advisor.py --list
Step 5: Understanding the output
The script produces a structured report with six sections:
Section 1: Executive Summary
A 2-3 sentence overview of the instance's health and the most critical finding.
Section 2: Throttling & Capacity Assessment
A table comparing observed IOPS, throughput, and network usage against the calculated limits:
──────────────────────────────────────────────────────────────────────
Analyzing: pg-perf-advisor-test
──────────────────────────────────────────────────────────────────────
[1/5] Fetching instance metadata...
Engine: postgres 16.14
Class: db.m5.large (2 vCPUs, 8 GB RAM)
Storage: gp3, 20 GB
IOPS limit: 3000 (limited by storage)
Throughput limit: 125 MB/s (limited by storage)
[2/5] Collecting CloudWatch metrics...
Metrics collected: 13
[3/5] Analyzing IOPS/throughput/network throttling...
IOPS: 1.7% of limit ✅ OK
Throughput: 4.6% of limit ✅ OK
Network: 0.1% of limit ✅ OK
[4/5] Collecting Performance Insights...
PI status: enabled, Wait events: 11, Top SQL: 6
[5/5] Invoking Amazon Bedrock...
Section 3: Key Findings
Prioritized findings with severity ratings (Critical/Warning/Informational), backed by specific data points from PI and CloudWatch.
Section 4: Recommendations
Actionable steps with:
- Specific SQL commands or parameter changes
- AWS CLI commands for parameter group modifications
- Expected impact
- Implementation complexity (Low/Medium/High)
Section 5: Quick Wins
Immediate, low-risk actions that can be taken right now.
Section 6: Monitoring Suggestions
CloudWatch alarms, Performance Insights counters, and PostgreSQL/MySQL/Oracle-specific queries to set up for ongoing monitoring.
How throttling analysis works
This is the key differentiation of this tool. For each instance, the script:
-
Reads the storage configuration from DescribeDBInstances:
- gp3: Uses the provisioned IOPS (default 3,000) and provisioned throughput (default 125 MB/s)
- gp2: Calculates as
min(max(allocated_GB × 3, 100), 16000)IOPS with burst to 3,000 for volumes under 1 TB - io1/io2: Uses the provisioned IOPS directly; throughput calculated as
min(IOPS × 0.256, 4000)MB/s
-
Looks up the instance class limits from a built-in table:
- Baseline IOPS (e.g., db.m5.large = 3,600)
- Maximum IOPS (e.g., db.m5.large = 18,750)
- Baseline throughput (e.g., db.m5.large = 593.75 MB/s)
- Network bandwidth (e.g., db.m5.large = 10 Gbps)
-
Calculates the effective limit as the MINIMUM of storage and instance class:
effective_IOPS_limit = min(storage_IOPS_limit, instance_class_IOPS_baseline)
effective_throughput_limit = min(storage_throughput_limit, instance_class_throughput_baseline)
-
Compares peak observed usage against the effective limit:
-
80% = ⚠️ AT RISK (recommend scaling)
-
95% = 🔴 THROTTLING LIKELY
-
-
Identifies the limiting factor so the recommendation targets the right component
Example: A db.m5.large with gp3 at default 3,000 IOPS has an effective limit of 3,000 (storage is the bottleneck, not the instance class at 3,600). If peak IOPS reaches 2,500, that's 83% — the advisor will recommend increasing provisioned IOPS on gp3 rather than upgrading the instance class.
How engine-specific recommendations work
The Bedrock prompt includes the engine type, and the AI is instructed to provide recommendations specific to that engine. For example:
| Engine | Parameter names | Views referenced | Upgrade path |
|---|---|---|---|
| PostgreSQL | shared_buffers, work_mem, effective_cache_size | pg_stat_activity, pg_stat_statements, pg_stat_user_tables | Instance class or gp3 IOPS |
| MySQL | innodb_buffer_pool_size, innodb_log_file_size | performance_schema, sys.schema_index_statistics | Instance class or gp3 IOPS |
| Oracle | SGA_TARGET, PGA_AGGREGATE_TARGET | V$SESSION_WAIT, AWR equivalents | Instance class or io1/io2 |
| SQL Server | max server memory, cost threshold for parallelism | sys.dm_exec_query_stats, sys.dm_os_wait_stats | Instance class or io1 |
| Aurora Serverless | ACU min/max | CloudWatch ServerlessDatabaseCapacity | Scale ACU range |
Sample output (from real workload test)
The following is an excerpt from a real report generated against an RDS PostgreSQL 16.14 instance (db.m5.large) after a 5-minute OLTP workload:
## 2. Throttling & Capacity Assessment ### IOPS | Metric | Value | Limit | Utilization | Status | |---|---|---|---|---| | Peak Total IOPS | 49.5 | 3,000 | 1.7% | ✅ Healthy | | Limiting Factor | Storage (gp3 provisioned) | — | — | No action needed | ### CPU | Metric | Value | Status | |---|---|---| | Average | 10.28% | ✅ Healthy baseline | | Peak | 81.58% | ⚠️ Elevated — investigation required | ## 3. Key Findings ### 🔴 Finding 1 — CRITICAL: Parallel Query Misconfigured for 2-vCPU Instance Evidence from Performance Insights wait events: IPC:ParallelBitmapScan → 0.0038 AAS IPC:HashBuildHashInner → 0.0022 AAS LWLock:SharedTidBitmap → 0.0055 AAS PostgreSQL is spawning parallel workers that compete for the same 2 vCPUs. ### ⚠️ Finding 3 — WARNING: work_mem Insufficient — Disk Spills Occurring Evidence: IO:BufFileWrite → 0.0008 AAS work_mem is 4 MB (default) — too low for joins on tables of meaningful size. ## 4. Recommendations ### Recommendation 2 — Create Custom Parameter Group
aws rds modify-db-parameter-group \ --db-parameter-group-name pg16-m5large-optimized \ --parameters \ "ParameterName=work_mem,ParameterValue=16384,ApplyMethod=immediate" \ "ParameterName=max_parallel_workers_per_gather,ParameterValue=1,ApplyMethod=immediate" \ "ParameterName=random_page_cost,ParameterValue=1.1,ApplyMethod=immediate" \ "ParameterName=effective_io_concurrency,ParameterValue=200,ApplyMethod=immediate"
Cost considerations
This solution uses the following AWS services, each with its own pricing:
- Performance Insights (7-day retention): Free tier includes 1 million API requests per month. The script makes ~3 API calls per instance analyzed.
- CloudWatch GetMetricData: Charged at $0.01 per 1,000 metrics requested. The script requests 13–15 metrics per instance (~$0.0001 per run).
- Amazon Bedrock (Claude Sonnet 4): Charged per input and output token. Input tokens vary based on the volume of Performance Insights data collected (wait events, top SQL). Output tokens vary based on the complexity of the AI-generated report.
Scaling note: When running in batch mode (e.g., --all across 50 instances), each instance generates a separate Bedrock invocation. Plan accordingly — costs scale linearly with the number of instances analyzed and the frequency of execution.
For current pricing details, see:
Cleanup
To remove resources created during testing:
# Delete test instances (if created for testing) aws rds delete-db-instance --db-instance-identifier pg-perf-advisor-test --skip-final-snapshot aws rds delete-db-instance --db-instance-identifier mysql-perf-test --skip-final-snapshot # Delete Aurora clusters aws rds delete-db-instance --db-instance-identifier aurora-pg-perf-test-1 --skip-final-snapshot aws rds delete-db-cluster --db-cluster-identifier aurora-pg-perf-test --skip-final-snapshot aws rds delete-db-instance --db-instance-identifier aurora-mysql-perf-test-1 --skip-final-snapshot aws rds delete-db-cluster --db-cluster-identifier aurora-mysql-perf-test --skip-final-snapshot # Remove security group rule aws ec2 revoke-security-group-ingress --group-id <YOUR_SECURITY_GROUP_ID> --protocol tcp --port 5432 --cidr YOUR_IP/32 aws ec2 revoke-security-group-ingress --group-id <YOUR_SECURITY_GROUP_ID> --protocol tcp --port 3306 --cidr YOUR_IP/32
Conclusion
This AI-powered performance advisor automates the most time-consuming part of database troubleshooting: correlating data across multiple sources and translating it into actionable, engine-specific recommendations. By combining Amazon CloudWatch metrics, Performance Insights wait events, instance-class throttling limits, and Amazon Bedrock's analytical capabilities, you get a DBA-quality performance assessment in under 2 minutes.
The solution works across all RDS engine types, correctly identifies the limiting factor when IOPS or throughput approach their ceiling (storage vs. instance class), and provides specific SQL commands and AWS CLI commands you can copy-paste to implement the recommendations. Run it interactively when troubleshooting a specific instance, or schedule it to proactively catch issues before they impact your applications.
Disclaimer:
This tool is AI-powered. Performance metrics are collected from Amazon CloudWatch, Performance Insights, and RDS instance metadata using standard AWS APIs. However, all recommendations and suggestions generated by the AI model (Amazon Bedrock) are advisory in nature and should be thoroughly reviewed, validated, and tested in a non-production environment before implementation. AWS resources, workloads, and configurations vary — what works for one environment may not be appropriate for another. Customer discretion is advised. The authors and AWS are not responsible for any unintended impact resulting from applying AI-generated recommendations without proper verification.
- Topics
- Database
- Language
- English
Relevant content
- Accepted Answer
asked a year ago
