top of page
Search

PostgreSQL Scaling Strategies — Quick Reference

2 days ago
4 min read

Any robust backend depends deeply on the design of it's data layer. In this area of the architecture development, there are two equally important concerns the system architect should care about. First is how is the data modeled, the second is how the data is accessed. In this post we explore the second field, the way the data is accessed in a Postgres database server.


The database design and configuration is one of the first activities of the software production life cycle. However, as in the early stages of software development developers are more focused into delivering a viable product than into solving scalability issues, not much work is invested into designing a scalable data layer.


As the development advance, it's very common that these concerns are left behind until one day, some APIs start running slow for no apparent reason. Then is when the technical debt on scalability takes over. The problem is that at this point, the data model is quite more complex, more tables, more relations, and in addition, probably much more records containing real production data.


A good system architect should envision and keep in mind scalability requirements from the very beginning. Questions like: what's more important for this table, readings or writings? How many request per second we are expected to receive if this new feature is released to production? How much this query return grows with the growth of some table?


Postgres server offers four strategies the system architect can make use of to address scalability. They are not exclusive but they compete. In other words, some of them enhance reading, others enhances writings to the database so, their use will depend on the specific requirements at any point of the architecture.


Strategy

Primary purpose

Scaling type

Indexing

Accelerate data retrieval

Query optimization

Partitioning

Organize large tables into smaller physical tables

Data organization

Replication

Distribute read workloads across servers

Horizontal read scaling

Sharding

Distribute data and workloads across servers

Horizontal read/write scaling


1. Indexing

Creates auxiliary data structures (B-tree, GIN, BRIN, etc.) to locate records efficiently.


Pros

  • Dramatically accelerates selective queries, joins, and sorting.

  • Can reduce disk I/O.

  • Relatively simple to implement.

Cons

  • Slows writes due to index maintenance.

  • Consumes storage and memory.

  • Excessive indexing can cause contention.


Use when: Queries frequently filter, join, or sort large datasets.


Avoid when: Tables are tiny, columns are rarely queried, or indexes have little selectivity and provide no other benefit.


2. Partitioning

Divides a logical table into smaller physical tables within PostgreSQL, typically by date, range, or hash.


Pros

  • Partition pruning improves queries targeting specific partitions.

  • Smaller indexes and more manageable maintenance.

  • Efficient historical data deletion by dropping partitions.

  • Can reduce contention in certain workloads.

Cons

  • Does not inherently increase total write capacity.

  • Adds planning, routing, and maintenance complexity.

  • Queries spanning many partitions may become slower.

  • Constraints and unique indexes have limitations across partitions.


Use when: Tables are very large, queries naturally filter by a partition key, or retention management is important.


Avoid when: Tables are relatively small, queries regularly access every partition, or there is no clear partition key.


3. Replication

Maintains copies of PostgreSQL data on additional servers, commonly using streaming replication.


Pros

  • Increases aggregate read throughput.

  • Offloads analytical or expensive read queries.

  • Supports high availability and disaster recovery.

  • Can indirectly free primary resources for writes.

Cons

  • Adds WAL transmission and replication overhead.

  • Does not directly distribute write operations.

  • Asynchronous replicas can return stale data.

  • Synchronous replication can increase commit latency.

  • Requires monitoring, failover management, and additional infrastructure.


Use when: Read workloads saturate the primary, or high availability is required.


Avoid when: The system is primarily write-bound, infrastructure cost is unjustified, or strict read-after-write consistency cannot be accommodated.


4. Sharding

Distributes subsets of data across independent PostgreSQL instances, usually using a distribution key.


Pros

  • Horizontally scales write and read capacity.

  • Distributes CPU, memory, storage, and I/O demands.

  • Can support datasets exceeding one server's capacity.

  • Enables workload isolation.

Cons

  • Distributed joins and transactions become more complicated.

  • Cross-shard queries introduce network overhead.

  • Shard-key selection is critical.

  • Rebalancing data can be expensive.

  • Higher operational complexity.


Use when: A single PostgreSQL instance cannot handle the workload despite reasonable optimization and vertical scaling.


Avoid when: The workload fits comfortably on one server, relationships require frequent cross-shard joins, or the team cannot justify distributed-system complexity.


5. Side-by-side comparison

Capability

Indexing

Partitioning

Replicas

Sharding

Faster selective reads

Excellent

Conditional

More capacity

More capacity

Higher write throughput

Usually negative

Conditional

Indirect at best

Yes

More total storage capacity

No

No*

No*

Yes

Read workload distribution

No

Limited

Yes

Yes

Query transparency

Yes

Yes

Routing needed

Middleware needed

Operational complexity

Low

Medium

Medium

High

Distributed joins

N/A

Not needed

N/A

Potentially costly

*Partitioning and replication may use additional storage, but they do not inherently increase the logical capacity of a single PostgreSQL primary.


6. Recommended optimization order


1 - Indexing & query optimization

Fix inefficient queries and access paths


2 - Partitioning

Manage large tables and retention


3 - Read replicas

Scale read concurrency and improve availability


4 - Sharding

Scale beyond one primary's capacity


This is a useful general progression, not a mandatory sequence. For example, replication may be needed early for high availability, and partitioning may never be necessary.


Bottom line: Indexing optimizes how rows are found. Partitioning optimizes how data is organized. Replication increases how many reads can be served. Sharding increases how much workload can be distributed across independent servers.



 
 
 

Comments


Commenting on this post isn't available anymore. Contact the site owner for more info.
bottom of page