Yesterday, I spoke about pg_acm at PGConf.EU. Speaking at the biggest Postgres conference in the world is an honor in itself, and it’s not that I have a chance to present there every year, so I am incredibly thankful to the CfP committee for choosing this talk.
This talk has a long history of rejection and denial of the fact that something could be wrong with Postgres, which made me appreciate this opportunity even more.
My presentation earlier this year at Tallinn PUG definitely helped me shape it better, and I think it went as well as it could have.
Not only do I have a dream, but I also have a request: please try pg_acm and give me feedback! From my perspective, the tool is complete, but I am sure other people will find issues. If you find them, please let me know! Please open an issue on GitHub!
Every major PostgreSQL upgrade I have done on a single primary came with the same conversation: how long can the application be down? is fast, but it is still an outage, and you still have to rebuild or resync the standbys afterwards.A multi-master cluster gives you a different option. Spock is pgEdge's open-source PostgreSQL extension for multi-master logical replication, and with it every node takes writes, so you never have to upgrade a node in place. You add a brand new node on the new major version, let it join the cluster, move traffic to it, and retire the old one. Repeat for every node and the cluster ends up on the new version without the application ever losing a writable endpoint.Starting with PostgreSQL 19, community Postgres offers a blue-green style upgrade built on , and the new sequence sync. This is not really ZERO downtime upgrade because the writes need to be paused for a certain period of time. At cutover, writes have to stop while the last changes drain, sequences are synced and the application is switched over. For a critical application, that pause is still an outage.I tested this end to end on my two node pgEdge test cluster running PostgreSQL 17.10 with Spock 5.0.12, adding a PostgreSQL 18.6 node next to them. This post walks through exactly what I ran, including the things that tripped me up, so you can do the same thing on your own cluster.One note before we start. pgEdge Control Plane is pgEdge's declarative orchestration tool for managing Postgres clusters. If your cluster runs under it, use its built-in major version upgrade instead. It drives the same zero downtime add node process through its API.
Please enjoy the slides and transcript from Tuning Postgres for Analytics at PostgreSQL Conference Europe (PGConf.EU) in Valencia, Spain on 20 Oct 2026.
I'll add a link to the recording once it's available.
I've included just very brief alt-text for each slide image, but I've tried to add any links or other essential information into the body of the blog post.

Obviously, I don't know the specifics of your particular Postgres environment. But, as always, there are some generalisations that apply to most systems. So, just for today, we're going to imagine that you're running a small chain of popular coffee shops in Valencia. If you've seen any of my previous talks, you might start to notice a coffee and cake theme in lots of my talks, demos and examples!
You've implemented a state of the art system to manage your sales, stock, customer loyalty program etc. and you've carefully configured your production database for the needs of your day-to-day application workload.
Let's talk about what happens if you then need to run analytics queries against your application data. How can you do that without compromising the performance of your application?

First, a quick "about me":
I’ve spent my whole career working with databases; for the first 20 years or so as a database administrator. I’m currently a Senior Software Engineer on the Postgres extensions team at Snowflake, working mainly on the pg_lake set of extensions.
I’m actively involved in PostgreSQL Europe; amongst other things, leading the PGEU Diversity Committee and helping to organise pgconf.eu. I also write and present talks (about databases) at Postgres and Developer conferences.
If you want ideas for non-database-related conversation topics when you meet me in the hallway: I love being creative; crocheting cute things, sewing clothes and accessories, and 3D printing all sorts of random things. I also enjoy getting out and about on one of my bikes in the mountains where I live.

Back to the presentation.
Let's
[...]We’re wrapping up our review of the March CommitFest for PostgreSQL 19. This fourth and final article in the series covers the changes related to SQL and to our DEV1 and DEV2 courses.
As a reminder, here’s the plan for our coverage of the final PostgreSQL 19 CommitFest:
Part 5.4 (SQL, DEV1, DEV2) -- you are here 🙂
For the earlier CommitFests, see: 2025-07, 2025-09, 2025-11, 2026-01.
Here’s what’s covered:
...
In my last post, a friend of mine kept four databases in production. Ask a team like that for a knowledge graph, and you can guess the fifth: a triple store. Search over company data, an ontology of products or skills, facts for an LLM application: a knowledge base often means RDF and SPARQL, and usually a separate server next to the relational database.
That server has a cost. The facts it needs already live in PostgreSQL tables, so an ETL job copies them as triples, and the copy goes stale as soon as the job ends. Two databases mean two security models, two backup schedules, two failover procedures, and no transaction that spans a row and a triple.
So I built pg_knowledge_base, a PostgreSQL 19 extension that runs Oxigraph’s SPARQL engine inside the server, without core patches. Triples live in ordinary tables, existing tables are read as RDF through R2RML mappings, and one SPARQL query can use both. Oxigraph’s HTTP endpoints remain for any SPARQL client, while transactions, replication and backups come from PostgreSQL. As with my previous extensions, Claude Code wrote the code, while I made the architectural decisions and checked the results.
Oxigraph is a graph database and RDF toolkit written in Rust, and its stated goal is “a compliant, safe, and fast graph database”. What matters for embedding is that its query stack is a set of small crates: spargebra parses SPARQL, sparopt optimizes it, spareval evaluates it, and sparesults and oxrdfio handle result and RDF formats. spareval evaluates over anything that implements its QueryableDataset trait, so pg_knowledge_base reuses Oxigraph’s parser, optimizer and evaluator and replaces only the storage: PostgreSQL tables instead of RocksDB.
Keeping the engine keeps its answers. Of the W3C SPARQL 1.1 query and update tests, 990 pass and none fails. Another 11 differ from the expected results exactly as Oxigraph’s own store does, mostly because it keeps typed literals as values ("01"^^xsd:integer comes back as 1), and 6 are skipped,
geos315: 3.15.0
proj98: 9.8.1
libgeotiff17: 1.7.4
librttopo: 1.1.0
libspatialite50: 5.1.0
gdal313 (with the Python 3.13 and Java bindings): 3.13.3
SFCGAL: 2.3.0
PostGIS (postgis33 ... postgis37): 3.3.10, 3.4.6, 3.5.7, 3.6.4, 3.7.0 RC
pgRouting: 4.0.2
ogr_fdw: 1.1.9
h3-pg: 4.5.0
postgis_tiger_geocoder: 2025.2
Postgres gives you no way to take back a single statement. When someone runs an UPDATE without its WHERE clause, recovery is a procedure rather than a command. You restore a copy of the database to the moment before the mistake, pull out the rows that were damaged, and reconcile them by hand against a live table that has kept moving since.This kind of recovery works, and teams do it. It also takes hours, needs your most senior person, and every step is a chance to make things worse while the table is still serving traffic. One second of bad SQL turns into an afternoon of careful work by the people you can least afford to tie up.Oracle users have Flashback for exactly this case, and it is really two features: one to read the past, one to put it back. Postgres has neither. Point in time recovery is what makes that procedure possible, but it recovers an entire cluster rather than a statement. You restore it alongside production and compare, because rewinding production itself would discard everything that happened after the mistake. I wanted something smaller and more precise, so I built pgVolvra.
Another story of something I saw in the field which surprised me. Turns out recovery_prefetch can cause outages.
Something which has been happening quietly in the background all the time, but we didn’t notice until we looked close enough to see it.
After a lot of work I discovered this was partly a case where someone had dropped an email to the postgres hackers list years ago “hey what about this” and everyone thought “nah it can’t be that bad” … and now here we are seeing production outages!
Exhibit A: Feb 2021, while the feature was being developed, a year and a half before it shipped, Stephen Frost
https://www.postgresql.org/message-id/20210214231815.GO27507@tamriel.snowman.net
Exhibit B: Mar 2025, clear report from the field, Michael Zhilin (Postgres Pro)
https://www.postgresql.org/message-id/9bdb428a-fc8e-4801-8fff-1ad0bc6f
[...]This is the second post in a series exploring graph databases and PostgreSQL. The first post covered what graphs are, what can be modeled as a graph, and the landscape of graph database systems. This post moves from the general to the specific: how we query graphs, why SQL can be an awkward fit, and what SQL/PGQ changes. It ends with the PostgreSQL implementation, why it was reverted, and a few notes on the main features still to come.
In the previous post, we ended on the observation that graph databases come in many forms, and that they differ in how they store graphs and what data models they support. They also differ in how you question them.
Unlike the relational world, which converged on SQL early and kept it as the dominant standard for decades, the graph ecosystem produced a proliferation of query languages:
(a:Person)-[:KNOWS]->(b:Person);
g.V().hasLabel('Person').out('KNOWS');
For this series, the relevant one is SQL/PGQ[5], standardized as part of SQL:2023. It is an extension of SQL that lets you define property graphs over existing tables and query them with GQL- and PGQL-like pattern syntax inside a standard SELECT.
Consider a social network stored in two tables: person and knows.
A Cypher query asking for friends of friends looks like this:
MATCH (a:Person)-[:KNOWS]->(b)-[:KNOWS]->(c)
WHERE a.name = 'Alice'
RETURN c.name
The equivalent in plain SQL is a two-way self-join:
SELECT DISTINCT c.name
FROM person a
JOIN knows k1 ON k1.src = a.id
JOIN person b ON k1.dst = b.id
JOIN knows k2 ON k2.src = b.id
JOIN person c ON k2.dst = c.id
WHERE a.na[...]
A friend of mine is an excellent architect but a complete snob. He has four different databases in production: PostgreSQL for OLTP, ClickHouse for OpenTelemetry data and web analytics, Elasticsearch for full-text search in the application, and MongoDB, “for historical reasons.”
In between, there are ETL and CDC pipelines, plus on-call developers hunting for where exactly the results don’t match. To him, it’s all a well-thought-out architecture; to me, it’s needless complexity in maintenance and development.
The other day I told him what I’ve been working on lately.
“I’ve managed to plug ClickHouse’s MergeTree table engine into PostgreSQL as a table access method, on a vanilla database core, without a fork, and with a vectorized query executor reading from it.”
“What for? Just use ClickHouse and spare yourself the pain.”
“Because I need JOINs across lots of tables, consistent data throughout the system, and one platform that’s familiar to develop and maintain.”
“That’s not how it works. It’s either reliable or fast!”
“Well, I’ve managed to combine the best of both worlds.”
“Wait a minute. Didn’t you just port Greenplum into a Postgres extension and then write a vectorized executor on top of it? What do you need MergeTree for?”
“Vectorization grinds through columns fast, but it chokes the moment it has to read the data.”
The backstory began when I ported Apache Cloudberry to PostgreSQL 19 as a set of extensions, which got me ORCA, Greenplum’s cost-based planner, on PostgreSQL 19. On top of that query optimizer I developed pg_vexec, a vectorized executor without a single core patch.
Its nodes, VecScan, VecHashJoin, VecAgg and VecSort, get into a query plan through the database’s standard extension mechanisms and compete with the ordinary nodes on cost. ORCA prices the vector nodes with its own cost model. Inside, the executor processes batches of 1,024 rows in columnar form with kernels bound to function OIDs. Where there is no dedic
[...]The PostGIS Team is pleased to release PostGIS 3.7.0rc3! Best Served with PostgreSQL 19 RC 1 , GEOS 3.15.0 , postgis_tiger_geocoder 2025.2 , and address_standardizer.
This version requires GEOS 3.10+, PostgreSQL 14-19beta3, Proj 6.1+, and libgmp. To take advantage of all postgis extension features, GEOS 3.15+ is needed. To take advantage of all postgis_sfcgal extension features SFCGAL 2.3+ is needed. Python 3 is a new requirement to build the documentation. Visual examples in the docs are off by default. To build docs with them, configure with --with-visual-examples and make sure you have a running PostgreSQL instance; they are then generated automatically when building the docs (or explicitly with make -C regress visual-examples).
This release contains fixes since 3.7.0rc3 release.
Cheat Sheets:
This release is a release candidate of a major release, it includes bug fixes since PostGIS 3.6.4 and new features.
We’re continuing our review of the March CommitFest for PostgreSQL 19. This third article in the series covers the changes related to our DBA3 and DBS courses.
As a reminder, here’s the plan for our coverage of the final PostgreSQL 19 CommitFest:
Part 5.3 (DBA3, DBS) -- you are here 🙂
Part 5.4 (SQL, DEV1, DEV2)
For the earlier CommitFests, see: 2025-07, 2025-09, 2025-11, 2026-01.
Here’s what’s covered:
...
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.