<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Database on Nalar</title>
    <link>https://nalar.dev/tags/database/</link>
    <description>Recent content in Database on Nalar</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 01 Sep 2026 00:00:00 +0700</lastBuildDate>
    <atom:link href="https://nalar.dev/tags/database/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Enforce Non-Overlapping Time Ranges with PostgreSQL Exclusion Constraints</title>
      <link>https://nalar.dev/postgresql-exclusion-constraints-non-overlapping-ranges/</link>
      <pubDate>Tue, 01 Sep 2026 00:00:00 +0700</pubDate>
      <guid>https://nalar.dev/postgresql-exclusion-constraints-non-overlapping-ranges/</guid>
      <description>&lt;p&gt;Applications that schedule rooms, equipment, or maintenance windows often need a simple invariant: two active reservations for the same resource must not overlap. Checking for conflicts in application code looks easy, but concurrent transactions can both pass the check before either inserts.&lt;/p&gt;&#xA;&lt;p&gt;PostgreSQL can enforce this invariant inside the database with range types and exclusion constraints.&lt;/p&gt;&#xA;&lt;h2 id=&#34;model-the-interval-explicitly&#34;&gt;Model the interval explicitly&lt;/h2&gt;&#xA;&lt;p&gt;A half-open timestamp range includes its start and excludes its end. That lets adjacent bookings touch without overlapping.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Keyset Pagination for Stable and Efficient Database Queries</title>
      <link>https://nalar.dev/keyset-pagination-for-stable-database-queries/</link>
      <pubDate>Tue, 01 Sep 2026 00:00:00 +0700</pubDate>
      <guid>https://nalar.dev/keyset-pagination-for-stable-database-queries/</guid>
      <description>&lt;p&gt;Pagination looks straightforward with &lt;code&gt;LIMIT&lt;/code&gt; and &lt;code&gt;OFFSET&lt;/code&gt;, but deep offsets become increasingly expensive and can produce unstable results when rows are inserted or deleted between requests.&lt;/p&gt;&#xA;&lt;p&gt;Keyset pagination, also called seek pagination, uses the last seen sort key as the starting point for the next query.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-offset-degrades&#34;&gt;Why OFFSET degrades&lt;/h2&gt;&#xA;&lt;p&gt;A typical query is:&lt;/p&gt;&#xA;&lt;div &#xA;    x-data=&#34;{&#xA;        code: $el.querySelector(&#39;code&#39;).innerText&#xA;    }&#34;&#xA;    class=&#34;relative my-4 rounded-lg group&#34;&#xA;&gt;&#xA;    &lt;button&#xA;        @click=&#34;navigator.clipboard.writeText(code); $el.innerText = &#39;Copied!&#39;; setTimeout(() =&gt; $el.innerText = &#39;Copy&#39;, 2000)&#34;&#xA;        class=&#34;absolute top-2 right-2 bg-neutral-700 text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 transition-opacity&#34;&#xA;    &gt;&#xA;        Copy&#xA;    &lt;/button&gt;&#xA;    &#xA;    &lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;SELECT&lt;/span&gt; id, created_at, title&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;FROM&lt;/span&gt; posts&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ORDER&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;BY&lt;/span&gt; created_at &lt;span style=&#34;color:#66d9ef&#34;&gt;DESC&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;LIMIT&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;OFFSET&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100000&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;The database still has to find and skip preceding rows before returning the page. There is also a correctness problem: if a new row is inserted at the front between requests, offsets shift and a user may see a duplicate or miss an item.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Transaction Isolation and Safe Database Retries</title>
      <link>https://nalar.dev/transaction-isolation-and-safe-retries/</link>
      <pubDate>Tue, 01 Sep 2026 00:00:00 +0700</pubDate>
      <guid>https://nalar.dev/transaction-isolation-and-safe-retries/</guid>
      <description>&lt;p&gt;Database transactions make groups of reads and writes atomic, but atomicity alone does not answer what concurrent transactions are allowed to observe. That is the job of isolation.&lt;/p&gt;&#xA;&lt;p&gt;The practical challenge appears when correct transactions conflict. Strong isolation can intentionally abort one transaction rather than allow an invalid interleaving. Applications need to distinguish those retryable concurrency failures from ordinary errors.&lt;/p&gt;&#xA;&lt;h2 id=&#34;isolation-protects-invariants-not-just-statements&#34;&gt;Isolation protects invariants, not just statements&lt;/h2&gt;&#xA;&lt;p&gt;Consider two concurrent requests that reserve the last available item.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
