All Products
Search
Document Center

ApsaraDB RDS:Troubleshoot high CPU utilization of ApsaraDB RDS for PostgreSQL

Last Updated:Jun 03, 2026

When CPU utilization on an ApsaraDB RDS for PostgreSQL instance spikes, the root cause is typically either a surge in active connections or a small set of resource-intensive queries. This guide walks you through diagnosing each possibility and applying the appropriate fix.

Note
  • Check the disaster recovery and fault tolerance capabilities of instances before you perform high-risk operations such as modifying configurations or data.

  • Create snapshots or enable RDS log backup before you modify the configurations or data of instances such as ECS and ApsaraDB RDS instances.

  • If you have granted permissions to users or submitted sensitive information such as logon accounts and passwords in Alibaba Cloud Management Console, modify the information in a timely manner.

Step 1: Check active connections

When CPU utilization hits 100%, first check whether the spike coincides with a surge in active connections during peak hours. A sudden connection increase beyond normal levels usually means the instance lacks the reserved resources to handle the workload.

To view historical connection trends, go to the Monitoring and Alerts section in the ApsaraDB RDS console.

To check current active connections, connect to the database and run:

SELECT state, count(*)
FROM pg_stat_activity
WHERE state NOT LIKE '%idle'
GROUP BY state
ORDER BY count DESC;

Grouping by state shows how connections are distributed across active, idle-in-transaction, and other states, which helps pinpoint whether the problem is raw connection volume or stuck transactions.

  • Active connections are significantly higher than normal: The instance may need more resources. Consider upgrading the instance specification.

  • Active connections are within the normal range: High CPU utilization is likely caused by slow queries. Continue with Step 2.

Step 2: Identify slow queries

When active connections are at normal levels, a small number of resource-intensive queries are typically consuming most of the CPU. Use one of the following methods to find them.

Method

Best for

Requires

Method 1: pg_stat_statements

Finding historically expensive queries

Extension installation

Method 2: pg_stat_activity

Finding currently running long queries

No setup

Method 3: Missing indexes

Detecting full table scans

No setup

Method 1: Use the pg_stat_statements extension

The pg_stat_statements extension tracks cumulative execution statistics for all SQL statements. Because it accumulates data over time, reset its counters before troubleshooting so the results reflect only recent activity.

Note

This method is applicable only to ApsaraDB RDS for PostgreSQL.

  1. If the extension is not already installed, create it and reset the counters:

    CREATE EXTENSION pg_stat_statements;
    SELECT pg_stat_reset();
    SELECT pg_stat_statements_reset();
  2. Wait about one minute for the counters to accumulate data.

  3. Find the queries that consume the most total execution time:

    SELECT *
    FROM pg_stat_statements
    ORDER BY total_time DESC
    LIMIT 5;
  4. Find the queries that read the most shared buffer blocks. High buffer reads typically indicate missing indexes — the database scans far more data than needed:

    SELECT *
    FROM pg_stat_statements
    ORDER BY shared_blks_hit + shared_blks_read DESC
    LIMIT 5;

To find queries that are slow per individual call (rather than in aggregate), also sort by mean_exec_time DESC. This surfaces queries with a high average runtime that may not rank near the top by total time.

After identifying the problematic queries, go to Step 3 to resolve the issue.

Method 2: Use the pg_stat_activity view

The pg_stat_activity view shows all current database sessions and their queries. Run the following query to find queries that have been running for an unusually long time:

SELECT datname,
       usename,
       client_addr,
       application_name,
       state,
       backend_start,
       xact_start,
       xact_stay,
       query_start,
       query_stay,
       replace(query, chr(10), ' ') AS query
FROM (
    SELECT pgsa.datname AS datname,
           pgsa.usename AS usename,
           pgsa.client_addr AS client_addr,
           pgsa.application_name AS application_name,
           pgsa.state AS state,
           pgsa.backend_start AS backend_start,
           pgsa.xact_start AS xact_start,
           extract(epoch FROM (now() - pgsa.xact_start)) AS xact_stay,
           pgsa.query_start AS query_start,
           extract(epoch FROM (now() - pgsa.query_start)) AS query_stay,
           pgsa.query AS query
    FROM pg_stat_activity AS pgsa
    WHERE pgsa.state != 'idle'
      AND pgsa.state != 'idle in transaction'
      AND pgsa.state != 'idle in transaction (aborted)'
) idleconnections
ORDER BY query_stay DESC
LIMIT 5;

After identifying the problematic queries, go to Step 3 to resolve the issue.

Method 3: Find tables with missing indexes

Without indexes, the database performs a sequential scan and reads every row to find matching results. For example, if the database has 8 GB of memory and 6 GB of hot data resides in memory without indexes, sequential scans process large amounts of irrelevant data and drive up CPU usage. For tables with more than 100,000 rows, a single sequential scan can consume nearly all available CPU — and the problem compounds when hundreds of connections run such scans at the same time.

  1. Find the tables with the most sequential scans:

    SELECT *
    FROM pg_stat_user_tables
    WHERE n_live_tup > 100000
      AND seq_scan > 0
    ORDER BY seq_tup_read DESC
    LIMIT 10;
  2. Check for slow queries currently accessing those tables:

    SELECT *
    FROM pg_stat_activity
    WHERE query ILIKE '%<table name>%'
      AND now() - query_start > interval '10 seconds';
Note

To find queries related to a specific table, use the pg_stat_statements extension:

SELECT *
FROM pg_stat_statements
WHERE query ILIKE '%<table>%'
ORDER BY shared_blks_hit + shared_blks_read DESC
LIMIT 3;

After identifying the problematic queries, go to Step 3 to resolve the issue.

Step 3: Resolve the issue

Terminate slow queries

After identifying the problematic queries in Step 2, terminate them to restore normal service. PostgreSQL provides two functions for this:

  • pg_cancel_backend(): Gracefully cancels a query without closing the connection.

  • pg_terminate_backend(): Forcibly terminates the entire backend process.

-- Gracefully cancel matching queries
SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE query LIKE '%<query text>%'
  AND pid != pg_backend_pid();

-- Forcibly terminate matching backend processes
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE query LIKE '%<query text>%'
  AND pid != pg_backend_pid();

Optimize slow queries

If the slow queries are necessary for your business, optimize them to prevent the issue from recurring.

  1. Update table statistics. Run ANALYZE or VACUUM ANALYZE on the tables involved in the slow queries. Outdated statistics cause the query planner to choose inefficient execution plans. Run these commands during off-peak hours to minimize impact.

    Note

    Replace [$Table] with the name of the table related to the slow queries.

    ANALYZE [$Table];
    VACUUM ANALYZE [$Table];
  2. Review the execution plan. Use EXPLAIN to examine how the database executes a query and identify whether it performs sequential scans on large tables that would benefit from an index.

    • View the execution plan without running the query:

      EXPLAIN [$Query_Text];
    • Run the query and view detailed execution statistics:

      EXPLAIN (BUFFERS TRUE, ANALYZE TRUE, VERBOSE TRUE) [$Query_Text];
    Note

    Replace [$Query_Text] with the SQL query you want to analyze.

    If the execution plan shows sequential scans on large tables, add indexes on columns used in WHERE clauses, JOIN conditions, or ORDER BY clauses.

  3. Rewrite inefficient queries. Remove unnecessary subqueries from slow queries. To further improve performance, consider rewriting UNION ALL operations and using JOIN clauses for fixed join sequences.

Applicable scope

  • ApsaraDB RDS for PostgreSQL