In many real production databases, we often see some tables receiving high-frequency updates (millions per day) and autovacuum running repeatedly (hundreds of times per day). Additionally, those tables can sometimes become heavily bloated. The end effect is poor performance, poor concurrency, and an unmanageable database.
In case we are using methods pg_gather for diagnosis, such anomalies are easy to spot by clicking on the table header to sort.
Very often, a closer look at these tables reveals that status-update workloads are driving these heavy updates. Many times, even the table names reveal their purpose through words like “task”, “queue”, or “bucket”. A discussion with application architects often reveals that these tables are used for specific workflows, with status fields tracking what is completed and what remains pending for further processing. There can also be multiple workflow stages. Sounds like use case for Kafka, right? Yes, Kafka is widely used to manage such workflows.
While this is happening on the database side, the buzz around “Just use PostgreSQL” is becoming increasingly popular. System designers and architects want to reduce the complexity of maintaining multiple components and dealing with operational issues. More complexity implies more potential failures. Recently, Chandan Shukla wrote a blog post titled PostgreSQL as a Workflow Engine: Building Reliable Long-Running AI Jobs Without Kafka, detailing trade-offs and considerations for building a simple yet reliable workflow engine using simple methods.
Yet, critical questions remain:
Yes, we can. Furthermore, when building modern enterprise applications where data arrives as even
[...]Some of you may have seen our pgEdge Starfleet announcement, and be pondering the question of “why?” Why did we build it, why now, and does the world really need another cloud Postgres service?It's a fair question, and the answer starts where most things at pgEdge start: with our customers.
On 22 September, the Toulouse PUG met, organized by
Speakers:
On 23 September 2026, the Postgres Meetup Group Valencia met, organized by
Speakers:
On 23 September 2026, the Hamburg PostgreSQL User Group met, organized by Joshua Steinmann and Tobias Alvermann.
Speakers:
On 23 September 2026, the PostgreSQL User Group Vienna met, organized by Cornelia Biacsics and Ranjeet Kumar.
Speakers:
On 24 September 2026, the PostgreSQL Edinburgh Meetup-Group met, organized by Jimmy Angelakos. Daniel Roe delivered a talk.
On 14 September 2026, the Bay Area Postgres Meetup Group met. Organized by Elizabeth Christensen. Elizabeth Christensen and Lukas Fittl delivered a talk.
Since I started building packages separately on each supported RHEL minor version, there has been a repository RPM for each minor version (9.6, 9.7, 9.8, 10.0, ...) in addition to the one for the major versio (9, 10). All of them share the same package name, and the minor version specific ones are also published in the repository of the latest minor version. As a result, dnf update replaced the major version repository RPM with the one of the latest minor version at that time, which then stayed on that minor version forever, even after the OS moved to a newer one.
I just fixed that issue. Please update the repo RPMs at your earliest convenience. Read the details here:
https://yum.postgresql.org/news/repo-rpms-follow-os-minor-version/
Issue detail: https://github.com/pgdg-packaging/pgdg-rpms/issues/215
I'd like to thank Daryl Herzmann for the report, analysis and testing.
Two years ago I compared pg_repack and pg_squeeze, the two extensions most of us reach for when a table has bloated beyond what autovacuum will ever give back and VACUUM FULL isn't an option.
PostgreSQL 19 changes the starting point. REPACK brings VACUUM FULL and CLUSTER together under one command, and REPACK (CONCURRENTLY) does the rewrite online. It needs no extension and no shared_preload_libraries, so it works on managed services too. That will bring online repacking to a much wider audience, so I spent the last few weeks measuring what it actually does to a running database, and how it compares with the two extensions.
Rewriting a table is easy when nobody is using it. VACUUM FULL takes an ACCESS EXCLUSIVE lock, copies the live rows into a new file, rebuilds the indexes and swaps the files. Nobody can read or write the table in the meantime, and on a big table that's minutes or hours.
The online version REPACK (CONCURRENTLY) does the same. Except you can use the table while it's being copied and hence it keeps changing while the process runs. A row copied in the first few seconds can get updated two minutes later. Or deleted. An online repack tool needs to do three things.
REPACK gets the first two steps for free from logical decoding. The mechanism logical replication is using. It starts by creating a temporary replication slot, which gives it a snapshot. Point in time for the initial copy. Because every change that happens during that phase is written to WAL anyway, a background work
The phrase now appears on almost every technology vendor’s website. That’s exactly why it has stopped meaning much.
A database is called AI-ready because it supports vectors. A cloud platform is AI-ready because it offers foundation models. A data platform is AI-ready because it can build a RAG pipeline. An application platform is AI-ready because somebody added a copilot.
These capabilities matter, but none of them answers the harder enterprise question: can the organisation safely turn its existing data, systems, processes and business rules into trusted AI-assisted or autonomous outcomes?
That’s a much higher bar. Think of an organisation with fragmented data, decades of applications, several clouds, conflicting sources of truth, regulatory obligations and a board asking when agents will reach production. For that organisation, “AI-ready” can’t mean starting again with a pristine architecture. It has to mean something more practical:
An organisation is AI-ready when it can introduce increasingly capable AI without losing control of data, authority, outcomes or evidence.
That changes the conversation. The question is no longer simply “Can we run AI?” It becomes a set of harder questions. Where should AI run? What should it know, and what should it be allowed to do? How will we know what happened when something goes wrong? And can the architecture evolve as models, regulations, workloads and business requirements change?
Those are architecture questions.
One of the easiest mistakes in enterprise AI is to start with the model. Which LLM? Do we need an agent? Which vector database? Should we build a knowledge graph? Which orchestration framework becomes the standard?
These are useful questions, but they are rarely the first ones. A better sequence starts with the outcome. What business result are we trying to improve, and what data and context does it require? Which parts of the process should stay deterministic, and where does judg
[...]
TypeSafe opened early access to its Jev model on 15 September 2026, pricing input at $0.042 per million tokens and listing output tokens as free, so at our own estimate of 150 input tokens a support ticket, labelling ten million tickets comes to about $63. Storing those labels in new category and confidence columns is a Postgres backfill on a large table, and when we ran one on a million rows in ten batches, the WHERE clause that picked each batch decided most of what the table paid for it.
Range batches at the default fillfactor, with nothing run between them, took the heap from 269.3 MB to 548.3 MB and nearly doubled the three indexes to 70.1 MB. Only 11.5% of the updates were HOT when we repeated them at fillfactor 90 with a VACUUM after every batch, so the indexes still grew to 64.4 MB. Swapping id between lo and hi for id % 10 = r, and changing nothing else, lifted the HOT share to 96.1% and held the indexes at 36.4 MB against the 35.6 MB they started at. Where range batches wrote 850 MB of WAL, interleaving wrote 455 MB, a lead it kept only until a checkpoint followed every batch and the interleaved run wrote 3 022 MB against 1 025 MB for range batches.
id % 10 batch asks for one row in ten.
id % 10 passes inside one id range before moving to the next kept interleaving's HOT share and wrote 544 MB of WAL with a checkpoint after every range.
ALTER TABLE ... SET (fillfactor = 90) with no rewrite still gave 86.2% HOT on a table loaded at fillfactor 100, and a rewrite by V
You can't read a pg_dump file the way you read a table. To see what is inside, you normally restore it into a PostgreSQL server first.
pg_restore and grep can list the tables without a restore, and even print a table's rows as raw text. They can't filter, sort or join them.
The free PostgreSQL Dump Viewer opens a pg_dump without a server. It replays the dump into a real PostgreSQL inside your browser tab and shows the tables, rows and foreign keys. You can run read-only SQL on it, and the file is never uploaded.
Before restoring a dump, you often need one small answer: is this the right backup, which schemas does it contain, are the rows you need actually there? Starting a server, restoring, waiting and then running one query is sensible for a real recovery. It is too much ceremony for a received backup or a pre-restore check.
Restoring a database puts it back into service; inspecting a dump answers a question about a file.
For inspection, the first things I want are usually the database tree, a table preview, the declared foreign keys, and read-only SQL. If I find what I need, I might export that result as CSV or JSON. If I do not, I have learned that before setting up a server and committing to a restore.
That is why we built the PostgreSQL Dump Viewer. It replays the dump into a real PostgreSQL running inside the browser tab. The file never leaves your computer, and the temporary database is gone when you close the tab.
The result is deliberately narrow: browse schemas and tables, inspect relationships, run read-only PostgreSQL SQL, and export a result. It is not a production restore service.
| PostgreSQL Dump Viewer | Restore into a PostgreSQL se |
|---|
I’m happy to share that I was a guest on the Rails Business podcast and the episode is now live. Here’s a recap of the topics we discussed.
We spent most of the time discussing engineering work last year related to scaling the database workload for peak traffic at Aura where we use Ruby on Rails and PostgreSQL.
I’m presenting this information in two places this fall, Rails at Scale Summit in Austin, TX, and the Postgres Summit in NYC.
Besides the podcast, you can get more details in these posts:
If you’re not able to make those events or prefer to listen to a discussion of the content, then the podcast will have a lot of the same information.
Besides the work at Aura, we also checked in on my book High Performance PostgreSQL for Rails, which has now been available in print for two years. Ryan asked about what’s next for the book, and it’s a difficult question to answer.
With the availability and quality of AI tooling for software engineers, I don’t see developers buying books as much. With fewer prospective readers, the ROI is less attractive for authors and publishers to commit to the resource-intensive process of creating a book.
I’m grateful to have had the opportunity to write a book before the rise of the AI tools. I’m still getting positive feedback from my book which is very fulfilling.
Recently I met Madison Sites who’s a reader, and they shared feedback that they’re reading the book as part of the WNB.rb book club. Madison said the book has been helpful for building vocabulary and familiarity with database concepts and implementation details, and that’s helped with database work and better comprehension for conference talks about similar topics. I appreciated hearing about that!
We segued into how we
[...]
With PGConf.dev 2027 now on the horizon, I found myself thinking back to PGConf.dev 2026 and all the moments that stayed with me.
What started with two accepted talk submissions for the Community Day at PGConf.dev 2026 turned into four days filled with community discussions, anniversary celebrations, hallway conversations, poster sessions, unconference discussions, and countless opportunities to meet the people behind PostgreSQL.
Some moments made me think. Some made me laugh. Others reminded me why I enjoy contributing to this community so much.
Between my first PGConf.dev, my recent transition to Microsoft, two accepted talks, a community coin I didn’t expect, and a brief moment of wondering whether I belonged, this conference turned out to be far more memorable than I anticipated.
Some moments stayed with me...
PGConf.dev 2026 took place in Vancouver, Canada. I decided to arrive a few days early, for several reasons:
I have attended many PostgreSQL conferences in Europe over the years, and one thing I always enjoy is seeing how every event develops its own personality.
PGConf.dev immediately felt different.
PGConf.dev (2024–2026), formerly known as PGCon (2007–2023), it is a conference for people who actively build PostgreSQL. And when I say build PostgreSQL, I do not only mean writing code.
PGConf.dev brings together: PostgreSQL committers and code contributors, Documentation writers, Infrastructure maintainers, Meetup organizers, Community o
[...]October's hacking workshop will cover my talk, pg_plan_advice: Plan Stability and User Planner Control for PostgreSQL?. If you're interesting in joining us, please sign up using this form and I will send you an invite to one of the sessions.
Read more »
A recent question on the community channels described a difficult situation: a standby had been promoted with archive_mode=off, and restarting the new primary was something the team wanted to avoid. Could they enable archiving on a downstream standby and take a pgBackRest backup from there instead?
Their attempt failed with archive_mode must be enabled, even with archive-mode-check=n. Removing the checks from pgBackRest’s source code allowed their proof of concept to succeed, but was that enough to trust the approach?
My recommendation was to return to a supported configuration, either through a restart or a controlled switchover. But I wanted to take a closer look and see whether archive-mode-check=n might allow the standby-based approach.
So, in this post, we’ll try to reproduce the situation, examine what pgBackRest checks, and see why a successful backup and restore don’t tell the whole recovery story.
archive_mode matters
The test environment consists of three VMs running AlmaLinux 10 and PostgreSQL 18: pg1, pg2, pg3. We’ll set up cascading replication: pg1 → pg2 → pg3.
pg1)
Let’s first set up pgBackRest on the primary (pg1):
/etc/pgbackrest.conf:
[global]
repo1-path=/shared
repo1-retention-full=4
log-level-console=info
log-level-file=detail
compress-type=zst
start-fast=y
[demo]
pg1-path=/var/lib/pgsql/18/data
The configuration here is relatively simple: we will store WAL archives and backups on a /shared drive accessible from all hosts involved.
postgresql.conf:
archive_mode = on
archive_command = 'pgbackrest --stanza=demo archive-push %p'
Remember, changing archive_mode requires a PostgreSQL restart, while changing archive_command only requires a reload.
$ pgbackrest --stanza=demo stanza-create
$ pgbackrest --stanza=demo check
$ pgbackrest --stanzaIt’s been a month since I published the first part of this research, and interest from the Postgres community has been higher than I expected. Most vendors I contacted were shy to respond, so the Databricks team’s blog post Collaboration makes us all stronger was one of the first examples of a vendor publicly sharing their side of the story.
In the past four weeks, I spoke with managers of managed Postgres services, security engineers, and red teamers who look for new threats in the services they offer. Here’s what I learned from those conversations:
My initial plan was actually write about PostgreSQL core vulnerabilities but the coordinated work with the vendors takes longer than I expected. As the time flies and given that I only have a 40-minute talk at PGCONF.EU, there’s simply no way I’ll be able to cover everything I gathered in a single session. So I want to share all the things I wont be able to cover at the talk here as a blog post.
In this article you will see the vulnerabilities I have found on PostgreSQL vendors’ security hardening extensions and the broader threat model discussion.
A few months ago, when I first logged in to a managed Postgres provider’s instance, I noticed I didn’t have superuser rights. Still, I could update all the data and set up features that usually require superuser rights. But I wasnt the superuser. This made me wonder how and why they set it up this way.
The answer is pretty simple. When a new PostgreSQL backend starts, custom security extensions step in and check queries to decide if the user
[...]A long time ago I ran a write-heavy system on a hub and a handful of workers. Each worker took a share of the application traffic and wrote events locally. The hub owned the reference data (customers, plans, prices), pushed it down to the workers, and pulled every worker’s events back up to compute the invoices. The plumbing was Londiste and PgQ: triggers on every table, a queue per node, a ticker, and a Python daemon per hop. It worked, and it was a lot of moving parts to explain to anyone new.
Postgres 10 shipped logical replication in 2017, and 19 is the tenth release that has it. Every release since Postgres 10 has taken a piece of that plumbing and made it a line of SQL.
This is the first article in a series about Postgres logical replication use-cases, and about how the feature set has evolved over the past ten years and ten releases. The question is the application developer’s one, not the DBA’s: which architectures can I deploy with Postgres core alone today, what does each release change about that, and where do I still need something else? I built three architectures for real, across three posts:
A fourth post, covering what is left out of this series in less detail — geo-replication, BDR-style multi-active setups, plain CDC and triggers — is also planned.
If I could give one piece of advice to the past me, starting to contribute to open source projects, it’d be to value other developers' time more. It took me a while to appreciate the “economy” behind this, and adjust how I work to increase my chance of getting patches done. Hopefully some new contributors could learn from my mistakes.
On the server this article was written against, pg_stat_statements_info.dealloc reads 20, and that counter is all the database has left to say about forty rows an agent deleted. The forty entries were there while the DELETE statements ran, one per table, counted and timed like anything else. Then the same agent read the schema twice over, 12 800 statements that changed not one row, and the reading needed room.
The eviction is documented behaviour rather than a defect. The view is sized once, at 5 000 entries by default, and once more distinct statements arrive than that the documentation says "information about the least-executed statements is discarded". Run once, a statement is the least-executed thing in the database.
Ordinary application traffic sits at the far end of the axis that policy implies, since an application issues a small set of statements a great many times each. An agent writing its SQL fresh on every turn does the reverse, and the rewriting adds a second cost on top, because a question asked in two shapes occupies two entries and each of those two has been called once.
-- comment and a public. prefix all merged into the baseline, while count(1), a table alias, a swapped predicate order, a subquery and a CTE each took an entry of their own.
queryid on PostgreSQL 18, where 17 kept them apart, and the surviving entry carries the name of whichever schema was queried first.
application_name set to payments-api and one to claude-agent, landed in the same entry, so an agent borrowing the application's login cannot be separated from it after the fact.
track at its default top, a statement inside a PL/pgSQL function or a DO block leaves no entry of its own, and the samRelational databases like Postgres provide many unique features, specifically atomicity, consistency, isolation, and durability (ACID), but providing durability has always been a challenge. Though computers originally used non-volatile magnetic-core memory, the past five decades have been dominated by computer architectures where CPU-accessible memory is volatile, and OS-accessible storage is non-volatile/durable. Postgres uses the write-ahead log (WAL), which is stored on OS-accessible durable storage, to provide durability. (I recently wrote a presentation about WAL, and I have a presentation explaining durability.)
However, using OS-accessible storage for durability adds complexity. What if CPU-accessible memory, where most of the database processing happens, could be made durable in a high-performance and cost-effective way? This has been a goal of memory manufacturers for over twenty years, and it might finally be ending in failure.
Variously called phase change memory (PCM), 3D XPoint, Optane, and non-volatile Compute Express Link (CXL), the technology allows durable CPU-accessible memory to be mixed with volatile DRAM in the same system. This 30-minute video covers the fits and starts of the effort, and its eventual abandonment by Micron and Intel. This 2012 article summarizes frustration with the industry, "Long-derided as a Techno-Ponzi scheme — useful for raising a development budget but never delivering a return — PCM may now finally start earning its way in the world."
Number of posts in the past two months
Number of posts in the past two months
Get in touch with the Planet PostgreSQL administrators at planet at postgresql.org.