Showing posts with label PostgreSQL. Show all posts
Showing posts with label PostgreSQL. Show all posts

Saturday, 5 September 2026

PostgreSQL Crash Recovery: An Oracle DBA’s View

  The first PostgreSQL crash I handled felt unusually quiet. I was prepared to mount the database, check the required logs and start a recovery procedure. Instead, PostgreSQL detected the unclean shutdown, replayed WAL and opened the database without any DBA command.

That automatic restart can make crash recovery appear simpler than it really is. Recovery time still depends on checkpoint activity, WAL volume, storage performance and the availability of required WAL files. A database that normally starts in seconds can behave very differently after a write-heavy workload or storage incident.



Saturday, 25 July 2026

pg_switch_wal() in PostgreSQL: Small Command, Big Recovery Impact

A PostgreSQL database can look completely healthy until the day you try to restore it.


Backups are available. WAL archiving is enabled. The archive directory has files. Monitoring shows green. Then, during PITR, PostgreSQL throws something like:


could not locate required checkpoint record

or recovery stops before the target time because the WAL needed for that moment was never archived.

This is where many DBAs learn an uncomfortable lesson: the WAL segment that contains the changes you need may still be sitting inside pg_wal/ as the active segment. It has not filled up yet, so the archiver has not copied it.

On a busy system, WAL segments rotate quickly. On a quiet database, the same 16 MB segment may remain open for hours or even days.

pg_switch_wal() is the function that forces PostgreSQL to close the current WAL segment and move to the next one.
It sounds simple. In recovery work, backup validation, and archive troubleshooting, it is extremely useful.


What pg_switch_wal() Actually Does

PostgreSQL writes every change to the Write-Ahead Log before the actual data file change is considered safe. WAL is split into segment files, normally 16 MB each, stored under pg_wal/.

A typical WAL file looks like this:
000000010000000000000019

That filename contains: Timeline ID Log ID & Segment number
Normally, PostgreSQL closes a WAL segment only when it becomes full.

 When you execute:

SELECT pg_switch_wal();


PostgreSQL forces the active WAL segment to finish early and starts writing into a new segment.
Operationally, this means:
  • Current WAL segment is closed
  • Remaining space is padded
  • Next WAL segment becomes active
  • Closed segment becomes ready for archiving
  • Function returns the LSN where the switch happened

The return value may look like this: 0/2B7A9C0

That is the LSN where the WAL switch happened.

0 = upper 32 bits of the byte position
2B7A9C0 = lower 32 bits in hexadecimal

Converting: 0x2B7A9C0 = 45,590,976 bytes, approximately 43.5 MB into the WAL stream.

With a 16 MB WAL segment size, this position falls inside the second WAL segment of that timeline range. To identify the WAL file name:

SELECT pg_walfile_name('0/2B7A9C0');

That tells you which WAL segment contains that LSN.

Small detail, but useful during recovery: the returned LSN is the switch location. The file containing that LSN is the segment that was active at the time of the switch and should now become available for archiving.



Why DBAs Use It Before Recovery Testing

The most practical use of pg_switch_wal() is not academic. It is recovery safety.


Imagine this situation:
10:00 - Base backup completed
10:15 - Application made important changes
10:20 - You want PITR to 10:15

But the database is quiet. The WAL segment containing the 10:15 changes is still open. It has not reached 16 MB. Since it is not complete, the archiver has not copied it yet.

Now your archive location looks fine, but recovery does not have the WAL required to reach 10:15.

Before running PITR tests or relying on a precise recovery target, force a WAL switch:
SELECT pg_switch_wal();

Then check whether the segment arrived in the archive destination:

SELECT
    archived_count,
    last_archived_wal,
    last_archived_time,
    failed_count,
    last_failed_wal,
    last_failed_time
FROM pg_stat_archiver;
If last_archived_wal does not move, do not trust your recovery setup yet.


A lot of backup checks only validate that a base backup exists. That is not enough. PostgreSQL recovery needs both the base backup and the required WAL chain.


Missing one WAL file can make an otherwise good backup useless.


Using It to Validate Archive Command

pg_switch_wal() is also one of the fastest ways to test whether archiving is actually working.


First check archive settings:
    SHOW archive_mode;
    SHOW archive_command;

Then force a WAL switch:
    SELECT pg_switch_wal();

Now check archiver status:

SELECT
    archived_count,
    last_archived_wal,
    last_archived_time,
    failed_count,
    last_failed_wal,
    last_failed_time
FROM pg_stat_archiver;

On the OS side, check the archive destination:

ls -ltr /app/postgres/arch/

If the archive command is correct, a new WAL file should appear shortly.

If not, check PostgreSQL logs. Most archive failures are boring but painful:
  • Permission denied
  • Destination full
  • Wrong path
  • NFS stale mount
  • archive_command returns non-zero exit code
  • File already exists
A bad archive command can sit unnoticed for a long time if nobody monitors failed_count.


This is a common DBA blind spot. People monitor database availability, replication lag, and CPU. But archiver failures are often discovered only during restore.

That is too late.




The No-Op Behavior That Confuses People

There is one nuance DBAs should remember. pg_switch_wal() may do nothing if no WAL has been generated since the last switch.

So if you run this twice:
    SELECT pg_switch_wal();
    SELECT pg_switch_wal();

the second call may return the same or nearly same LSN. That does not mean PostgreSQL is broken. It means there was nothing new to switch. To force WAL activity, generate some WAL first.

For example:

CREATE TABLE wal_test_tmp(id int);
DROP TABLE wal_test_tmp;

SELECT pg_switch_wal();
Or, depending on the test:

CHECKPOINT; SELECT pg_switch_wal();

Be careful with unnecessary forced switches on busy systems. Every switch creates a new WAL segment for archiving. If someone puts this into a frequent cron job without thinking, archive volume can increase, storage can fill faster, and backup systems may process more WAL files than needed.

Useful command. Bad habit if abused.




Production Failure Scenarios

1. PITR Fails Even Though Backup Exists

Symptoms:

  • Recovery starts
  • WAL restore works for some files
  • Recovery stops before target time
  • Required checkpoint record not found

Typical cause: The WAL segment containing the target time was never archived.

Fix: SELECT pg_switch_wal();

Then verify:

SELECT last_archived_wal, last_archived_time
FROM pg_stat_archiver;
Operational lesson: never validate PostgreSQL recovery using only the presence of base backups.


2. Archive Destination Fills Up

Symptoms:

  • WAL files accumulating in pg_wal
  • archive_command failing
  • Database disk usage increasing

Check: SELECT failed_count, last_failed_wal, last_failed_time FROM pg_stat_archiver;

OS check: 

df -h

du -sh /home/postgres/arch/

If archiving is broken long enough, pg_wal can grow and eventually threaten database availability.



3. Standby or Backup Lag Caused by WAL Handling


In streaming replication or backup-heavy systems, WAL is the lifeline. If archiving is delayed, replicas or restore jobs may fall behind or fail to fetch required segments.

SELECT
    pg_current_wal_lsn(),
    pg_walfile_name(pg_current_wal_lsn());

For replication:

SELECT
    application_name,
    state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    sync_state
FROM pg_stat_replication;

pg_switch_wal() will not fix a bad replica by itself. But it helps validate whether WAL generation and archiving are behaving as expected.


DBA Insights

Do not treat pg_switch_wal() as a magic recovery command. It does one thing: it closes the current WAL segment and makes it eligible for archiving.

The real DBA work is around validation.

Check whether archiving is enabled:

SHOW archive_mode;

Check whether the command is sane:

SHOW archive_command;

Check whether archiving is progressing:

SELECT archived_count, last_archived_wal, last_archived_time FROM pg_stat_archiver;

Check whether failures are increasing:

SELECT failed_count, last_failed_wal, last_failed_time FROM pg_stat_archiver;

And always check from the OS side:

ls -ltr /home/postgres/arch/

df -h


Common mistakes I have seen:

Assuming base backup success means PITR is safe
Not monitoring pg_stat_archiver
Forgetting quiet databases may not archive WAL quickly
Running pg_switch_wal too frequently without storage planning
Not testing restore until an actual incident
Ignoring archive_command failures because the database is still online

The most dangerous backup system is the one that has never been restored.


FAQs

Does pg_switch_wal() force WAL archiving?

Not directly. It closes the current WAL segment. Once the segment is complete, the archiver can pick it up if archive_mode is enabled and archive_command is working.


Why did pg_switch_wal() return the same LSN twice?

Most likely no WAL was generated between the two calls. Generate a small change, then run it again.


Is it safe to run in production?

Yes, but do not abuse it. Occasional use for backup, PITR validation, or archive testing is normal. Frequent forced switches can increase archive file count and storage pressure.


How do I know the switched WAL was archived?

SELECT last_archived_wal, last_archived_time FROM pg_stat_archiver;
Then confirm at the archive destination: ls -ltr /home/postgres/arch/


Can this fix broken PITR?

It can help if the required WAL is still in the active segment and has not yet been archived. It will not help if the WAL was already lost, deleted, or never generated.


Conclusion

pg_switch_wal() is a small PostgreSQL function, but it sits right in the middle of backup confidence, WAL archiving, and PITR reliability.


It is useful before restore testing, after important changes, and while validating archive behavior. But the command itself is only part of the story. The real discipline is checking whether the WAL segment reached the archive location and whether recovery can actually consume it.


A good DBA does not stop at “backup completed.”
A good DBA asks:
  • Can I restore it?
  • Can I recover to the required time?
  • Do I have every WAL file needed?
  • Did I test this before the outage?
That mindset saves production systems.



Monday, 29 June 2026

pg_gather: PostgreSQL Snapshot Tool Every DBA Should Use

 Assume Its 2 AM. Alerts are firing. CPU is maxed out, connections are piling up, and the application team is already asking for an ETA.

You SSH into the server, open psql, and start your usual routine - check pg_stat_activity, look at locks, scan logs, maybe run a few custom queries you’ve built over the years. Fifteen minutes in, you still don’t have the full picture.

This is exactly where things break down in production - - not because PostgreSQL lacks visibility, but because the data is scattered.

That is where pg_gather changes the game.



Tuesday, 23 June 2026

PostgreSQL vs Oracle: Choosing the Right Database for Your Architecture

  Selecting a database today isn’t just about technology - it's a strategic business decision. In production environments, the choice between PostgreSQL and Oracle Database affects scalability, reliability, compliance, and cost for years. As a DBA, architect, or infrastructure engineer, understanding the trade-offs between these systems can save significant headaches during implementation and future growth.



Tuesday, 16 June 2026

PostgreSQL Checkpoint Tuning for Stable Performance

   If you have been running PostgreSQL in production for a while, you have probably seen this pattern. Everything looks fine on the surface, queries are tuned, indexes are in place, and yet the system slows down at regular intervals. No obvious reason. No runaway query. Just sudden latency.

In many of these cases, the real issue is not in the foreground workload but in the background engine, specifically checkpoints.



Friday, 12 June 2026

PostgreSQL HugePages Explained for DBAs

   If you have spent years tuning Oracle Database, HugePages is probably second nature to you. You would not even think about running a large SGA without it.

Now, when moving into PostgreSQL, many DBAs assume memory works differently or that HugePages are optional. Technically, they are optional. Practically, ignoring them in a serious production system is a mistake I have seen more than once.


PostgreSQL relies heavily on shared memory, especially for its buffer cache. As systems scale and memory grows into tens or hundreds of GB, the way Linux manages memory pages starts to matter a lot. That is where HugePages step in.

In this article, I will walk through how HugePages behave in PostgreSQL, how they differ from Oracle, and what actually matters when you enable them in real production environments. More importantly, I will share the kind of operational lessons you only learn after seeing systems misbehave at 2 AM.



Sunday, 7 June 2026

PostgreSQL Performance Tuning That Survives Production

    A PostgreSQL performance issue rarely starts with one bad setting.

In production, it usually looks like this: the application team says the database is slow, CPU is not always high, storage graphs look confusing, and nobody changed anything “major”. Then we check deeper and find long transactions, dead tuples, stale statistics, unused indexes, chatty application queries, or checkpoint pressure.



Thursday, 4 June 2026

PostgreSQL VACUUM: Bloat, Autovacuum and Real Fixes

    A PostgreSQL table can grow quietly for weeks before anyone notices. The application team says they already deleted old data. Storage still looks high. Queries are touching more blocks than expected. Autovacuum is running, but the table does not seem to become smaller. This is where many DBAs first realize that DELETE in PostgreSQL is not the same as physically removing rows from the table file.

PostgreSQL uses MVCC, so old row versions remain inside the table until VACUUM can clean them. This is normal behavior, not a bug. The problem starts when dead tuples grow faster than VACUUM can remove them, or when long-running transactions prevent cleanup. Then you get table bloat, index bloat, stale statistics, poor plans, unnecessary I/O, and sometimes transaction ID wraparound pressure.



Thursday, 14 August 2025

Celebrating Freedom with PostgreSQL: A Tribute on India's Independence Day

 As India marks 78 years of freedom, it’s a perfect moment to draw some  parallels between our nation’s journey and our favorite open-source database, PostgreSQL. This Independence Day, let’s explore how the spirit of freedom and innovation reflects in both our national history and PostgreSQL’s capabilities.


Sunday, 1 December 2024

Addressing Query Slowness in PostgreSQL: A Comprehensive Guide

In my previous blog post, we delved into the impact of Re-Indexing to boost database performance. Again, Experiencing slow queries in PostgreSQL can be frustrating, especially when they disrupt the performance of your applications. Fortunately, there are several strategies to identify and resolve the root causes of query slowness. Below, I’ve compiled some key recommendations to help you optimize query performance in your PostgreSQL database.


Saturday, 23 November 2024

Exploring the Key Differences Between pglogical and Native Logical Replication in PostgreSQL

Hey, PostgreSQL enthusiasts! 🌟 Ready to dive into the fascinating world of logical replication?



Sunday, 15 September 2024

Oracle to Postgres Migration: A Whirlwind Adventure! 🌪️

Set sail on a daring voyage from the shores of Oracle to the exotic lands of Postgres migration! Embark on a journey of database transformation as we delve into the intricacies of migrating from Oracle to Postgres. 🚀🔍Discover essential tips and strategies for seamless conversion, ensuring a smooth transition between these powerful database systems.



Sunday, 11 August 2024

Oracle to Postgres Migration Tips Unveiled!

 Hello, data enthusiasts! Today, we’re embarking on an exciting journey from Oracle to Postgres. We’ll explore how to handle schema changes and share helpful tips to make your transition to Postgres as smooth as possible. Let’s get started!



Sunday, 7 July 2024

The Curious Case of "No Space Left on Device" in PostgreSQL

 Hey there, PostgreSQL adventurers! 🌟 Ever encountered the mysterious error message "No space left on device" while trying to start your Postgres instance or connect to your beloved database,Only to find that your disk space is as abundant as ever? Fear not, for I'am about to embark on a thrilling journey to uncover the hidden culprit behind this puzzling phenomenon. Let's dive in!



Sunday, 30 June 2024

Reindexing: Maximizing PostgreSQL Performance

In my previous blog post, we delved into the impact of memory parameters on database performance. Now, let's shift our focus to another crucial aspect: reindexing in PostgreSQL and its profound influence on enhancing database performance.


Sunday, 17 March 2024

Memory Matters: Optimizing Performance in PostgreSQL

When it comes to PostgreSQL, memory usage boils down to two main tasks, each managed by its own set of parameters:



Sunday, 5 November 2023

A Case Study: Oracle Database vs. PostgreSQL

 Considering the best database management system for your organization? Let's explore the key differences between Oracle Database and PostgreSQL, two powerful contenders in the database landscape.



Sunday, 8 October 2023

Facts: Native vs pglogical Logical Replication in PostgreSQL

Here are some of the facts about Native vs pglogical Logical Replication in PostgreSQL 



Tuesday, 5 September 2023

Trace performance issues in PostgreSQL using the pg_stat_statements

👉 The pg_stat_statements view is a PostgreSQL extension that provides information about the execution statistics of all SQL statements that have been executed by the PostgreSQL server. 



Sunday, 6 March 2022

PostgreSQL VACUUM and MVCC

   PostgreSQL uses MVCC (multi-version concurrency control) to provide transactional semantics. In the simplest form, MVCC lets each transaction work on a different copy of a row in a table. What it means is whenever a row is updated, a new version of the row is created.