<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://postgres.ai/blog</id>
    <title/>
    <updated>2026-11-05T12:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://postgres.ai/blog"/>
    <icon>https://postgres.ai/favicon.svg</icon>
    <rights>PostgresAI</rights>
    <entry>
        <title type="html"><![CDATA[UUIDv4 vs UUIDv7: what a random primary key costs in Postgres]]></title>
        <id>https://postgres.ai/blog/20261105-uuidv4-vs-uuidv7</id>
        <link href="https://postgres.ai/blog/20261105-uuidv4-vs-uuidv7"/>
        <updated>2026-11-05T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[Same table, same insert stream, three primary keys on Postgres 18. At 100M rows, UUIDv4 inserted at 0.62 to 0.69 of the rate of an ordered key on the same server, and wrote 1.5 to 1.9 times the WAL per row. Where the cost starts, and what it is made of.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="performance" term="performance"/>
        <category label="UUID" term="UUID"/>
        <category label="WAL" term="WAL"/>
        <category label="Postgres.FM" term="Postgres.FM"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[What your Postgres is waiting for, and why the dashboard can't tell you]]></title>
        <id>https://postgres.ai/blog/20261103-what-postgres-is-waiting-for</id>
        <link href="https://postgres.ai/blog/20261103-what-postgres-is-waiting-for"/>
        <updated>2026-11-03T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[Wait events, explained for everyone: what the live flag means, how every dashboard samples it, and one measured incident where the dashboard's own fixes did nothing and the cause was a lock it ranked fifth, at 2%.]]></summary>
        <author>
            <name>Dmitry Fomin</name>
            <email>dmitry@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="monitoring" term="monitoring"/>
        <category label="wait events" term="wait events"/>
        <category label="performance" term="performance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Dump/restore done. Now what?]]></title>
        <id>https://postgres.ai/blog/20261028-dump-restore-now-what</id>
        <link href="https://postgres.ai/blog/20261028-dump-restore-now-what"/>
        <updated>2026-10-28T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[After pg_dump and pg_restore, by default the planner statistics and the visibility map are missing. One query: 32.6 s before VACUUM ANALYZE, 23 ms after.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="performance" term="performance"/>
        <category label="maintenance" term="maintenance"/>
        <category label="pg_restore" term="pg_restore"/>
        <category label="Postgres.FM" term="Postgres.FM"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[DBLab 4.2: clone upgrades, simplified install, retention, and more]]></title>
        <id>https://postgres.ai/blog/20260917-dblab-engine-4-2-released</id>
        <link href="https://postgres.ai/blog/20260917-dblab-engine-4-2-released"/>
        <updated>2026-09-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[DBLab 4.0 made database branching instant. 4.1 added the controls around it — protection leases, Teleport, metrics. 4.2 closes the last item on 4.1's own roadmap — testing a Postgres major version upgrade on a clone — and removes the two remaining points of friction around it: getting configured in the first place, and cleaning up what accumulates afterwards.]]></summary>
        <author>
            <name>Denis Morozov</name>
            <email>denis@postgres.ai</email>
        </author>
        <category label="Product announcements" term="Product announcements"/>
        <category label="DBLab Engine" term="DBLab Engine"/>
        <category label="Database Lab Engine" term="Database Lab Engine"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[DBLab 4.1: protection leases, Teleport, Prometheus, and more]]></title>
        <id>https://postgres.ai/blog/20260408-dblab-engine-4-1-released</id>
        <link href="https://postgres.ai/blog/20260408-dblab-engine-4-1-released"/>
        <updated>2026-04-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[DBLab 4.0 introduced instant database branching with O(1) economics. With 4.1, we're making it safe to hand off to a platform team: automatic resource governance, enterprise access control, production-safe data refresh, and native observability.]]></summary>
        <author>
            <name>Denis Morozov</name>
            <email>denis@postgres.ai</email>
        </author>
        <category label="Product announcements" term="Product announcements"/>
        <category label="DBLab Engine" term="DBLab Engine"/>
        <category label="Database Lab Engine" term="Database Lab Engine"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[PG18 preserves planner statistics on upgrade — even from PG14]]></title>
        <id>https://postgres.ai/blog/20260324-pg18-stats-upgrade-across-versions</id>
        <link href="https://postgres.ai/blog/20260324-pg18-stats-upgrade-across-versions"/>
        <updated>2026-03-24T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[Postgres 18 can preserve planner statistics during major version upgrades. But can it work when upgrading from an older version to PG18 — which many plan to do soon? Let's test and see.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="PostgreSQL" term="PostgreSQL"/>
        <category label="pg_upgrade" term="pg_upgrade"/>
        <category label="performance" term="performance"/>
        <category label="major upgrades" term="major upgrades"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[How moving one word can speed up a query 10–50x]]></title>
        <id>https://postgres.ai/blog/20260311-not-exists-vs-exists-partial-index</id>
        <link href="https://postgres.ai/blog/20260311-not-exists-vs-exists-partial-index"/>
        <updated>2026-03-11T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[One of these queries is 32x faster than the other. Which one, and why?]]></summary>
        <author>
            <name>Maxim Boguk</name>
            <uri>https://www.linkedin.com/in/maxim-boguk-b1bb9980/</uri>
        </author>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="performance" term="performance"/>
        <category label="indexing" term="indexing"/>
        <category label="SQL" term="SQL"/>
        <category label="partial index" term="partial index"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The hidden cost of invalid indexes in Postgres (yes, even on Supabase/RDS/Neon)]]></title>
        <id>https://postgres.ai/blog/20260106-invalid-index-overhead</id>
        <link href="https://postgres.ai/blog/20260106-invalid-index-overhead"/>
        <updated>2026-01-06T01:23:45.000Z</updated>
        <summary type="html"><![CDATA[When CREATE INDEX CONCURRENTLY or REINDEX INDEX CONCURRENTLY fails, Postgres leaves behind an invalid index. Many engineers assume these indexes are harmless placeholders waiting to be cleaned up. After all, the planner won't use them for queries, right?]]></summary>
        <author>
            <name>Dmitry Fomin</name>
            <email>dmitry@postgres.ai</email>
        </author>
        <category label="Postgres" term="Postgres"/>
        <category label="indexes" term="indexes"/>
        <category label="performance" term="performance"/>
        <category label="internals" term="internals"/>
        <category label="maintenance" term="maintenance"/>
        <category label="HealthyPostgres" term="HealthyPostgres"/>
        <category label="Index maintenance" term="Index maintenance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-013: Why keep your index set lean]]></title>
        <id>https://postgres.ai/blog/20251110-postgres-marathon-2-013-why-keep-your-index-set-lean</id>
        <link href="https://postgres.ai/blog/20251110-postgres-marathon-2-013-why-keep-your-index-set-lean"/>
        <updated>2025-11-10T23:59:59.000Z</updated>
        <summary type="html"><![CDATA[Your API is slowing down. You check your database and find 42 indexes on your users table. Which ones can you safely drop? How much performance are they costing you? Let's look at what actually happens in Postgres when you have too many indexes.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="indexes" term="indexes"/>
        <category label="performance" term="performance"/>
        <category label="maintenance" term="maintenance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-012: Ultra-fast replica creation with pgBackRest]]></title>
        <id>https://postgres.ai/blog/20251105-postgres-marathon-2-012-ultra-fast-replica-creation-pgbackrest</id>
        <link href="https://postgres.ai/blog/20251105-postgres-marathon-2-012-ultra-fast-replica-creation-pgbackrest"/>
        <updated>2025-11-05T23:59:59.000Z</updated>
        <summary type="html"><![CDATA[Suppose you need to create a replica for a 1 TiB database. You have a fast server with NVMe storage and 75 Gbps network, but pg_basebackup typically delivers only 300-500 MiB/s due to its single-threaded architecture — regardless of how powerful your hardware is (though PG18 brings a surprise we'll discuss later).]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <author>
            <name>Maxim Boguk</name>
            <uri>https://www.linkedin.com/in/maxim-boguk-b1bb9980/</uri>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="cloning" term="cloning"/>
        <category label="pgBackRest" term="pgBackRest"/>
        <category label="performance" term="performance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-011: Prepared statements and partitioned tables — the paradox, part 3]]></title>
        <id>https://postgres.ai/blog/20251030-postgres-marathon-2-011</id>
        <link href="https://postgres.ai/blog/20251030-postgres-marathon-2-011"/>
        <updated>2025-10-30T23:59:59.000Z</updated>
        <summary type="html"><![CDATA[In #PostgresMarathon 2-009 and #PostgresMarathon 2-010, we explored why execution 6 causes a lock explosion when building a generic plan for partitioned tables — the planner must lock all 52 relations because it can't prune without parameter values.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
        <category label="prepared statements" term="prepared statements"/>
        <category label="partitioning" term="partitioning"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-010: Prepared statements and partitioned table lock explosion, part 2]]></title>
        <id>https://postgres.ai/blog/20251029-postgres-marathon-2-010</id>
        <link href="https://postgres.ai/blog/20251029-postgres-marathon-2-010"/>
        <updated>2025-10-29T23:59:59.000Z</updated>
        <summary type="html"><![CDATA[In #PostgresMarathon 2-009, we focused on Lock Manager's behavior when dealing with prepared statements and partitioned tables.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
        <category label="prepared statements" term="prepared statements"/>
        <category label="partitioning" term="partitioning"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-009: Prepared statements and partitioned table lock explosion, part 1]]></title>
        <id>https://postgres.ai/blog/20251028-postgres-marathon-2-009</id>
        <link href="https://postgres.ai/blog/20251028-postgres-marathon-2-009"/>
        <updated>2025-10-28T12:00:00.000Z</updated>
        <summary type="html"><![CDATA[In #PostgresMarathon 2-008, we discovered that prepared statements can dramatically reduce LWLock:LockManager contention by switching from planner locks (which lock everything) to executor locks (which lock only what's actually used). Starting with execution 7, we saw locks drop from 6 (table + 5 indexes) to just 1 (table only).]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
        <category label="prepared statements" term="prepared statements"/>
        <category label="partitioning" term="partitioning"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-008: LWLock:LockManager and prepared statements]]></title>
        <id>https://postgres.ai/blog/20251014-postgres-marathon-2-008</id>
        <link href="https://postgres.ai/blog/20251014-postgres-marathon-2-008"/>
        <updated>2025-10-14T23:59:59.000Z</updated>
        <summary type="html"><![CDATA[As was discussed in #PostgresMarathon 2-002, for a simple SELECT from a table, at planning time, Postgres locks the table and all of its indexes with AccessShareLock. A simple demo to remind it (let me be a bit weird here and save some bytes when typing SQL):]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
        <category label="prepared statements" term="prepared statements"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-007: Should we worry about pg_blocking_pids()'s observer effect?]]></title>
        <id>https://postgres.ai/blog/20251013-postgres-marathon-2-007</id>
        <link href="https://postgres.ai/blog/20251013-postgres-marathon-2-007"/>
        <updated>2025-10-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Many years ago, when developing complex automated procedures for a large company, I realized that my automation needs monitoring components. Including understanding heavyweight lock contention – for example, to recognize situations when a poorly designed change is blocked by things like autovacuum running in transaction ID wraparound prevention mode (it doesn't yield to anybody, when in this mode).]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
        <category label="monitoring" term="monitoring"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-006: Mysterious max_locks_per_transaction]]></title>
        <id>https://postgres.ai/blog/20251010-postgres-marathon-2-006</id>
        <link href="https://postgres.ai/blog/20251010-postgres-marathon-2-006"/>
        <updated>2025-10-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The setting maxlockspertransaction is mysterious, it is a good illustration of Socrates' "I know that I know nothing". This is the main fact to memorize about maxlockspertransaction. Don't try to remember details. Unless you touch it often, you'll forget (I do). Instead, let's rely on the docs:]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-005: More LWLock:LockManager benchmarks for Postgres 18]]></title>
        <id>https://postgres.ai/blog/20251009-postgres-marathon-2-005</id>
        <link href="https://postgres.ai/blog/20251009-postgres-marathon-2-005"/>
        <updated>2025-10-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[In 2023-2024, after incidents that multiple customers of PostgresAI experienced, when production nodes were down because of LWLock:LockManager contention, we studied it in synthetic environments.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-004: Fast-path locking explained]]></title>
        <id>https://postgres.ai/blog/20251008-postgres-marathon-2-004</id>
        <link href="https://postgres.ai/blog/20251008-postgres-marathon-2-004"/>
        <updated>2025-10-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[After 2-003, @ninjouz asked on X:]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-003: The roots of LWLock:LockManager]]></title>
        <id>https://postgres.ai/blog/20251007-postgres-marathon-2-003</id>
        <link href="https://postgres.ai/blog/20251007-postgres-marathon-2-003"/>
        <updated>2025-10-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[As we discussed, Lock Manager manages heavyweight locks – various kinds of them (various modes, various levels of granularity). These locks are released only at the end of the transaction.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[#PostgresMarathon 2-002: Relation-level locks]]></title>
        <id>https://postgres.ai/blog/20251005-postgres-marathon-2-002</id>
        <link href="https://postgres.ai/blog/20251005-postgres-marathon-2-002"/>
        <updated>2025-10-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Let's talk about relation-level locks and various confusions, surprises and what is worth to remember in practice.]]></summary>
        <author>
            <name>Nikolay Samokhvalov</name>
            <email>nik@postgres.ai</email>
        </author>
        <category label="Postgres insights" term="Postgres insights"/>
        <category label="PostgresMarathon" term="PostgresMarathon"/>
        <category label="internals" term="internals"/>
        <category label="locks" term="locks"/>
        <category label="lockmanager" term="lockmanager"/>
    </entry>
</feed>