All Products
Search
Document Center

ApsaraDB RDS:Development and operations recommendations

Last Updated:Mar 30, 2026

Best practices for improving the compliance, stability, and performance of ApsaraDB RDS for PostgreSQL instances.

Connection pooling

Configure connection pool parameters

Use PreparedStatement objects to cache SQL statements in the connection pool. This eliminates hard parses, reduces CPU usage, and improves instance performance.

Minimize idle connections to reduce memory usage, improve GetSnapshotData() efficiency, and boost overall system performance.

Enable connection pooling in your application to avoid the overhead of short-lived connections. If your application does not support built-in connection pooling, place a connection pool between your application and the RDS instance — for example, PgBouncer or Pgpool-II.

Set the following parameters for your connection pool:

Parameter Recommended value Description
minimumIdle 1 Minimum number of idle connections. Setting this to 1 reduces idle connections.
maxIdle 1 Maximum number of idle connections. Applies only if the parameter is available — it is removed from most connection pool implementations.
maxLifetime 60 minutes Maximum time-to-live (TTL) per connection. Reduces out-of-memory (OOM) errors caused by frequent connections to RelCache.
maximumPoolSize 15 Maximum connections per pool. Suitable for most workloads. Increase this value on database clients only if your instance handles workloads from more connections than the pool can serve.

Recommended configurations by framework

The following configurations apply to the most common connection pool frameworks. They do not include PreparedStatement settings — configure those based on your application requirements.

HikariCP (recommended for Java):

minimumIdle=1, maximumPoolSize=15, idleTimeout=600000 (10 minutes), maxLifetime=3600000 (60 minutes)

GORM (recommended for Go):

sqlDB.SetMaxIdleConns(1), sqlDB.SetMaxOpenConns(15), sqlDB.SetConnMaxLifetime(time.Hour)

Druid (Java):

initialSize=1, minIdle=1, maxIdle=1, maxActive=15, testOnBorrow=false, testOnReturn=false, testWhileIdle=true, minEvictableIdleTimeMillis=600000 (10 minutes), maxEvictableIdleTimeMillis=900000 (15 minutes), timeBetweenEvictionRunsMillis=60000 (1 minute), maxWait=6000 (6 seconds)

Performance and stability

  • A single database corresponds to a folder in the underlying file system. Tables, partitions, and indexes correspond to files in that folder. If the number of files exceeds 20 million, the instance reports a disk space exhausted error. Split the database or merge table files based on your workload.

  • Use CREATE INDEX CONCURRENTLY to create indexes for online workloads. This avoids blocking INSERT, UPDATE, and DELETE operations on the target table in other sessions.

  • For instances running PostgreSQL 12 or later, use REINDEX CONCURRENTLY to rebuild indexes. For PostgreSQL 11 or earlier, use CREATE INDEX ... CONCURRENTLY to create a replacement index, then drop the original.

  • Avoid frequently creating and dropping temporary tables — this increases system table overhead. Use caution with ON COMMIT DROP. In most cases, use a WITH clause instead of a temporary table.

  • PostgreSQL 13 improves support for partitioned tables, HashAggregate operations for GROUP BY clauses, and parallel queries. Upgrade your instance to PostgreSQL 13 where possible. For more information, see Upgrade the major engine version of an ApsaraDB RDS for PostgreSQL instance.

  • Disable the cursor feature if you are no longer using it.

  • Use TRUNCATE instead of DELETE for table-level data removal — TRUNCATE is significantly faster.

  • Wrap DDL statements in transactions so you can roll them back if needed. Keep transactions short: long DDL transactions block read operations on the objects they lock.

  • For bulk data writes, use COPY or multi-row INSERT INTO table VALUES (),(),...(); to maximize write throughput.

Minor engine version

  • To use the replication slot feature, update the minor engine version to 20201230 or later. This enables the Logical Replication Slot Failover feature and lets you configure an alert rule for the Maximum Replication Slot Latency metric, preventing logical subscriptions from falling behind or being interrupted. If logical subscriptions are delayed or interrupted, replication slots are lost and write-ahead logging (WAL) records accumulate. For more information, see Logical Replication Slot Failover and Manage the alert rules of an ApsaraDB RDS for PostgreSQL instance.

  • To use the audit log feature or the Performance Insight feature, update the minor engine version to 20211031 or later.

    When log_statement is set to all, performance improves approximately four times in scenarios with more than 50 active connections, and prevents significant CPU utilization spikes.

Monitoring and alerting

  • Turn on Initiative Alert to activate the default alert rules provided by the monitoring and alerting feature. For more information, see Manage the alerts.

  • Set the memory usage alert threshold between 85% and 95% based on your workload characteristics.

Troubleshooting

To find the most resource-intensive SQL statements (Top SQL), see Find the most resource-intensive SQL statements (Top SQL).

To identify SQL statements with the highest resource consumption, see Locate SQL statements with the highest resource consumption.

Design

Permissions

Follow the principle of least privilege (PoLP) and manage permissions by schema or role. Create two roles for each instance: one with read and write permissions, and one with read-only permissions. For more information, see Manage permissions in an ApsaraDB RDS for PostgreSQL instance.

If you implement read/write splitting at the application layer, assign the read-only role to read-only database clients.

Tables

  • Match data types in your schema to the data types in your application, and apply consistent validation rules across all tables. This prevents type-mismatch errors and ensures indexes are used correctly.

  • For tables with regularly purged historical data, partition by year or month. Use DROP or TRUNCATE on child partitions to remove data — avoid running DELETE on child partitions.

  • For tables with frequent updates, set FILLFACTOR to 85 at creation time. This reserves 15% of storage per page for hot updates, reducing page splits.

    CREATE TABLE test123(id int, info text) WITH(FILLFACTOR=85);
  • Use the following naming conventions:

    • Temporary tables: names start with tmp_

    • Child partition tables: names end with the partition key value. For example, if the parent table is tbl and partitioned by year, child tables are named tbl_2016, tbl_2017, and so on.

Indexes

ApsaraDB RDS for PostgreSQL supports the following index types: B-tree, Hash, GIN, GiST, SP-GiST, BRIN, RUM, Bloom, and PASE. RUM, Bloom, and PASE are extended index types.

Choosing an index type:

  • B-tree: The default index type. Fields must not exceed 2,000 bytes total. If the total size of indexed fields exceeds 2,000 bytes, create a function-based index (such as a hash index) or run the data through an analyzer before indexing.

  • BRIN: Use for large tables where column values have a natural linear ordering — for example, timestamps, auto-increment IDs, or streaming data. BRIN indexes are compact and accelerate range queries.

    CREATE INDEX idx ON tbl USING BRIN(id);

Avoid full table scans except when scanning and analyzing large datasets. Most PostgreSQL data types support indexes.

Index naming conventions:

Index type Prefix
Primary key indexes pk_
Unique indexes uk_
Regular indexes idx_

Data types and character sets

Select data types that match the data you are storing. Avoid using string types for numeric data or data that fits naturally into tree structures — appropriate data types improve query efficiency.

ApsaraDB RDS for PostgreSQL supports a wide range of data types, including: Numeric, Floating-Point, Monetary, String, Character, Binary, Date/Time, Boolean, Enumerated, Geometry, Network Address, Bit String, Text Search, UUID, XML, JSON, Array, Composite, Range, Object identifier, row number, large object, ltree structure, Data Cube, geography, H-Store, pg_trgm module, PostGIS, and HyperLogLog. PostGIS supports point, line segment, surface, path, latitude, longitude, raster, and topology types. HyperLogLog is a fixed-size, set-like data structure for counting distinct values at tunable precision.

Set LC_COLLATE to C rather than UTF8. The C collation outperforms UTF8 collation. If you use UTF8 collation, you must specify the text_pattern_ops operator class on indexes to support LIKE queries.

Stored procedures

For complex business logic that involves many round trips between your application and the database, use stored procedures (such as PL/pgSQL-based procedures) or built-in functions to reduce application-database interactions. PostgreSQL supports analytic functions, aggregate functions, window functions, mathematical functions, and geometric functions.

Data query

  • Use COUNT(*) rather than COUNT(column_name) or COUNT(constants). COUNT(*) is the SQL-92 standard for counting rows and includes NULL values. COUNT(column_name) excludes NULL values and produces a different result.

  • For COUNT(DISTINCT) across multiple columns, enclose the column list in parentheses:

    COUNT( (col1, col2, col3) )

    COUNT(DISTINCT) includes all NULL values, so it produces the same result as COUNT(*).

  • Avoid SELECT * FROM t. Specify only the columns you need to prevent returning unnecessary data.

  • Avoid returning large result sets to database clients, except for extract, transform, and load (ETL) operations. If a query returns an abnormally large result set, check whether the query's execution plan is optimal.

  • For range queries, use Range data types with GiST indexes to improve performance.

  • If your application frequently runs queries that return many rows, aggregate results into batches. For example, if a query returns 100 rows, aggregate them into a single result set. If your application accesses results by ID, aggregate by ID periodically. Smaller result sets reduce response time.

Instance management

  • Enable the SQL Explorer and Audit feature to query and export SQL execution information, including the databases queried, execution status, and durations. Use this feature to diagnose SQL health, troubleshoot performance issues, and analyze traffic. For more information, see Use the SQL Explorer and Audit feature on an ApsaraDB RDS for PostgreSQL instance.

  • To monitor and record activity within your Alibaba Cloud account — including console, API, and developer tool access — use ActionTrail. ActionTrail records these actions as events that you can download from the ActionTrail console or deliver to Log Service Logstores or Object Storage Service (OSS) buckets for security analysis, resource change tracking, or compliance auditing. For more information, see What is ActionTrail?.

  • Review all DDL operations before running them, and schedule DDL changes during off-peak hours.

  • Before committing transactions that delete or modify data, run a SELECT statement to confirm the affected rows. If your business logic requires updating exactly one row, add LIMIT 1.

  • For DDL operations and other operations that acquire locks — such as VACUUM FULL and CREATE INDEX — set a lock timeout to prevent them from blocking queries indefinitely:

    BEGIN;
    SET LOCAL lock_timeout = '10s';
    -- DDL statement;
    END;
  • Use EXPLAIN ANALYZE to inspect a query's execution plan. Unlike EXPLAIN, EXPLAIN ANALYZE actually executes the query. If the plan involves DML operations (UPDATE, INSERT, or DELETE), wrap the statement in a transaction and roll it back after inspection to avoid unintended data changes:

    BEGIN;
    EXPLAIN (ANALYZE) <DML (UPDATE/INSERT/DELETE) SQL>;
    ROLLBACK;
  • For large-scale deletions or updates, process data in batches — each batch in its own transaction. Deleting or updating all rows in a single transaction generates large amounts of junk data.