<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[Tiger Data Blog]]></title>
        <description><![CDATA[Insights, product updates, and tips from TigerData (Creators of TimescaleDB) engineers on Postgres, time series & AI. IoT, crypto, and analytics tutorials & use cases.]]></description>
        <link>https://www.tigerdata.com/blog</link>
        <image>
            <url>https://www.tigerdata.com/icon.ico</url>
            <title>Tiger Data Blog</title>
            <link>https://www.tigerdata.com/blog</link>
        </image>
        <generator>RSS for Node</generator>
        <lastBuildDate>Tue, 07 Apr 2026 10:01:58 GMT</lastBuildDate>
        <atom:link href="https://www.tigerdata.com/blog" rel="self" type="application/rss+xml"/>
        <ttl>60</ttl>
        <item>
            <title><![CDATA[The Problem With Locks and PostgreSQL Partitioning (and How to Actually Fix It)]]></title>
            <description><![CDATA[PostgreSQL locks can cause issues in partitioned tables. Read how TimescaleDB solves this using lock minimization strategies.]]></description>
            <link>https://www.tigerdata.com/blog/how-timescaledb-solves-common-postgresql-problems-in-database-operations-with-data-retention-management</link>
            <guid isPermaLink="true">https://www.tigerdata.com/blog/how-timescaledb-solves-common-postgresql-problems-in-database-operations-with-data-retention-management</guid>
            <category><![CDATA[PostgreSQL]]></category>
            <category><![CDATA[PostgreSQL Tips]]></category>
            <category><![CDATA[Hypertables]]></category>
            <dc:creator><![CDATA[Chris Travers]]></dc:creator>
            <pubDate>Thu, 12 Oct 2023 13:00:00 GMT</pubDate>
            <media:content medium="image" href="https://timescale.ghost.io/blog/content/images/2023/10/Screenshot-2023-10-12-at-11.52.06-AM.png">
            </media:content>
            <content:encoded><![CDATA[<p>In my career, I have frequently worked for companies with large amounts of<a href="https://www.timescale.com/learn/types-of-data-supported-by-postgresql-and-timescale" rel="noreferrer"> time-partitioned data</a>, where I was a software engineer focusing on our PostgreSQL databases. </p><p>We’d already grown past the point where deleting data row-by-row was no longer practical, so <a href="https://www.timescale.com/learn/when-to-consider-postgres-partitioning" rel="noreferrer">we needed to use PostgreSQL partitioning to manage data retention.</a> In brief, dropping a whole partition allows PostgreSQL to remove the entire file from disk for a subset of your data rather than going through each row and removing them individually. So it’s <em>much</em> faster. <a href="https://www.timescale.com/learn/pg_partman-vs-hypertables-for-postgres-partitioning" rel="noreferrer">But if you are doing partitioning natively in PostgreSQL, you do have to make sure to add new partitions where you’re ingesting new data and drop the old ones. </a></p><p>This was a frequent cause of outages for us, even if we had reasonably well-tested scripts for adding and removing partitions. Unfortunately, the interactions around the scripts were less well-tested, and new, frequent, and long-running queries prevented the partition management scripts from getting the locks required and creating new partitions. We didn’t see the problem at first because we’d created partitions a few days in advance, but then we ran out of time, and with no new partitions, we couldn’t insert, and whoops, down goes the app.</p><p>These types of problems are particularly hard to debug and disentangle because they are often caused by totally unrelated pieces of code in combination with changes in load. PostgreSQL has begun to address this with newer approaches attaching partitions concurrently, but they’re quite complex. </p><p>I’ve seen the outages caused by <a href="https://timescale.ghost.io/blog/how-to-fix-no-partition-of-relation-found-for-row/" rel="noreferrer">partitions failing to create</a>, disk filling up because they can’t be dropped, or the pauses in other normal queries by partition management code. I know how difficult these problems can be. This is why TimescaleDB's hypertables were so exciting to me when I discovered them, especially their lock minimization strategies. </p><h2 id="understanding-postgresql-locks">Understanding PostgreSQL Locks </h2><h3 id="what-are-postgresql-locks">What are PostgreSQL locks? </h3><p>PostgreSQL locks are mechanisms that control concurrent access to data in the database to ensure consistency, integrity, and isolation of database transactions. </p><p>PostgreSQL, like most other relational database management systems, is a <em>concurrent</em> system, which means that multiple queries can be processed at the same time. Locks help in managing multiple transactions attempting to access the same data simultaneously, avoiding conflicts and potential data corruption. </p><h3 id="why-are-postgresql-locks-necessary">Why are PostgreSQL locks necessary? </h3><p>Concurrency is essential for optimizing the performance and responsiveness of the database. However, concurrency introduces several challenges that need careful handling to ensure the database’s integrity, consistency, and reliability: </p><ul><li>When multiple queries are executed concurrently, there's a risk that one transaction might view inconsistent or uncommitted data modified by another ongoing transaction. This can lead to erroneous results and inconsistencies in the database.</li><li>Queries executing simultaneously can interfere with each other, leading to performance degradation, locking issues, or inconsistent data.</li><li>When two transactions try to modify the same data simultaneously, it can lead to conflicts, data corruption, or loss of data.</li></ul><p>Locks are necessary to prevent these problems. </p><h3 id="types-of-postgresql-locks">Types of PostgreSQL locks </h3><p><a href="https://www.postgresql.org/docs/current/explicit-locking.html">PostgreSQL supports many different types of locks</a>, but the three relevant to this article are <code>ACCESS SHARE</code>, <code>SHARE UPDATE EXCLUSIVE</code>, and <code>ACCESS EXCLUSIVE</code> locks. </p><ul><li><code>ACCESS SHARE</code> locks are the least restrictive and are intended to prevent the database schema from changing under a query along with related caches being cleared. Access share locks are acquired for database read operations. The purpose of access share locks is to block access exclusive locks.</li><li><code>SHARE UPDATE EXCLUSIVE</code><strong> </strong>locks allow concurrent writes to a table but block operations that change the database schema in ways that might interfere with running queries. These are used for some forms of concurrent schema changes in PostgreSQL, though two concurrent transactions cannot both take this lock on the same table. For example, you cannot concurrently detach and attach the same partition to/from the same parent table in different sessions. One must complete before the other starts. These locks generally are used for concurrency-safe schema changes, which do not clear cached relation information.</li><li><code>ACCESS EXCLUSIVE</code> locks are the most restrictive and are intended to prevent other queries from operating across a schema change. Access exclusive locks block all locks from all other transactions on the locked table.</li></ul><h3 id="cache-invalidation-and-access-exclusive-locks">Cache invalidation and <code>ACCESS EXCLUSIVE</code> locks </h3><p>For performance reasons, PostgreSQL caches information about tables and views (which we call “relations”) and uses this cached information in query execution. This strategy is instrumental for PostgreSQL's efficiency, ensuring that data retrieval is quick and resource utilization is optimized. </p><p>A critical scenario that needs meticulous handling lock-wise is when the structrure of tables is altered. When the schema is altered (e.g. by adding or dropping columns, changing data types, or modifying constraints) the cached information related to that table might become outdated or inconsistent. Therefore, it needs to be invalidated and refreshed to ensure that the query execution reflects the modified schema. </p><p>To make this work, PostgreSQL takes an access exclusive lock on the table in question before the cached information for that relation can be invalidated.</p><h2 id="using-postgresql-partitioning-to-simplify-data-management">Using PostgreSQL Partitioning to Simplify Data Management </h2><p>In PostgreSQL <a href="https://www.postgresql.org/docs/current/ddl-partitioning.html" rel="noreferrer">declarative partitioning</a>, PostgreSQL tables are used both for empty parent tables and for partitions holding the data. Internally, each partition is a table, and there is mapping information used by the planner to indicate which partitions should be looked at for each query. This information is cached in the relation cache.</p><p>When tables are partitioned based on time, it allows for an organized structure where data is segmented into specific time frames. This makes data management much faster, since dropping a whole partition allows PostgreSQL to remove the entire partition from disk rather than going through each row and removing them individually. </p><p>In PostgreSQL, you can follow two general approaches for managing partitions and data retention, which as we'll see later, have two different concurrency considerations and problematics. </p><h3 id="approach-1-dropping-partitions">Approach #1: Dropping partitions<br></h3><p>In the first approach, we simply drop partitions from a partitioned table when we want to delete data. </p><pre><code class="language-SQL">CREATE TABLE partition_test (
    event_time timestamp,
    sensor_id bigint,
    reported_value float
) partition by range (event_time);

-- Create partition 
CREATE TABLE partition_test_2022 PARTITION OF partition_test 
FOR VALUES event_time FROM ('2022-01-01 00:00:00') TO ('2023-01-01 00:00:00');
```

--Drop partition
ALTER TABLE partition_test DROP PARTITION partition_test_2022;</code></pre><h3 id="approach-2-concurrent-workflow">Approach #2: Concurrent workflow<br></h3><p>PostgreSQL also offers (in PostgreSQL 14 and newer) a concurrent workflow for these operations.</p><pre><code class="language-SQL">CREATE TABLE partition_test_2022 (like partition_test);


ALTER TABLE partition_test ATTACH PARTITION partition_test_2022 FOR VALUES event_time FROM ('2022-01-01 00:00:00') TO ('2023-01-01 00:00:00') CONCURRENTLY;
</code></pre>
<p>To remove a partition concurrently, we can:</p><pre><code class="language-SQL">ALTER TABLE partition_test DETACH PARTITION partition_test_2022 CONCURRENTLY;


DROP TABLE partition_test_2022;
</code></pre>
<h2 id="the-problem-with-locks-and-postgresql-partitioning">The Problem With Locks and <a href="https://www.tigerdata.com/learn/when-to-consider-postgres-partitioning" rel="noreferrer">PostgreSQL Partitioning</a> </h2><p>From a database administration perspective, neither of these approaches is very safe. </p><p>Both the partition creation and dropping requires an access exclusive lock on the <code>partition_test</code>, meaning that once the query is issued, no other queries can run against that table until the query is concluded and the transaction committed or rolled back. The locking in each case looks like this:</p><figure class="kg-card kg-image-card"><img src="https://timescale.ghost.io/blog/content/images/2023/01/Data-Retention-Access-Exclusive-Lock_img1.png" class="kg-image" alt="" loading="lazy" width="2000" height="626" srcset="https://timescale.ghost.io/blog/content/images/size/w600/2023/01/Data-Retention-Access-Exclusive-Lock_img1.png 600w, https://timescale.ghost.io/blog/content/images/size/w1000/2023/01/Data-Retention-Access-Exclusive-Lock_img1.png 1000w, https://timescale.ghost.io/blog/content/images/size/w1600/2023/01/Data-Retention-Access-Exclusive-Lock_img1.png 1600w, https://timescale.ghost.io/blog/content/images/2023/01/Data-Retention-Access-Exclusive-Lock_img1.png 2070w" sizes="(min-width: 720px) 720px"></figure><p>In terms of the concurrent approach, it still has to address the issue of clearing the relation cache. It does so in two stages: first, a share update exclusive lock is taken <code>partition_test</code>, and then information is written to the catalogs indicating that the table will be removed from the partition list. The backend then waits until all running queries have concluded (and all transactions guaranteeing repeatable reads have concluded) before removing the table from the partition map.</p><p>This approach does not rely on locks to signal that the process is complete, only to prevent multiple concurrent updates for the status of the same set of partitions. As a result, even unrelated queries can block the detach operation. If the partition management script’s connection is interrupted for any reason, cleanup processes must be performed by the database administrator.</p><p>Once the partition is removed from the partition list, it is locked in access exclusive mode and dropped. The locking approach of this process looks like this:</p><figure class="kg-card kg-image-card"><img src="https://timescale.ghost.io/blog/content/images/2023/01/Data-retention-management-stages-1-and-2_img2.png" class="kg-image" alt="" loading="lazy" width="2000" height="854" srcset="https://timescale.ghost.io/blog/content/images/size/w600/2023/01/Data-retention-management-stages-1-and-2_img2.png 600w, https://timescale.ghost.io/blog/content/images/size/w1000/2023/01/Data-retention-management-stages-1-and-2_img2.png 1000w, https://timescale.ghost.io/blog/content/images/size/w1600/2023/01/Data-retention-management-stages-1-and-2_img2.png 1600w, https://timescale.ghost.io/blog/content/images/2023/01/Data-retention-management-stages-1-and-2_img2.png 2070w" sizes="(min-width: 720px) 720px"></figure><p>In conclusion, </p><ul><li>The first approach (involving the manual creation and dropping of partitions) relatively quick operations but forces hard synchronization points on partitioned tables, which in time-series workloads are usually partitioned due to being heavily used. Problems here can cause database outages fairly quickly.</li><li>The concurrent workflow doesn’t always solve these problems. In mixed-workflow applications, waiting for all running queries to complete (which can include long-running automatic maintenance tasks) can lead to long delays, dropped connections, and general difficulties in actually managing data retention. Particularly under load, these operations may not perform well enough to be useful.</li></ul><h2 id="common-advice-on-how-to-fix-this-problem-and-why-its-not-the-best">Common Advice on How to Fix This Problem (and Why It's Not the Best) </h2><p>The overall problems of partition management with time-series data fall into two categories:  </p><p>1) Failure to create partitions before they are needed can block inserts.</p><p>2) Dropping partitions when needed for regulatory or cost reasons not only can fail but can also block reading and writing to the relevant tables. </p><p>If you ask for advice, you'll probably hear one of these two things: </p><h3 id="use-custom-scripts">Use custom scripts</h3><p>Many companies begin their partition-management journey with custom scripts. This has the advantage of simplicity, but the disadvantage is that the operations can require heavy locks, and there is often a lack of initial knowledge on how to address these.</p><p>Custom scripts are the most flexible approach to lock problems of partition management because of the entire toolkit (lock escalation, time-out and retry, and more). This allows knowledgeable teams to build solutions that work around the existing database workloads with the best success chance. </p><p>On the other hand, this problem is full of general landmines, and teams often do not begin with the knowledge to navigate these hazards successfully.</p><p>A second major problem with custom scripts is that database workloads can change over time, and this is often out of the hands of the responsible team. For example, a data science team might run workloads that interfere with production in ways the software engineering teams had not considered.</p><h3 id="use-pgpartman">Use pg_partman </h3><p><a href="https://www.timescale.com/learn/pg_partman-vs-hypertables-for-postgres-partitioning" rel="noreferrer"><code>pg_partman</code> provides a general toolkit for partition management which can mitigate the problem on some workloads.</a> <code>pg_partman</code> takes a time-out-and-retry approach to partition creation and removal, meaning that—depending on the configuration and how things are run—the functions will run in an environment where a lock time-out is set. This prevents a failed lock from leading to an outage, but there is no guarantee that it will be obtained before the partitions are required. </p><p>In most cases, you can tune these features to provide reasonable assurances that problems will usually be avoided. Workloads exist that prevent the partition management functions from successfully running in such an environment.</p><p><code>pg_partman</code> is a good tool and an important contribution to this topic, but at scale and under load, it will only work in cases where you have a real opportunity to get the locks required within the lock time-out. I have personally worked in environments where important services would have to be briefly disabled to allow this to happen.</p><h2 id="how-timescaledb-solves-the-problem-of-locking-in-postgresql-partitioning">How TimescaleDB Solves the Problem of Locking in PostgreSQL Partitioning </h2><p>Instead of using PostgreSQL native partitioning, you can <a href="https://docs.timescale.com/self-hosted/latest/install/" rel="noreferrer">install the TimescaleDB extension</a> and use <a href="https://www.tigerdata.com/blog/database-indexes-in-postgresql-and-timescale-cloud-your-questions-answered" rel="noreferrer">hypertables</a>, which are PostgreSQL tables that are automatically partitioned. This solves the problems caused by locking since hypertables minimize locks by design.  <br></p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">💡</div><div class="kg-callout-text">For those using our managed PostgreSQL service, <a href="https://www.timescale.com/cloud" rel="noreferrer">Timescale Cloud</a>, <a href="https://docs.timescale.com/about/latest/changelog/#:~:text=%F0%9F%94%90%20Current%20Lock%20Contention" rel="noreferrer">you can see current lock contention in the results section of our SQL editor</a> if a query is waiting on locks and can't complete execution.</div></div><p><br></p><p>TimescaleDB automatically partitions hypertables into chunks, organized by various partitioning criteria, usually time. This implementation is independent of PostgreSQL’s partitioning strategies and has been optimized as an independent add-on to PostgreSQL rather than a part of PostgreSQL core. TimescaleDB does not use inheritance as a table partitioning structure either, nor does TimescaleDB rely on the relation cache mentioned above for determining which chunks to scan.</p><p>Within a TimescaleDB hypertable, chunks are added transparently as needed and removed asynchronously without intrusive locks on the parent table. TimescaleDB then uses various strategies to hook into the planner and execute TimescaleDB-specific approaches to partition selection and elimination. These strategies require locking the chunk table with intrusive locks but not locking the parent. <br><br>This approach is likely to lead to some potential problems in serializable transaction isolation levels because once the underlying partition is gone, it is gone. In the event that a serializable transaction starts and then chunks are dropped, this will result in serialization errors or isolation violations.<br></p><figure class="kg-card kg-image-card"><img src="https://timescale.ghost.io/blog/content/images/2023/01/Data-retention-management-Access-Share-Lock-and-Exclusive-Lock_img3.png" class="kg-image" alt="" loading="lazy" width="2000" height="738" srcset="https://timescale.ghost.io/blog/content/images/size/w600/2023/01/Data-retention-management-Access-Share-Lock-and-Exclusive-Lock_img3.png 600w, https://timescale.ghost.io/blog/content/images/size/w1000/2023/01/Data-retention-management-Access-Share-Lock-and-Exclusive-Lock_img3.png 1000w, https://timescale.ghost.io/blog/content/images/size/w1600/2023/01/Data-retention-management-Access-Share-Lock-and-Exclusive-Lock_img3.png 1600w, https://timescale.ghost.io/blog/content/images/2023/01/Data-retention-management-Access-Share-Lock-and-Exclusive-Lock_img3.png 2070w" sizes="(min-width: 720px) 720px"></figure><h3 id="lock-minimization">Lock minimization</h3><p>PostgreSQL has traditionally taken the view that concurrency is not extremely important for <a href="https://www.tigerdata.com/learn/guide-to-postgresql-database-operations" rel="noreferrer">database operations</a> while Data Definition Language (DDL) commands are run. Traditionally, this is true. Even today, DDL commands are usually run sufficiently infrequently that the database cannot take the performance hit of introducing DDL commands as synchronization points. </p><p>The emerging problems of heavy PostgreSQL users today are not usually performance problems but the fact that applications are often not written with an awareness of what these added synchronization points will mean. In my experience, these synchronization points themselves are a significant cause of database outages among large-scale PostgreSQL users.</p><p>Timescale has been built to avoid the sort of locking problems that currently exist with PostgreSQL’s declarative partitioning simply because this is a common problem in time-series workloads.</p><p>TimescaleDB maintains its own chunk catalogs and only locks the partitions that will be removed. The catalog entry is removed, then the chunk table is locked and dropped. Only an access share lock is taken on the top-level table. This means that reads and even writes can be done to other chunks without interfering with dropping or adding chunks.</p><p>TimescaleDB’s current approach has one limitation when used under serializable transactions. Currently, if you use serializable transactions, there are certain circumstances where a transaction could go to read dropped chunks and no longer see them, resulting in a violation of the serialization guarantees. This is only a problem under very specific circumstances, but in this case, TimescaleDB behaves differently than PostgreSQL’s concurrent DDL approaches. </p><p>In general, though, you should only drop chunks when you are reasonably sure they are not going to be accessed if you use serializable transaction isolation.</p><h3 id="why-is-postgresql-not-doing-this">Why is PostgreSQL not doing this? </h3><p>TimescaleDB’s solution cannot be perfectly replicated with stock PostgreSQL at the moment because dropping partitions requires active invalidation of cached data structures, which other concurrent queries might be using. </p><p>Offering some sort of lazy invalidation infrastructure (via message queues, etc.) would go a long way to making some of this less painful, as would allowing more fine-grained invalidations to caching.</p><h2 id="conclusion">Conclusion</h2><p>TimescaleDB’s approach to the problem of locking is the best solution today, better than the options available in stock PostgreSQL. But it's not yet perfect; it operates between the two options given in terms of concurrency capabilities. We cannot drop a chunk that a serializable transaction has read until that transaction concludes regardless.</p><p>Getting there is likely to require some changes to how PostgreSQL caches the table and view characteristics and how this cache invalidation works. However, such improvements would help us move toward more transactional DDL. </p><p>Many <code>ALTER TABLE</code> commands are limited in concurrency largely because of these caching considerations. I think the general success of our approach here is also evidence of a need to address these limitations generally.<br><br>In the meantime, if you're planning to partition your tables, check out Timescale.  If you're running your PostgreSQL database on your own hardware,&nbsp;<a href="https://docs.timescale.com/self-hosted/latest/install/?ref=timescale.com" rel="noreferrer">you can simply add the TimescaleDB extension</a>. </p><p>If you're running managed PostgreSQL, <a href="https://console.cloud.timescale.com/signup?ref=timescale.com" rel="noreferrer">try the Timescale platform for free.</a> Besides the advantages of a mature cloud platform, Timescale Cloud will warn you about lock contention via our UI. <a href="https://docs.timescale.com/about/latest/changelog/#:~:text=%F0%9F%94%90%20Current%20Lock%20Contention" rel="noreferrer">The Timescale Console displays the current lock contention</a> in the results section of our SQL editor if a query is waiting on locks and can't complete execution.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A PostgreSQL Developer's Perspective: Five Interesting Patches From September's Commitfest]]></title>
            <description><![CDATA[Welcome to our new blog series! Every other month, Timescale’s developer advocate, Chris Travers, will use his PostgreSQL developer perspective to feel the pulse of the beloved database by looking into new commitfest patches.]]></description>
            <link>https://www.tigerdata.com/blog/a-postgresql-developers-perspective-five-interesting-patches-from-septembers-commitfest</link>
            <guid isPermaLink="true">https://www.tigerdata.com/blog/a-postgresql-developers-perspective-five-interesting-patches-from-septembers-commitfest</guid>
            <category><![CDATA[PostgreSQL]]></category>
            <dc:creator><![CDATA[Chris Travers]]></dc:creator>
            <pubDate>Wed, 02 Nov 2022 14:14:11 GMT</pubDate>
            <media:content medium="image" href="https://timescale.ghost.io/blog/content/images/2022/11/PostgreSQL-Developer-Perspective-September-commitfest--1-.png">
            </media:content>
            <content:encoded><![CDATA[<div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">🐘</div><div class="kg-callout-text"><em>The PostgreSQL community organizes patch reviews into “</em><a href="https://commitfest.postgresql.org/"><em>commitfests</em></a><em>” which last for a month at a time, every other month. In this series, our very own PostgreSQL developer advocate and expert, Chris Travers, will discuss a few patches that may be of interest to PostgreSQL users after each commitfest. This is intended to provide a sense of the progress and future of PostgreSQL as a major player in the database world.</em></div></div><p><a href="https://commitfest.postgresql.org/39/">September’s commitfest</a> is over with 65 committed patches, 40 patches returned with feedback, 177 patches moved to the next commitfest, 3 rejected, and 11 withdrawn. From a PostgreSQL developer's perspective and beyond, the patches include a large number of improvements in a large number of areas.</p><p>In this new blog post series pilot, I have selected a few patches that I find particularly interesting and helpful, and which I feel I can easily communicate their importance to a general audience of PostgreSQL users. This is by no means a comprehensive list of committed patches of interest, and in particular, patches that improve code quality or set the foundations for new features somewhere in the distant future are not included in this review. However, in my discussion with PostgreSQL developers, the improvements that I heard a lot about involved type-safety improvements not on this list.</p><p>In this article I have selected five patches, three of which are committed and two returned with feedback, for discussion. I will focus on their utility to database users and application developers from my PostgreSQL developer point of view (POV).</p><p>Let’s start with the committed patches.</p><h2 id="postgresql-developer-pov-interesting-patches-committed">PostgreSQL Developer POV: Interesting Patches Committed</h2><h3 id="reducing-chunk-header-size-on-all-memory-context-types"><br>Reducing chunk header size on all memory context types</h3><p>PostgreSQL <a href="https://www.youtube.com/watch?v=tP2pHbKz2R0">manages memory by lifetime</a> and allocates based on either a “chunk allocator” or a “slab allocator” (the latter being designed specifically for logical replication contexts, and not relevant to this patch). </p><p>Allocation sets are arranged in a hierarchy relating to memory lifetime within the software. This prevents one from having to free memory at a defined point later, as the system can just do this later, at a defined point in time.  For example, if we allocate memory with a lifetime related to the processing of a row, then the memory will be reused or freed when PostgreSQL moves on to process the next row.  If we allocate to the lifetime of the transaction, then the memory is freed when the transaction commits or rolls back.  It also means that in some cases, PostgreSQL can just reuse a chunk of memory without having to do significant processing of it other than the header.</p><p>The chunk allocator also increases the memory allocation on each subsequent call for an allocation set. The first chunk in the allocation set is 8 kB in size, and each subsequent chunk allocated doubles until one reaches 1 GiB. A given allocation within a set cannot span chunks, and this is why you cannot allocate (compressed or not) more than 1 GB of data within PostgreSQL in C <a href="http://postgresql.org/docs/6.3/c3903.htm">using the palloc memory allocation interfaces</a>.</p><p><a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=c6e0fe1f2a08505544c410f613839664eea9eb21">This patch</a> provides a number of important memory improvements in this regard. Although PostgreSQL memory management is well-optimized performance-wise and avoids most of the problems plaguing C programmers generally, this introduces further improvements.</p><p>Databases are environments where memory allocation efficiency matters for a number of reasons. In addition to pure memory savings, the fact that these may allow more data to fit in a given chunk means fewer malloc() calls will happen, and this is likely to produce performance improvements as well.</p><p>This patch does not affect all aspects of memory in PostgreSQL. While data coming into shared buffers or from shared buffers back to disk are not affected by this change, the data allocated for processing data extracted from shared buffers (or processed for writing to shared buffers) is affected.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">✨</div><div class="kg-callout-text"><strong>Editor's Note: </strong>shared_buffers are an important part of configuring your PostgreSQL instance. <a href="https://timescale.ghost.io/blog/database-scaling-postgresql-caching-explained/">Check out this article on what they are and how they’re designed</a>, and <a href="https://timescale.ghost.io/blog/postgresql-caching-the-postmaster-process/">read this blog post to learn how they interact with the postmaster process</a>.</div></div><p>This also shows how even very well-optimized systems can sometimes still have opportunities for further improvements, and it shows that even in mature systems, there are often gains to be made by those with the knowledge and insight to find them.</p><h3 id="handle-infinite-recursion-in-a-logical-replication-setup">Handle infinite recursion in a logical replication setup</h3><p>PostgreSQL’s logical replication is built on a publisher/subscriber model, where a publisher exposes a series of changes that a subscriber ingests and writes locally. In current releases of PostgreSQL, it is not really possible to have a loop of subscribers and publishers. Replication must always be only unidirectional.</p><p>For the most part, this works well because bidirectional replication poses fundamental (mathematical) conflict resolution problems that are impossible to solve where authoritative data is required. For example, if the same row is updated on two different mutually replicating systems, there is insufficient information to determine what the final output state is or should be. For this reason, cyclic replication topologies—often called “multi-master replication”—are generally frowned upon.</p><p>A common approach to addressing this problem is to use “last update wins” as a strategy, but this approach necessarily clobbers existing updates. In my previous work in other companies, where I was using such complex replication topologies with other databases, we actually had to take steps to prevent conflicting updates elsewhere in the infrastructure for this reason.</p><p><a href="https://commitfest.postgresql.org/39/3610/">This patch</a> allows, for the first time, logical replication loops. In other words, while a subscriber can already republish data it subscribed to, the original publisher could now, with new options set on the subscription, subscribe to data that could be republished from its own subscriptions. This can be done while preventing replication loops by setting an “origin” option in the subscription. The patch is then intended to prevent replication write loops, where the same insert or update is replicated back and forth forever.</p><p>Logical replication is a completely different beast when compared to physical streaming replication. It has completely different use cases and pitfalls than the latter. It imposes very different administrative burdens as well. However, this is a massive leap forward towards a community-owned bidirectional logical replication capability, which will likely open some doors for PostgreSQL where replication topologies based on cyclic graphs (often called multi-master replication) are actually worth the significant costs.</p><h3 id="proper-planner-support-for-order-by-distinct">Proper planner support for <code>ORDER BY</code> / <code>DISTINCT</code></h3><p>PostgreSQL supports various aggregates where collation operations are important, such as ntile, percentile, and other ordered set aggregates, window functions, and aggregates with the <code>DISTINCT</code> modifier. The efficiency of these operations is affected by the sort ordering of the table scans, and in current versions of PostgreSQL, the planner does not take this into account. As a result, <code>ORDER BY</code> and <code>DISTINCT</code> in aggregate functions can lead to unnecessary sorts, which lead to slower query performance. </p><p>Having proper planner support for these sorts of operations is a significant performance win for anyone using these sorts of aggregates. In my experience, there are many users of these sorts of features, especially those whose workflows include both transactional and decision support workflows. <a href="https://commitfest.postgresql.org/39/3164/">This patch</a> represents another significant improvement for analytic workloads on PostgreSQL.</p><p>Now let’s address the two patches that haven’t been yet committed.</p><h2 id="patches-not-yet-committed">Patches Not Yet Committed</h2><p>Not every interesting patch that caught my attention here got committed this time around. Two important patches will get discussed further as they progress through peer review and the commitfest feedback process. Both of these patches are currently listed as “returned with feedback” but are of sufficient importance or near enough to completion that they are worth watching anyway.</p><h3 id="kerberos-delegation">Kerberos Delegation</h3><p><a href="https://web.mit.edu/kerberos/">Kerberos, the authentication protocol that was developed by MIT</a>, and available on many platforms before being incorporated into Microsoft’s ActiveDirectory, has the capacity to pass delegated credentials between hosts. PostgreSQL can already accept delegated credentials for authentication but currently cannot delegate credentials.</p><p>So, for example, when a user accesses an internal ASP.net application on a company intranet, the web server can authenticate the user via Kerberos, and then pass on a delegated credential to the database if needed for actual access. This approach allows fine-grained and redundant control over access to data with a great deal of defense in depth.</p><p>What PostgreSQL is not currently able to do is delegate Kerberos authentication, which means that Kerberos authentication cannot be used between PostgreSQL nodes over things like foreign data wrappers.</p><p>A <a href="https://commitfest.postgresql.org/39/3582/">proposed patch</a> would ensure that PostgreSQL could delegate Kerberos credentials to libpq connections, allowing this to be used by the PostgreSQL foreign data wrapper, dblink, and similar extensions. While this patch has been listed as “returned with feedback,” the general sense is that this would be a really useful feature, and so I would read that status at present as a note that the current patch has some problems that need to be rethought before it can be accepted.</p><p>The fundamental difficulty here is that Kerberos session encryption does not provide forward privacy or forward security, and therefore, when session encryption is used with credential delegation, the user could potentially break the encryption on the middle host. In the event that passwords are also used for a foreign data wrapper connection, this would render some protections against less robust sensitive data or even in some cases (for example, where passwords are used in a passthrough way to authenticate against a third-party provider) allow for password disclosure.</p><p>The overall consensus is that this is a feature that would be very helpful in PostgreSQL, something I believe as well. The patch rejection is also a great testament to the degree of peer review in the community that goes into security-critical code paths. I expect that sooner or later, this feature will be included with appropriate safety measures in place, and I hope it is resubmitted sooner rather than later.</p><h3 id="allows-database-specific-role-memberships">Allows database-specific role memberships</h3><p>In PostgreSQL, roles (which include users) are global to an instance of PostgreSQL (called a “cluster” in PostgreSQL terminology). This means that if you have several databases managed by the same PostgreSQL instance, the roles and role memberships are common throughout all databases.</p><p>One major difficulty in writing multi-tenant applications which use databases as the tenant boundary is that if you assign a user with a role in one database, this occurs in all databases. For example, if you have an accounting application and you have a user “chris” who has different permissions in three different databases on the same server, you cannot use a simple, consistent set of roles to manage database permissions.</p><p>One solution to this problem (which we did when I was building out such a system in LedgerSMB) is to create different roles on each database, including, for example, the database name in the role name. This leads to a certain degree of complexity and makes the role names harder to read. Another option would be to limit users to a single database. This adds complexity in a different place.</p><p>A <a href="https://commitfest.postgresql.org/39/3374/">proposed patch</a> would allow the ability to grant role permissions only on a specific database. For multi-tenant applications, this would be a game changer. The patch was near acceptance when there was some further discussion on documentation. It needed to be rebased and corrected, and the initial submitter did not reply in a timely manner.  This can happen—people can become busy or unavailable for one reason or another, and patches can end up temporarily orphaned.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-emoji">✨</div><div class="kg-callout-text"><strong>Editor's Note: </strong>For an insider’s perspective on commitfests, <a href="https://timescale.ghost.io/blog/how-to-manage-a-commitfest/">read this blog post on being a commitfest manager</a>, and <a href="https://timescale.ghost.io/blog/what-does-a-postgresql-commitfest-manager-do-and-should-you-become-one/">check out if you should become one</a>.</div></div><p>Given the general utility of this patch for multi-tenant applications, I would like to see this fixed and resubmitted sooner rather than later.</p><h2 id="concluding-thoughts">Concluding Thoughts</h2><p>The patches discussed here represent small but useful steps forward for PostgreSQL. These and many others make PostgreSQL a database that is improving significantly with each major release. </p><p>Commitfests such as these provide great insight into this process, the review that patches undergo, and how PostgreSQL keeps moving forward.</p><p>That’s one of my <strong>favorite things about PostgreSQL: it’s a database that is significantly improving with each major release. </strong>If you want to add even more functionality to PostgreSQL, <a href="https://www.timescale.com/timescale-signup">explore TimescaleDB</a>—<a href="https://timescale.ghost.io/blog/postgresql-timescaledb-1000x-faster-queries-90-data-compression-and-much-more/"><strong>it extends PostgreSQL</strong> with things like automatic time-based partitioning and indexing, continuous aggregations, columnar compression, and time-series functionality.</a> And if you’re using a managed service for PostgreSQL, <a href="https://console.cloud.timescale.com/">try Timescale</a>—it’s free for 30 days, no credit card required. <br></p>]]></content:encoded>
        </item>
    </channel>
</rss>