<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://proopensource.it/feed.xml" rel="self" type="application/atom+xml" /><link href="https://proopensource.it/" rel="alternate" type="text/html" /><updated>2026-06-09T10:11:50+02:00</updated><id>https://proopensource.it/feed.xml</id><title type="html">ProOpenSource OÜ Blog</title><subtitle>Blog about open source, mainly PostgreSQL</subtitle><entry><title type="html">My Three Top PostgeSQL 19 Features</title><link href="https://proopensource.it/blog/postgresql-19-features" rel="alternate" type="text/html" title="My Three Top PostgeSQL 19 Features" /><published>2026-06-09T00:00:00+02:00</published><updated>2026-06-09T00:00:00+02:00</updated><id>https://proopensource.it/blog/postgresql-19-features</id><content type="html" xml:base="https://proopensource.it/blog/postgresql-19-features"><![CDATA[<p>PostgeSQL 19 beta 1 has been <a href="https://www.postgresql.org/about/news/postgresql-19-beta-1-released-3313/">released on 2026-06-04</a>.</p>

<p>The release is planned for September 2026, though it’s time to go through the <a href="https://www.postgresql.org/docs/19/release-19.html">new features</a> and changes.</p>

<h2 id="my-top-three-features">My Top Three Features</h2>

<p>All three features below are cool and great developments from the authors of the patches that implemented them. But there are a lot of new cool features and extesnions to exisiting features done by a lot of people.</p>

<p>My thanks go out to all the people who made PostgreSQL 19 possible.</p>

<p>For all others there is still the opportunity to be part of that people, your time is now to test the current and comming beta and release candidates of PostgreSQL 19. And please <a href="https://www.postgresql.org/docs/current/bug-reporting.html">report bugs</a> you may find.<br />
That way you help all users having a stable release version ready to use in production.</p>

<h3 id="insert">INSERT</h3>

<p>The <a href="https://www.postgresql.org/docs/19/sql-insert.html">INSERT</a> became a new conflict action: It can now return a <strong>SELECT</strong> for conflicts.</p>

<p>Previously it already hat the options <strong>DO NOTHING</strong> and <strong>DO UPDATE</strong>, the first one did exactly what it was named, doing nothing, the second on offered to update the already existing columns.</p>

<p>The <strong>SELECT</strong> gives a complete new set of possibilities to handle existing data in an <strong>INSERT</strong> statement.</p>

<h3 id="repack">REPACK</h3>

<p>Previously one needed an extension, <a href="https://github.com/reorg/pg_repack">pg_repack</a>, but <a href="https://www.postgresql.org/docs/19/sql-repack.html">repack</a> is now a command directly availabe in PostgeSQL 19.</p>

<p>Not only is it now a command, it also supports the parameter <strong>CONCURRENTLY</strong>. That way repack does not affect current database sessions.</p>

<p>And you can pass an index name of an existing index to sort the repacked table after an index. When you have defined the sortorder with <a href="https://www.postgresql.org/docs/current/sql-cluster.html"><strong>CLUSTER</strong></a> and you do not pass an index name, the sortorder is done after the index specified in <strong>CLUSTER</strong>.</p>

<p>That does obviously not solve the <em>problem</em> of having the table data always physically sorted, but at least with <strong>REPACK</strong> as regular maintenance job, the data is mostly sorted.</p>

<h3 id="sqlpgq">SQL/PGQ</h3>

<p><a href="https://en.wikipedia.org/wiki/Graph_Query_Language">Graph Query Language (GQL)</a> is a standardized query language for <a href="https://en.wikipedia.org/wiki/Property_graphs">property graphs</a>.</p>

<p><a href="https://en.wikipedia.org/wiki/Graph_Query_Language#SQL/PGQ_Property_Graph_Query">SQL/PGQ</a> is the SQL standard extension to add the Graph Query Language to relatianonal databases.</p>

<p>It is availabe now in PostgeSQL, too, please see the <a href="https://www.postgresql.org/docs/19/ddl-property-graphs.html">Property Graphs documentation</a>.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="postgres" /><summary type="html"><![CDATA[PostgeSQL 19 beta 1 has been released on 2026-06-04. The release is planned for September 2026, though it’s time to go through the new features and changes. My Top Three Features All three features below are cool and great developments from the authors of the patches that implemented them. But there are a lot of new cool features and extesnions to exisiting features done by a lot of people. My thanks go out to all the people who made PostgreSQL 19 possible. For all others there is still the opportunity to be part of that people, your time is now to test the current and comming beta and release candidates of PostgreSQL 19. And please report bugs you may find. That way you help all users having a stable release version ready to use in production. INSERT The INSERT became a new conflict action: It can now return a SELECT for conflicts. Previously it already hat the options DO NOTHING and DO UPDATE, the first one did exactly what it was named, doing nothing, the second on offered to update the already existing columns. The SELECT gives a complete new set of possibilities to handle existing data in an INSERT statement. REPACK Previously one needed an extension, pg_repack, but repack is now a command directly availabe in PostgeSQL 19. Not only is it now a command, it also supports the parameter CONCURRENTLY. That way repack does not affect current database sessions. And you can pass an index name of an existing index to sort the repacked table after an index. When you have defined the sortorder with CLUSTER and you do not pass an index name, the sortorder is done after the index specified in CLUSTER. That does obviously not solve the problem of having the table data always physically sorted, but at least with REPACK as regular maintenance job, the data is mostly sorted. SQL/PGQ Graph Query Language (GQL) is a standardized query language for property graphs. SQL/PGQ is the SQL standard extension to add the Graph Query Language to relatianonal databases. It is availabe now in PostgeSQL, too, please see the Property Graphs documentation.]]></summary></entry><entry><title type="html">PostgreSQL Ecosystem Problems</title><link href="https://proopensource.it/blog/postgresql-ecosystem-problems-2026" rel="alternate" type="text/html" title="PostgreSQL Ecosystem Problems" /><published>2026-04-29T00:00:00+02:00</published><updated>2026-04-29T00:00:00+02:00</updated><id>https://proopensource.it/blog/postgresql-ecosystem-problems-2026</id><content type="html" xml:base="https://proopensource.it/blog/postgresql-ecosystem-problems-2026"><![CDATA[<h2 id="pgbackrest-is-dead">PgBackRest Is Dead</h2>
<p>Yesterday the maintainer of PgBackRest, <a href="https://www.linkedin.com/in/davidsteele/">David Steele</a>, published the
<a href="https://github.com/pgbackrest/pgbackrest">NOTICE OF OBSOLESCENCE</a>.</p>

<p>For further information please read the blog post <a href="https://mydbanotebook.org/posts/pgbackrest-is-dead.-now-what/">pgBackRest is dead. Now what?</a> by <a href="https://mydbanotebook.org/about/">Lætitia Avrot</a>. She also points to how to go an as she, like me, always recommended PgBackRest for PostgreSQL backups.</p>

<p>Therefore a big thank you goes for the work David has done on PgBackRest.</p>

<h2 id="and-now-what">And Now What?</h2>

<p>Things alike happened before, for example when due to the liquidation of the Segfault Inc. <a href="https://github.com/Segfault-Inc/Multicorn">Multicorn</a> became an abandend project.</p>

<p>That has been solved by several people creating a fork and named that fork <a href="https://github.com/pgsql-io/multicorn2">Multicorn2</a>.</p>

<p>I predict that very soon several forks of PgBackRest will be spotted in the wild with different names. And that might become a problem.<br />
It might end up with different patches solving problems and they would not be consistent. In additon, which fork would become the replacement the RPM or DEB packages?</p>

<p>This would also not solve the problem, that a very good maintainer of an essential part of the PostgreSQL ecosystem does not get paid for the work he’s done. And keep in mind, that this is not a small job that one could do as a side project. He, like all of us, needs to make a living.</p>

<p>Even having a another company sponsoring him would only be a short-time solution. What when that company get bought, or a new CEO decides to spare the money to invest it elsewhere?</p>

<p>Some people of the PostgreSQL community already thought, that it might be a good idea to move PgBackRest into PostgreSQL itself.<br />
But that might also be a short-time solution, in additon to all the arguments speaking against this way like, the code differs a lot to PostgreSQL standards.</p>

<p>What about other widely used projects in the PostgreSQL ecosystem that are widely used, and extenesions, that do have a lot of users?</p>

<h2 id="an-umbrella-for-the-ecosystem">An Umbrella For the Ecosystem?</h2>

<p>IMHO an umbrella organisation for tools in the PostgreSQL ecosystem would be a good solution. No single company owning the code. Also switching maintainers would be much easier.<br />
Not to speak about that it would be much easier to raise money by an organisation, than some single persons trying to raise enough for an income for themselves.</p>

<p>There are already examples out there that might help to find a solution. To mind are coming <a href="https://apache.org/">The Apache Software Foundation</a> and <a href="https://codeberg.org/">Codeberg e.V.</a>.</p>

<p>I know that someone has already submitted a proposal for the <a href="https://2026.pgconf.eu/community-day/">PostgreSQL Conference Europe Community Event Day</a>, but that conference is about six months away. Nevertheless, it would be a good place to discuss stuff in person.</p>

<p>Feel free to contact me to discuss what think about my ideas per email or on <a href="https://t.me/SneakyPie">Telegram</a>.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="postgres" /><category term="extensions" /><category term="extension" /><category term="postgres-tools" /><category term="ecosystem" /><category term="PgBackRest" /><summary type="html"><![CDATA[Due to the maintainer of PgBackRest dropping the project, a PostgreSQL ecosystem problem came public.]]></summary></entry><entry><title type="html">sparql_fdw Foreign Data Wrapper Tested Against PostgreSQL 18</title><link href="https://proopensource.it/blog/sparql_fdw-postgresql-18" rel="alternate" type="text/html" title="sparql_fdw Foreign Data Wrapper Tested Against PostgreSQL 18" /><published>2025-10-12T00:00:00+02:00</published><updated>2025-10-12T00:00:00+02:00</updated><id>https://proopensource.it/blog/sparql_fdw-postgresql-18</id><content type="html" xml:base="https://proopensource.it/blog/sparql_fdw-postgresql-18"><![CDATA[<h1 id="sparql_fdw-forreign-data-wrapper">sparql_fdw Forreign Data Wrapper</h1>

<p>The sparql_fdw is a <a href="https://wiki.postgresql.org/wiki/Foreign_data_wrappers">foreign data wrapper</a> to connect to query web databases with the <a href="https://en.wikipedia.org/wiki/SPARQL">SPARQL</a> protocol from inside <a href="https://postgresql.org">PostgreSQL</a> written in Python.</p>

<h1 id="test-against-postgresql-18">Test Against PostgreSQL 18</h1>

<p>As <a href="https://github.com/pgsql-io/multicorn2">multicorn2</a> is already working with PostgreSQL 18, I tested the <a href="https://codeberg.org/sjstoelting/sparql_fdw">sparql_fdw</a>, too.</p>

<p>It worked like a charm and I have added PostgreSQL 18 to the supported versions in the README file.</p>

<p>In addtion I removed PostgreSQL 12 as supported version as that version is out of support.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="SPARQL" /><category term="Foreign data wrapper" /><category term="sparql_fdw" /><category term="multicorn" /><category term="multicorn2" /><summary type="html"><![CDATA[Released a new version of the PostgreSQL FDW for SPARQL]]></summary></entry><entry><title type="html">Postgresql Performance</title><link href="https://proopensource.it/blog/postgresql-performance" rel="alternate" type="text/html" title="Postgresql Performance" /><published>2025-10-01T00:00:00+02:00</published><updated>2025-10-01T00:00:00+02:00</updated><id>https://proopensource.it/blog/postgresql-performance</id><content type="html" xml:base="https://proopensource.it/blog/postgresql-performance"><![CDATA[<h1 id="table-of-contents">Table of Contents</h1>

<ul>
  <li><a href="#indexes">Indexes</a></li>
  <li><a href="#users-and-connections">Users and Connections</a></li>
  <li><a href="#splitting-data-over-disks">Splitting Data over Disks</a></li>
  <li><a href="#network">Network</a></li>
  <li><a href="#vacuum">Vacuum</a></li>
  <li><a href="#fillfactor">Fillfactor</a></li>
</ul>

<hr />

<h1 id="postgresql-performance">PostgreSQL Performance</h1>

<p>A lot of settings and also the database design do have an impact of the performance of a PostgreSQL database.</p>

<h2 id="indexes">Indexes</h2>

<h3 id="foreign-keys">Foreign Keys</h3>

<p>PostgreSQL does not create an index when a foreign key is created. This might seem as a downside, but it is not. It gives the database designers the opportunity create that index with a different index type than the referenced table is using.</p>

<p>An example is on a big table a <a href="https://www.postgresql.org/docs/current/brin.html">block range index (BRIN)</a> will be faster and kept in memory compared to a <a href="https://www.postgresql.org/docs/current/btree.html">B-Tree index</a>.</p>

<p>My PostgreSQL extension <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks">pgsql_tweaks</a> has a view for that: <a href="https://rtfm.pgsql-tweaks.org/docs/views/system-information/pg_foreign_keys.html">Documentation of pg_foreign_keys</a>.</p>

<h3 id="forgotten-indexes">Forgotten Indexes</h3>

<p>Check execution plans, use <a href="https://www.postgresql.org/docs/current/sql-explain.html">EXPLAIN ANALYSE</a> to find them while developing. To find them in production use the <a href="https://rtfm.pgsql-tweaks.org/docs/views/system-information/pg_missing_indexes.html">missing indexes view</a> from <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks">pgsql_tweaks</a>.</p>

<p>There need to be some data in the database, otherwise PostgreSQL uses wrong assumptions.</p>

<p>Also install the <a href="https://www.postgresql.org/docs/current/auto-explain.html">auto_explain</a> extension to get runtime execution plans for slow queries.</p>

<h3 id="too-many-indexes">Too Many Indexes</h3>

<p>Having too many indexes does slow down INSERT and UPDATE statements. Indexes have to written to disk.</p>

<p>Use <a href="https://www.postgresql.org/docs/current/indexes-multicolumn.html">multicolumn indexes</a>, <a href="https://www.postgresql.org/docs/current/indexes-expressional.html">indexes on expressions</a>, and/or <a href="https://www.postgresql.org/docs/current/indexes-partial.html">partial indexes</a> (yes, indexes can have a where condition) .</p>

<p>Conditional indexes are great for example when tables do contain records, that are marked in a column as deleted. When someone needs to access the deleted records, a query takes longer because not deleted can be a condition in an index. But the active records can be found much faster as the index is much smaller and might easier stay in memory and there aren’t that many pages to parse in a tree.</p>

<h3 id="unused-indexes">Unused Indexes</h3>

<p>Regularly check for unused indexes especially on the production database.</p>

<p><a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks">pgsql_tweaks</a> has a view for that: <a href="https://rtfm.pgsql-tweaks.org/docs/views/system-information/pg_unused_indexes.html">pg_unused_indexes</a>.</p>

<h2 id="users-and-connections">Users and Connections</h2>

<p>Too many users connecting to PostgreSQL is not something, PostgreSQL is good in.</p>

<p>That is due to how a connection is done. For every connection postgres process is forked into a new one.<br />
This can end up in not being able to copy a new process and the database connection fails.</p>

<p>Also with a lot of connections each connection will only have a small amount of RAM available. That results into writing stuff to disk into the cache. Even while mostly the spinning rust is gone, this will slow down the answer.</p>

<p>Use a server side connection pooler like <a href="https://www.pgbouncer.org/">PgBouncer</a> to increase the amount of connections. It does keep connections open and spares PostgreSQL to copy processes for every new connection.</p>

<p>Another problem might even end in a immediate server shutdown. When the configuration is not well calculated, PostgreSQL might run out of memory.</p>

<h2 id="splitting-data-over-disks">Splitting Data over Disks</h2>

<p>On heavy writing PostgreSQL servers it is often usefull to have disks for certain purposes. This splitts the work of writing data.</p>

<ul>
  <li>One Disk for the OS</li>
  <li>One Disk for the data</li>
  <li>One Disk for the write ahead log (WAL)</li>
  <li>One Disk for database logs</li>
</ul>

<p>Just to have several partitions on the same disk does not speed anything up.</p>

<h3 id="file-systems">File Systems</h3>

<p>Splitting data over disks and using <a href="https://openzfs.org/">ZFS</a> doing snapshots is impossible, as the time will differ between the different disks.</p>

<p>This results in an inconsistent state for a RDBMS and PostgreSQL will fail to start as it has several check functions that take care, that the system is not in an undefined status.</p>

<h2 id="network">Network</h2>

<p>Insufficient network problems can be very problematic. And that is not only true for the client connection, but also for the replication of data.</p>

<p>This could result in followers falling behind of the primary. Which is resulting in wrong query results on a follower compared to the same query on the primary.</p>

<p>But there is also a problem, when the follower is not able to get the WAL from the primary.<br />
This could result in a full disk and that will end with PostgreSQL shutting down.</p>

<p>Monitor the primary and the followers about the WAL status, use the view <em>stats.replication</em>.</p>

<h2 id="vacuum">Vacuum</h2>

<p><a href="https://www.postgresql.org/docs/current/sql-vacuum.html">PostgreSQL Vacuum</a> is necessary to remove data from tables, that is not visible anymore. This is due to how <a href="https://www.postgresql.org/docs/current/mvcc-intro.html">Multi Version Concurrency Control (MVCC)</a> is implemented.</p>

<p><a href="https://www.postgresql.org/docs/current/runtime-config-autovacuum.html">Autocacuum</a> takes care of removing the unvisible data by making the space availabe for reusage. This does not result in more free disk space. Except when pages that are located at the end of a table are vacuumed. These pages will be removed.<br />
Statistically speaking, that can be ignored.</p>

<p>Therefore <span style="color:red;"><em>never turn autovacuum off</em></span>.</p>

<h3 id="autovacuum-configuration">Autovacuum Configuration</h3>

<p>By default autovacuum is configured very conservative. The setting can be adjusted to be more aggressive, meaning to clean up less bloated tables and having more workers, espescially when there are lots of tables.</p>

<p>Parameters to tune:</p>

<ul>
  <li><a href="https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-MAX-WORKERS">autovacuum_max_workers</a></li>
  <li><a href="https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-SCALE-FACTOR">autovacuum_vacuum_scale_factor</a></li>
  <li><a href="https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-LIMIT">autovacuum_vacuum_cost_limit</a></li>
  <li><a href="https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-VACUUM-COST-DELAY">autovacuum_vacuum_cost_delay</a></li>
</ul>

<p>The <a href="https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-MAX-WORKERS">autovacuum_max_workers</a> has to be adjusted to the other jobs running on the server. Meaning, that too many of these workers might slow down the server.</p>

<h4 id="table-level-configuration">Table Level Configuration</h4>

<p>On tables where lots of UPDATE and/or DELETE are executed against, autovacuum can be adjusted to run more often than what is set in the global configuration.</p>

<p>This results in shorter runtimes of autovacuum on this tables, therefore reducing the impact.</p>

<h5 id="monitoring-tables">Monitoring Tables</h5>

<p>To know bloat of tables, the ones with high inserts, updates, and/or deletes should be monitored.&lt;/br /&gt;</p>

<p>Don’t monitor all tables, that will move the focus away from what is neccessary to monitor.</p>

<p>There is a view to see the current status of tables, <a href="https://rtfm.pgsql-tweaks.org/docs/views/system-information/pg_table_bloat.html">pg_table_bloat</a>. This view is very expensive, therefore do not execute it too often. It is often usefull to filter tables to only those, that do need monitoring.</p>

<p>The downside with TimescaleDB here is, that all time partitions are independend tables for PostgreSQL, therefore you cannot not just monitor the main TimescaleDB table. In fact exclude them, as they do not return any goodinformation.</p>

<h5 id="adjusting-for-index-only-scans">Adjusting For Index Only Scans</h5>

<p>Index only scans are the fastest way to access data in joins, where conditions, and sorting.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">-- Tuning autovacuum for index only scans</span>
<span class="k">ALTER</span> <span class="k">TABLE</span> <span class="p">{</span><span class="k">table</span> <span class="n">name</span><span class="p">}</span>
<span class="k">SET</span> <span class="p">(</span><span class="n">autovacuum_vacuum_scale_factor</span> <span class="o">=</span> <span class="mi">0</span><span class="p">.</span><span class="mi">01</span><span class="p">)</span>
<span class="p">;</span>
</code></pre></div></div>

<h5 id="autovacuum-high-inserting-into-tables">Autovacuum High Inserting Into Tables</h5>

<p>With having 100,000 transactions per day doing UPDATE or DELETE, tune it to run round about once a day.<br />
Adjust <a href="https://www.postgresql.org/docs/current/runtime-config-autovacuum.html#GUC-AUTOVACUUM-FREEZE-MAX-AGE">autovacuum_freeze_max_age</a> to the number of daily transactions on these tables.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">ALTER</span> <span class="k">TABLE</span> <span class="p">{</span><span class="k">table</span> <span class="n">name</span><span class="p">}</span>
<span class="k">SET</span> <span class="p">(</span><span class="n">autovacuum_freeze_max_age</span> <span class="o">=</span> <span class="mi">100000</span><span class="p">)</span>
<span class="p">;</span>
</code></pre></div></div>

<h4 id="transaction-wraparound">Transaction Wraparound</h4>

<p>Transaction Wraparound is a serious problem that even might take server maintenance downtime if not addressed.</p>

<p>Anti-Wraparound vacuum has to be able to freeze tuples in all tables.<br />
Blocking anti-wraparound can be coused by:</p>

<ul>
  <li>Very long running database sessions</li>
  <li>Data corruption</li>
</ul>

<p>For tables with lots of INSERT statements the problem is solved with <a href="#autovacuum-high-inserting-into-tables">Autovacuum High Inserting Into Tables</a>.</p>

<h2 id="fillfactor">Fillfactor</h2>

<p>Fillfactor is availabe on <a href="https://www.postgresql.org/docs/current/sql-createtable.html#RELOPTION-FILLFACTOR">tables</a> and <a href="https://www.postgresql.org/docs/current/sql-createindex.html#INDEX-RELOPTION-FILLFACTOR">indexes</a>.</p>

<p>PostgreSQL stores its data in pages. The fillfactor affects the size of the page that is filled in percent.</p>

<h3 id="on-tables">On Tables</h3>

<p>The fillfactor increases the performance especially of <a href="https://www.postgresql.org/docs/current/sql-update.html">UPDATE</a> statements.</p>

<p>The rule of thumb is to have a fillfactor on tables between 70 % and 90%, depending on the amount of updates and the size of a row stored in a page.</p>

<p>On tables that get rows only inserted, a fillfactor of 100 %  is the best setting.</p>

<h3 id="on-indexes">On Indexes</h3>

<p>The fillfactor affects indexes differently than tables. <a href="https://www.postgresql.org/docs/current/btree.html">B-Tree</a> indexes get new leaves on the same page, when possible, otherwise a page is split and the index is splitted over several pages.</p>

<p>Therefore the fillfactor is usefull for INSERT and UPDATE statements on indexes.</p>

<h2 id="prewarm-cache">Prewarm Cache</h2>

<p>The more data you have, the more memory your servers will have. Accessing the data in RAM still is magnitutes faster than grabbing them from SSDs, not to speak about rotating disks.</p>

<p>Every time you have to restart a PostgreSQL server, the caches are empty and will be filled again step by step. But that is not a greate experience for users as their requests run slow because their data has to be grabbed from disk.</p>

<p>There is an extension to solve this problem: <a href="https://www.postgresql.org/docs/current/pgprewarm.html">pg_prewarm</a>.</p>

<p>When a server is shut down, it takes a bit longer as the data in chaches will be written to disk. Also the start is slower as the caches will be filled with the content of the file on disks. But the user experience is the same as before.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="postgres" /><category term="performance" /><category term="settings" /><category term="configuration" /><category term="pgsql_tweaks" /><summary type="html"><![CDATA[Table of Contents Indexes Users and Connections Splitting Data over Disks Network Vacuum Fillfactor PostgreSQL Performance A lot of settings and also the database design do have an impact of the performance of a PostgreSQL database. Indexes Foreign Keys PostgreSQL does not create an index when a foreign key is created. This might seem as a downside, but it is not. It gives the database designers the opportunity create that index with a different index type than the referenced table is using. An example is on a big table a block range index (BRIN) will be faster and kept in memory compared to a B-Tree index. My PostgreSQL extension pgsql_tweaks has a view for that: Documentation of pg_foreign_keys. Forgotten Indexes Check execution plans, use EXPLAIN ANALYSE to find them while developing. To find them in production use the missing indexes view from pgsql_tweaks. There need to be some data in the database, otherwise PostgreSQL uses wrong assumptions. Also install the auto_explain extension to get runtime execution plans for slow queries. Too Many Indexes Having too many indexes does slow down INSERT and UPDATE statements. Indexes have to written to disk. Use multicolumn indexes, indexes on expressions, and/or partial indexes (yes, indexes can have a where condition) . Conditional indexes are great for example when tables do contain records, that are marked in a column as deleted. When someone needs to access the deleted records, a query takes longer because not deleted can be a condition in an index. But the active records can be found much faster as the index is much smaller and might easier stay in memory and there aren’t that many pages to parse in a tree. Unused Indexes Regularly check for unused indexes especially on the production database. pgsql_tweaks has a view for that: pg_unused_indexes. Users and Connections Too many users connecting to PostgreSQL is not something, PostgreSQL is good in. That is due to how a connection is done. For every connection postgres process is forked into a new one. This can end up in not being able to copy a new process and the database connection fails. Also with a lot of connections each connection will only have a small amount of RAM available. That results into writing stuff to disk into the cache. Even while mostly the spinning rust is gone, this will slow down the answer. Use a server side connection pooler like PgBouncer to increase the amount of connections. It does keep connections open and spares PostgreSQL to copy processes for every new connection. Another problem might even end in a immediate server shutdown. When the configuration is not well calculated, PostgreSQL might run out of memory. Splitting Data over Disks On heavy writing PostgreSQL servers it is often usefull to have disks for certain purposes. This splitts the work of writing data. One Disk for the OS One Disk for the data One Disk for the write ahead log (WAL) One Disk for database logs Just to have several partitions on the same disk does not speed anything up. File Systems Splitting data over disks and using ZFS doing snapshots is impossible, as the time will differ between the different disks. This results in an inconsistent state for a RDBMS and PostgreSQL will fail to start as it has several check functions that take care, that the system is not in an undefined status. Network Insufficient network problems can be very problematic. And that is not only true for the client connection, but also for the replication of data. This could result in followers falling behind of the primary. Which is resulting in wrong query results on a follower compared to the same query on the primary. But there is also a problem, when the follower is not able to get the WAL from the primary. This could result in a full disk and that will end with PostgreSQL shutting down. Monitor the primary and the followers about the WAL status, use the view stats.replication. Vacuum PostgreSQL Vacuum is necessary to remove data from tables, that is not visible anymore. This is due to how Multi Version Concurrency Control (MVCC) is implemented. Autocacuum takes care of removing the unvisible data by making the space availabe for reusage. This does not result in more free disk space. Except when pages that are located at the end of a table are vacuumed. These pages will be removed. Statistically speaking, that can be ignored. Therefore never turn autovacuum off. Autovacuum Configuration By default autovacuum is configured very conservative. The setting can be adjusted to be more aggressive, meaning to clean up less bloated tables and having more workers, espescially when there are lots of tables. Parameters to tune: autovacuum_max_workers autovacuum_vacuum_scale_factor autovacuum_vacuum_cost_limit autovacuum_vacuum_cost_delay The autovacuum_max_workers has to be adjusted to the other jobs running on the server. Meaning, that too many of these workers might slow down the server. Table Level Configuration On tables where lots of UPDATE and/or DELETE are executed against, autovacuum can be adjusted to run more often than what is set in the global configuration. This results in shorter runtimes of autovacuum on this tables, therefore reducing the impact. Monitoring Tables To know bloat of tables, the ones with high inserts, updates, and/or deletes should be monitored.&lt;/br /&gt; Don’t monitor all tables, that will move the focus away from what is neccessary to monitor. There is a view to see the current status of tables, pg_table_bloat. This view is very expensive, therefore do not execute it too often. It is often usefull to filter tables to only those, that do need monitoring. The downside with TimescaleDB here is, that all time partitions are independend tables for PostgreSQL, therefore you cannot not just monitor the main TimescaleDB table. In fact exclude them, as they do not return any goodinformation. Adjusting For Index Only Scans Index only scans are the fastest way to access data in joins, where conditions, and sorting. -- Tuning autovacuum for index only scans ALTER TABLE {table name} SET (autovacuum_vacuum_scale_factor = 0.01) ; Autovacuum High Inserting Into Tables With having 100,000 transactions per day doing UPDATE or DELETE, tune it to run round about once a day. Adjust autovacuum_freeze_max_age to the number of daily transactions on these tables. ALTER TABLE {table name} SET (autovacuum_freeze_max_age = 100000) ; Transaction Wraparound Transaction Wraparound is a serious problem that even might take server maintenance downtime if not addressed. Anti-Wraparound vacuum has to be able to freeze tuples in all tables. Blocking anti-wraparound can be coused by: Very long running database sessions Data corruption For tables with lots of INSERT statements the problem is solved with Autovacuum High Inserting Into Tables. Fillfactor Fillfactor is availabe on tables and indexes. PostgreSQL stores its data in pages. The fillfactor affects the size of the page that is filled in percent. On Tables The fillfactor increases the performance especially of UPDATE statements. The rule of thumb is to have a fillfactor on tables between 70 % and 90%, depending on the amount of updates and the size of a row stored in a page. On tables that get rows only inserted, a fillfactor of 100 % is the best setting. On Indexes The fillfactor affects indexes differently than tables. B-Tree indexes get new leaves on the same page, when possible, otherwise a page is split and the index is splitted over several pages. Therefore the fillfactor is usefull for INSERT and UPDATE statements on indexes. Prewarm Cache The more data you have, the more memory your servers will have. Accessing the data in RAM still is magnitutes faster than grabbing them from SSDs, not to speak about rotating disks. Every time you have to restart a PostgreSQL server, the caches are empty and will be filled again step by step. But that is not a greate experience for users as their requests run slow because their data has to be grabbed from disk. There is an extension to solve this problem: pg_prewarm. When a server is shut down, it takes a bit longer as the data in chaches will be written to disk. Also the start is slower as the caches will be filled with the content of the file on disks. But the user experience is the same as before.]]></summary></entry><entry><title type="html">pgsql_tweaks Logo</title><link href="https://proopensource.it/blog/pgsql_tweaks-logo" rel="alternate" type="text/html" title="pgsql_tweaks Logo" /><published>2025-09-20T00:00:00+02:00</published><updated>2025-09-20T00:00:00+02:00</updated><id>https://proopensource.it/blog/pgsql_tweaks-logo</id><content type="html" xml:base="https://proopensource.it/blog/pgsql_tweaks-logo"><![CDATA[<h1 id="the-new--pgsql_tweaks-project-logo">The new  pgsql_tweaks Project Logo</h1>

<h2 id="the-idea">The Idea</h2>

<p>The idea of the logo is based on a citation of <a href="https://www.justatheory.com/">David E. Wheeler</a>. He once said, that this extension is sort of my PostgreSQL swiss army knife.</p>

<h2 id="logo-creation">Logo Creation</h2>

<p>When I asked the designer of the logo, (Elodie Jex)[], to create a logo, she wanted some contexts. I explained PostgreSQL and extensions a bit. In addition I told her the swiss army knife story.</p>

<p>She used that information to come up with the shiny new logo for the <a href="https://pgsql-tweaks.org">pgsql_tweaks</a> extension.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="Extension" /><category term="pgsql_tweaks" /><summary type="html"><![CDATA[pgsql_tweaks is a bundle of functions and views for PostgreSQL]]></summary></entry><entry><title type="html">pgsql_tweaks 1.0.0 Released</title><link href="https://proopensource.it/blog/pgsql_tweaks-1-0-0-released" rel="alternate" type="text/html" title="pgsql_tweaks 1.0.0 Released" /><published>2025-09-16T00:00:00+02:00</published><updated>2025-09-16T00:00:00+02:00</updated><id>https://proopensource.it/blog/pgsql_tweaks-1-0-0-released</id><content type="html" xml:base="https://proopensource.it/blog/pgsql_tweaks-1-0-0-released"><![CDATA[<h1 id="pgsql_tweaks-is-a-bundle-of-functions-and-views-for-postgresql">pgsql_tweaks is a bundle of functions and views for <a href="https://postgresql.org">PostgreSQL</a></h1>

<p>The source code is available on <a href="https://codeberg.org/pgsql_tweaks/pgsql-tweaks.org">Codeberg</a>.<br />
You can install the whole package, or just copy what is needed from the source code.</p>

<p>The extension is also available on <a href="https://pgxn.org/dist/pgsql_tweaks/help.html">PGXN</a>.</p>

<h2 id="version-10">Version 1.0</h2>

<p>I decided to make this the 1.0 Version. The First commit is from 2017-08-11, the extension is now more than eight years old.</p>

<h2 id="news">News</h2>

<p>The project started as a personal repository. When I left GitHub, see <a href="/blog/leaving-github">Leaving GitHub</a> and <a href="https://proopensource.it/blog/github-is-history">GitHub is History</a> for details, I decided to move it to a project on its own on <a href="https://codeberg.org">Codeberg</a>.</p>

<h3 id="website">Website</h3>

<p>The website on <a href="https://pgsql-tweaks.org">pgsql-tweaks.org</a> has been setup first with the HTML help page of the project.</p>

<p>Now it is a real website realised with <a href="https://jekyllrb.com/">Jekyll</a>. Future changes of pgsql_tweaks will be blogged on <a href="https://pgsql-tweaks.org/blog">pgsql-tweaks.org/blog</a>.<br />
The source code is part of the project on <a href="https://codeberg.org/pgsql_tweaks/pgsql-tweaks.org">Codeberg</a>.</p>

<p>Also the documentation has been changed from a single Markdown file to a website, also realised with Jekyll on <a href="https://rtfm.pgsql-tweaks.org">rtfm.pgsql-tweaks.org</a>. RTFM stands for Read The Fine Manual.<br />
The source code is part of the project on <a href="https://codeberg.org/pgsql_tweaks/rtfm.pgsql-tweaks.org">Codeberg</a>.</p>

<h3 id="contribution">Contribution</h3>

<p>This move also opens the possibilities to contribute to the project. The documentation has now detailed information about how to contribute:</p>

<ul>
  <li><a href="https://rtfm.pgsql-tweaks.org/docs/contribution-info.html">Contribution Informaion</a></li>
  <li><a href="https://rtfm.pgsql-tweaks.org/docs/developer-info.html">Developer Informaion</a></li>
</ul>

<h2 id="extension-changes">Extension Changes</h2>

<h3 id="pgsql_tweaks-becomes-a-logo">pgsql_tweaks Becomes a Logo</h3>

<p>Thanks to <a href="https://littleyellowfish.fr/">Elodie Jex</a> the extension has a shiny logo.</p>

<p><a href="https://pgsql-tweaks.org/assets/img/PNG/pgsql_tweaks-logo-1-sqare.png">![The pgsql_tweaks logo](https://pgsql-tweaks.org/assets/img/pgsql_tweaks-logo.png “”)</a></p>

<h3 id="created-in-schema-pgsql_tweaks">Created in Schema pgsql_tweaks</h3>

<p>Instead of the current default schema, the extension is now created in its own schema. This solves conflicts with other extensions, as has been the case in the past with <a href="https://pgtap.org/">pgtap</a>, see <a href="https://github.com/theory/pgtap/issues/340">pgTAP Issue 340</a> for details.</p>

<h3 id="documentation-for-view-pg_unused_indexes">Documentation for View pg_unused_indexes</h3>

<p>The view has not been documented in previous versions.</p>

<h3 id="new-features">New Features</h3>

<p>The new features are blogged on <a href="https://pgsql-tweaks.org/blog/pgsql_tweaks-v1-released.html">pgsql_tweaks Version 1 Released!</a>.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="Extension" /><category term="pgsql_tweaks" /><summary type="html"><![CDATA[pgsql_tweaks is a bundle of functions and views for PostgreSQL]]></summary></entry><entry><title type="html">ProOpenSource is now an Official Codeberg Member</title><link href="https://proopensource.it/blog/proopensource-codeberg-member" rel="alternate" type="text/html" title="ProOpenSource is now an Official Codeberg Member" /><published>2025-09-08T00:00:00+02:00</published><updated>2025-09-08T00:00:00+02:00</updated><id>https://proopensource.it/blog/proopensource-codeberg-member</id><content type="html" xml:base="https://proopensource.it/blog/proopensource-codeberg-member"><![CDATA[<h1 id="proopensource-is-now-an-official-codeberg-member">ProOpenSource is now an Official Codeberg Member</h1>

<p>Last month I wrote in <a href="/blog/leaving-github">Leaving GitHub</a> that ProOpenSource OÜ applied for a membership of the Codeberg e.V., the public organistion, that is behind <a href="https://codeberg.org">codeberg.org</a>.</p>

<p>On Thursday, September 03, 2025 I got the message, that this is now official.</p>

<p>I am proud my company is able to support the hosting of open source repositories.</p>

<h2 id="about-codeberg">About Codeberg</h2>

<p>Codeberg is a non profit organistion hosting open source Git repositories.</p>

<p>There is no tracking and sharing personal information with third parties.</p>

<p>This is a big difference compared to other other Git hosters, especially to GitHub.</p>]]></content><author><name>stefanie</name></author><category term="Codeberg" /><summary type="html"><![CDATA[ProOpenSource became an official member of Codeberg e.V.]]></summary></entry><entry><title type="html">pgsql_tweaks 0.11.5 Released</title><link href="https://proopensource.it/blog/pgsql_tweaks-0-11-5-released" rel="alternate" type="text/html" title="pgsql_tweaks 0.11.5 Released" /><published>2025-08-19T00:00:00+02:00</published><updated>2025-08-19T00:00:00+02:00</updated><id>https://proopensource.it/blog/pgsql_tweaks-0-11-5-released</id><content type="html" xml:base="https://proopensource.it/blog/pgsql_tweaks-0-11-5-released"><![CDATA[<h1 id="pgsql_tweaks-is-a-bundle-of-functions-and-views-for-postgresql">pgsql_tweaks is a bundle of functions and views for <a href="https://postgresql.org">PostgreSQL</a></h1>

<p>The source code is available on <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks">Codeberg</a>.</p>

<p>The extension is also available on <a href="https://pgxn.org/dist/pgsql_tweaks/help.html">PGXN</a>.</p>

<p>The extension is also availabe through the <a href="https://www.postgresql.org/download/linux/redhat/">PostgreSQL rpm packages</a>.</p>

<h2 id="general-changes">General changes</h2>

<p>No code has been changed.</p>

<h3 id="documentation-changes">Documentation Changes</h3>

<p>The documentation of the view <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks/src/branch/main/sql/view_pg_bloat_info.sql">pg_bloat_info</a> was the wrong one as it covered a view, that is in the making for a future version.</p>

<p>This is fixed in this release.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="Extension" /><category term="pgsql_tweaks" /><summary type="html"><![CDATA[pgsql_tweaks is a bundle of functions and views for PostgreSQL]]></summary></entry><entry><title type="html">pgsql_tweaks 0.11.4 Released</title><link href="https://proopensource.it/blog/pgsql_tweaks-0-11-4-released" rel="alternate" type="text/html" title="pgsql_tweaks 0.11.4 Released" /><published>2025-08-18T00:00:00+02:00</published><updated>2025-08-18T00:00:00+02:00</updated><id>https://proopensource.it/blog/pgsql_tweaks-0-11-4-released</id><content type="html" xml:base="https://proopensource.it/blog/pgsql_tweaks-0-11-4-released"><![CDATA[<h1 id="pgsql_tweaks-is-a-bundle-of-functions-and-views-for-postgresql">pgsql_tweaks is a bundle of functions and views for <a href="https://postgresql.org">PostgreSQL</a></h1>

<p>The source code is available on <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks">Codeberg</a>.</p>

<p>The extension is also available on <a href="https://pgxn.org/dist/pgsql_tweaks/help.html">PGXN</a>.</p>

<p>The extension is also availabe through the <a href="https://www.postgresql.org/download/linux/redhat/">PostgreSQL rpm packages</a>.</p>

<h2 id="general-changes">General changes</h2>

<p>There is only one repository for the source code of the extension, <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks">codeberg.org/pgsql_tweaks/pgsql_tweaks</a> from now on.</p>

<p>The source is now part of <a href="https://codeberg.org/pgsql_tweaks">pgsql_tweaks project</a>.</p>

<h3 id="project-website">Project Website</h3>

<p>The project has its own website, <a href="https://pgsql-tweaks.org">pgsql-tweaks.org</a>. Currently the website is only a HTML copy of the <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks/src/branch/main/help.html">HTML help page</a> of the project.</p>

<p>This will be changed to a documentation website of the project, the work is already started.</p>

<p>The sources of the website are also part of the <a href="https://codeberg.org/pgsql_tweaks/pgsql-tweaks.org">pgsql_tweaks project</a>. The documentation will be based on <a href="https://jekyllrb.com/">Jekyll</a>, please see the projects <a href="https://codeberg.org/pgsql_tweaks/pgsql-tweaks.org/src/branch/jekyll">jekyll branch</a>.</p>

<h3 id="postgresql-18-support">PostgreSQL 18 Support</h3>

<p>No code has been changed. Tests against <a href="https://www.postgresql.org/about/news/postgresql-176-1610-1514-1419-1322-and-18-beta-3-released-3118/">PostgreSQL 18 beta 3</a> have been successful.</p>

<p>Therefore PostgreSQL 18 is now supoorted by pgsql_tweaks.</p>

<h3 id="documentation-changes">Documentation Changes</h3>

<p>The documentation of the view <a href="https://codeberg.org/pgsql_tweaks/pgsql_tweaks/src/branch/main/sql/view_pg_bloat_info.sql">pg_bloat_info</a> has been added, the view itself has been released earlier.</p>]]></content><author><name>stefanie</name></author><category term="PostgreSQL" /><category term="Extension" /><category term="pgsql_tweaks" /><summary type="html"><![CDATA[pgsql_tweaks is a bundle of functions and views for PostgreSQL]]></summary></entry><entry><title type="html">GitHub is History</title><link href="https://proopensource.it/blog/github-is-history" rel="alternate" type="text/html" title="GitHub is History" /><published>2025-08-15T00:00:00+02:00</published><updated>2025-08-15T00:00:00+02:00</updated><id>https://proopensource.it/blog/github-is-history</id><content type="html" xml:base="https://proopensource.it/blog/github-is-history"><![CDATA[<h1 id="github-is-history">GitHub is History</h1>

<p>At least to me. Today was the day to remove all left repositories from GitHub. Afterwards I deleted my account.</p>

<p>You don’t need GitHub to handle your <a href="https://git-scm.com/">Git</a> repositories. Git is federated and you can add remotes and/or remove them.</p>

<h2 id="why-i-left">Why I Left</h2>

<p>First their current CEO declared in an interview, that you are not a software developer, when you are not following <a href="https://thecon.ai/">The AI Con</a>. I wrote about that in my blog post <a href="/blog/leaving-github.html">Leaving GitHub</a>.</p>

<p>Only a week later the same guy announced he would step back from his position. And Microsoft did its best to add another nail to GitHubs coffin, they decided that it does not get a new CEO and will be integrated into their <a href="https://arstechnica.com/gadgets/2025/08/github-will-be-folded-into-microsoft-proper-as-ceo-steps-down/">CoreAI organisation</a>.</p>

<p>That move by Microsoft only affirmed my decision to leave GitHub behind. And I also decided, that I do not want to link to their AI con pages.</p>

<h2 id="tell-github-to-delete-your-personal-data">Tell GitHub To Delete Your Personal Data</h2>

<p>As a citizen of the European Union I also demanded to delete information about me from their servers, that are not releated to crucial busines data, that need to be kept.</p>

<p>In Europe we do have the <a href="https://gdpr.eu/what-is-gdpr/">General Data Protection Regulation (GDPR)</a>. This law gives citizen of the European Union a lot more rights how their data are allowed to be handled.</p>

<p>You can demand that GitHub deletes yoru personal data according to Art. 17 GDPR within one month with an email request to privacy@github.com and/or dpo@github.com.</p>

<h1 id="alternatives-to-github">Alternatives to GitHub</h1>

<h2 id="gitlab"><a href="https://gitlab.com/">GitLab</a></h2>

<h3 id="hosted-on-gitlab">Hosted on GitLab</h3>

<p>You can do the same things as on GitHub, but so far they did not any stupid AI stuff or publish stupid things about developers who disagree with the AI slope.</p>

<p>I moved my personal repositories to GitLab right after Microsoft bought GitHub in 2018 and only kept mirrors on GitHub.</p>

<h3 id="self-hosting-gitlab">Self hosting GitLab</h3>

<p>You can also run the GitLab community edition on your own infrastructure, it is availabe for several environments, see <a href="https://about.gitlab.com/install/">about.gitlab.com/install</a> for details.</p>

<p>It is licensed under the <a href="https://docs.gitlab.com/development/licensing/">MIT licencse</a>.</p>

<h2 id="self-hosting-with-forgejo">Self Hosting with <a href="https://forgejo.org/">Forgejo</a></h2>

<p>When you are able to run a self hosted environment, this might be a possible solution.</p>

<p>Forgejo is licensed under the <a href="https://forgejo.org/2024-08-gpl/">GNU General Public License v3.0 or later</a>.</p>

<h2 id="codeberg"><a href="https://codeberg.org">Codeberg</a></h2>

<p>Codeberg is based on Forgejo. It is mantained by a public non-profit organisation that accepts <a href="https://donate.codeberg.org/">donations</a> and offers personal and company <a href="https://join.codeberg.org/">memberships</a> to support them.</p>

<p>Services are offered for free and open source projects.</p>

<p>My company, <a href="https://proopensource.eu">ProOpenSource OÜ</a>, applied for a company membership.</p>]]></content><author><name>stefanie</name></author><category term="GitHub" /><category term="GitLab" /><category term="Forgejo" /><category term="Codeberg" /><summary type="html"><![CDATA[Leaving GitHub because of their AI con]]></summary></entry></feed>