<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Postgresql on Adam Vu</title><link>https://vutg.me/tags/postgresql/</link><description>Recent content in Postgresql on Adam Vu</description><generator>Hugo</generator><language>en</language><lastBuildDate>Mon, 09 Sep 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://vutg.me/tags/postgresql/index.xml" rel="self" type="application/rss+xml"/><item><title>PostgreSQL Full-Text Search and Elasticsearch</title><link>https://vutg.me/posts/postgresql-full-text-search-and-elasticsearch/</link><pubDate>Mon, 09 Sep 2024 00:00:00 +0000</pubDate><guid>https://vutg.me/posts/postgresql-full-text-search-and-elasticsearch/</guid><description>&lt;p&gt;Search is one of the important features users interact with a system. A user types &amp;ldquo;Taylor Swift&amp;rdquo; and expects results in under a second. At small scale this is trivial. At millions of events, it becomes one of the harder problems to get right.&lt;/p&gt;
&lt;p&gt;The naive implementation reaches for a &lt;code&gt;LIKE&lt;/code&gt; query:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;SELECT&lt;/span&gt; &lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;FROM&lt;/span&gt; events
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;WHERE&lt;/span&gt; name &lt;span style="color:#66d9ef"&gt;LIKE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%Taylor%&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; description &lt;span style="color:#66d9ef"&gt;LIKE&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;%Taylor%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This works correctly and is easy to write. The problem is performance. The wildcard on both sides of the search term — &lt;code&gt;%Taylor%&lt;/code&gt; — means no standard index can help. The database has no choice but to read every single row in the table, check each one against the pattern, and discard the ones that do not match. This is called a &lt;strong&gt;full table scan&lt;/strong&gt;, and its cost grows linearly with the number of rows. At 10,000 events it is imperceptible. At 10 million events it can take several seconds, and under concurrent load it can saturate the database entirely.&lt;/p&gt;</description></item><item><title>Redis TTL Distributed Lock for Ticket Reservation</title><link>https://vutg.me/posts/redis-ttl-distributed-lock-for-ticket-reservation/</link><pubDate>Mon, 27 Nov 2023 00:00:00 +0000</pubDate><guid>https://vutg.me/posts/redis-ttl-distributed-lock-for-ticket-reservation/</guid><description>&lt;p&gt;If you&amp;rsquo;ve ever booked concert tickets or a flight, you&amp;rsquo;ve seen that countdown timer: &lt;em&gt;&amp;ldquo;You have 10 minutes to complete your purchase.&amp;rdquo;&lt;/em&gt; That timer isn&amp;rsquo;t just UX theatre — it&amp;rsquo;s a distributed lock with a TTL. This post walks through why that pattern exists and how to implement it with Redis.&lt;/p&gt;
&lt;h2 id="the-problem-with-naive-ticket-booking"&gt;
 The problem with naive ticket booking
 &lt;a class="heading-link" href="#the-problem-with-naive-ticket-booking"&gt;
 &lt;i class="fa-solid fa-link" aria-hidden="true" title="Link to heading"&gt;&lt;/i&gt;
 &lt;span class="sr-only"&gt;Link to heading&lt;/span&gt;
 &lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;The simplest correct implementation of a booking system uses a database transaction:&lt;/p&gt;</description></item></channel></rss>