<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://brokenco.de//feed/by_tag/data.xml" rel="self" type="application/atom+xml" /><link href="https://brokenco.de//" rel="alternate" type="text/html" /><updated>2026-08-24T11:29:18+00:00</updated><id>https://brokenco.de//feed/by_tag/data.xml</id><title type="html">rtyler</title><subtitle>a moderately technical blog</subtitle><author><name>R. Tyler Croy</name></author><entry><title type="html">Crashing the index with PostgreSQL custom types</title><link href="https://brokenco.de//2026/08/14/custom-types-index.html" rel="alternate" type="text/html" title="Crashing the index with PostgreSQL custom types" /><published>2026-08-14T00:00:00+00:00</published><updated>2026-08-14T00:00:00+00:00</updated><id>https://brokenco.de//2026/08/14/custom-types-index</id><content type="html" xml:base="https://brokenco.de//2026/08/14/custom-types-index.html"><![CDATA[<p>My current work project is one of the first Aurora/PostgreSQL deployments and
already the <strong>largest</strong>. Success brings <em>scaling challenges</em> and the types of
things seasoned operators classify as “good problems to have.” Compared to
previous scaling work around <a href="https://delta.io">Delta Lake</a> the knobs and ways
in which online relational databases scale is a muscle that has atrophied in
the past decade. The relational database landscape is also quite different
especially with <a href="https://aws.amazon.com/video/watch/f2a0fcbccb8/">Amazon Aurora which is quite well
designed</a>in the past decade.
The relational database landscape is also quite different especially with
<a href="https://aws.amazon.com/video/watch/f2a0fcbccb8/">Amazon Aurora which is quite well
designed</a>.</p>

<p>At some point it doesn’t matter how “well architected” the underlying database engine was, the laws of physics still apply. The speed of light between CPU cores, storage, and memory still imposes limitations. Similar to my work
related to <a href="/2026/02/13/screaming-in-the-cloud.html">Engineering around Extreme S3
scale</a>, the difference between systems
which handle hundreds of millions of <em>something</em> and hundreds of <strong>billions</strong>
of something is substantial.</p>

<p>My original database design relied upon <a href="https://www.postgresql.org/docs/current/sql-createtype.html">Custom
types</a>, which I
really enjoy using for easily mapping complex data types into PostgreSQL.
Similar to a <code class="language-plaintext highlighter-rouge">struct</code> in Rust, at it’s most simple a custom type is a
collection of associated fields:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Coordinate</span> <span class="p">{</span>
    <span class="n">brand</span><span class="p">:</span> <span class="n">Brand</span><span class="p">,</span>
    <span class="n">doc_id</span><span class="p">:</span> <span class="nb">u64</span><span class="p">,</span>
    <span class="n">page</span><span class="p">:</span> <span class="nb">Option</span><span class="o">&lt;</span><span class="nb">u32</span><span class="o">&gt;</span><span class="p">,</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Can easily map into the database with:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">TYPE</span> <span class="n">coordinate</span> <span class="k">AS</span> <span class="p">(</span><span class="n">brand</span> <span class="n">BRAND</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="n">doc_id</span> <span class="nb">BIGINT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="n">page</span><span class="p">:</span> <span class="nb">INTEGER</span><span class="p">);</span>
</code></pre></div></div>
<p>The utility of custom types is so <em>alluring</em> for modeling richer data in at the
database level because so much of our mental models for systems are driven by
data encapsulation. I see similar design patterns from my colleagues when working with Delta Lake tables. A preference for creating columns of deeply nested structs, despite my protestations around flattening the into wider table schemas with more columns.</p>

<p>The biggest performance downside with custom types that I observed was when
using custom types in <strong>indexes</strong> but the issue was obscured by Aurora’s
exceptional performance until we crossed into the <em>billions</em> scale.</p>

<p>For the PostgreSQL engine version we were running, custom types in indexes would only be used correctly if the full type was present in the query. Using the example above this meant that a query would <strong>not use the index correctly</strong> when querying on <code class="language-plaintext highlighter-rouge">doc_id</code> alone! Instead the query was required to construct a type inline, e.g.:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span> <span class="k">FROM</span> <span class="n">some_table</span> 
    <span class="k">WHERE</span> <span class="k">c</span> <span class="o">=</span> <span class="p">(</span><span class="s1">'scribd'</span><span class="p">,</span> <span class="mi">123</span><span class="p">,</span> <span class="k">NULL</span><span class="p">)::</span><span class="n">COORDINATE</span>

</code></pre></div></div>

<p>The inefficiencies of queries with a partial custom type predicate wasn’t
noticed until queries in hitting billion row tables started to slow down. Those
production query plans made it fairly obvious that the index wasn’t being used,
but it was not clear to me <em>why</em> until after we really considered the offending query plans.</p>

<p><strong>Storage</strong> of the custom type was also not something I considered until after
the billions scale where the indexes and table sizes ballooned. The <a href="https://www.postgresql.org/docs/current/datatype-enum.html">enumerated
type</a> occupies four
bytes on disk. Combined with the other two entries in the type each row
required 16 bytes of storage. With smaller scale data that’s kind of a “who
cares” amount of data but 10 billion rows that equates to around 149GiB to
store nothing but this one custom type in the table.</p>

<hr />

<p>The solution we ended up with to resolve the inefficiencies of the custom type
for query and storage performance was to switch towards a bit-masked 64-bit
integer with the custom type’s properties encoded within.</p>

<p>My colleague experimented with using a binary encoded field which had similar
benefits over a custom type. Ultimately the bitmask approach allowed us to
halve the storage requirements and improved query performance since the index
moved from a hash index to a <a href="https://www.postgresql.org/docs/current/indexes-types.html">b-tree
index</a> for
operations on that column.</p>

<p><strong>Billions</strong> is such an astronomically large number that I often explain that
the “physics of billions” is so fundamentally different that it’s like going
from Newtonian to Quantum physics: the old rules no longer apply. In our online
data system, we have tables that vary from hundreds of millions of rows, to
tens of billions of rows, and our modelling has to account for <em>both</em> which has
been an exciting challenge.</p>

<center><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XCv9Tviftgo?si=BzXciAynsuGwsshX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe></center>

<p>The system would not have gotten this far without some of the superpowers that
PostgreSQL has to offer. Originally we deployed to PostgreSQL 17 but after
watching the above session we were convinced to upgrade to PostgreSQL 18 and
reaped the additional performance rewards offered by the upgrade.</p>

<p>PostgreSQL by default is quite fast. Aurora/PostgreSQL by default is
exceptionally fast. As a data system grows the “nice problems to have” start
popping up and query plans, APM traces, and all other sorts of telemetry become
crucial to understanding how and where to start improving performance.</p>

<p>I would not recommend avoiding custom types in PostgreSQL, there is a time and
a place for them, and we’re still using them quite heavily, just not as indexed
columns!</p>]]></content><author><name>R. Tyler Croy</name></author><category term="postgresql" /><category term="data" /><category term="dataeng" /><summary type="html"><![CDATA[My current work project is one of the first Aurora/PostgreSQL deployments and already the largest. Success brings scaling challenges and the types of things seasoned operators classify as “good problems to have.” Compared to previous scaling work around Delta Lake the knobs and ways in which online relational databases scale is a muscle that has atrophied in the past decade. The relational database landscape is also quite different especially with Amazon Aurora which is quite well designedin the past decade. The relational database landscape is also quite different especially with Amazon Aurora which is quite well designed.]]></summary></entry><entry><title type="html">2026 April: Recently Studied Stuff</title><link href="https://brokenco.de//2026/04/30/fresh-from-rss.html" rel="alternate" type="text/html" title="2026 April: Recently Studied Stuff" /><published>2026-04-30T00:00:00+00:00</published><updated>2026-04-30T00:00:00+00:00</updated><id>https://brokenco.de//2026/04/30/fresh-from-rss</id><content type="html" xml:base="https://brokenco.de//2026/04/30/fresh-from-rss.html"><![CDATA[<p>Similar to last month I have given more intention to some of the interesting
things that I have stumbled across in my feed reader or the fediverse. Rather
than just a quip, boost, or reply, I have wanted to consolidate these thoughts
with more permanance here to my blog.</p>

<p>Chris’ talk below at <a href="https://northbaypython.org/">North Bay Python</a> was, as
his always are, well-delivered and worth consideration.</p>

<center><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/d7AeWFbOTHg?si=zW0bHhRpj--dsrdW" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen=""></iframe></center>

<p>The conclusion that he
draws towards the end is similar to something I was <a href="/2025/09/20/sacrificing-the-understanding.html">noodling last
year</a>:</p>

<blockquote>
  <p>At some point somebody, somewhere, is going to have to actually understand
how things work.</p>
</blockquote>

<p>Chris makes the point, as he typically does, much more thoughtfully and with a
stronger philosophical base.</p>

<hr />

<p>Had some discussions with the <a href="https://github.com/delta-io/delta-kernel-rs">delta-kernel-rs</a> developers after they mistakenly added a <em>ton</em> of new files to <code class="language-plaintext highlighter-rouge">tests/</code> blowing up test cycle times. Another community member shared <a href="https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html">this great overview</a> about <strong>not</strong> using Cargo integration tests.</p>

<hr />

<p>Catching up on <a href="https://open.substack.com/pub/dataengineeringcentral/p/revisiting-data-quality?utm_source=share&amp;utm_medium=android&amp;r=cxg56">Daniel’s thoughts on Data
Quality</a>
and reconsidering the domain. The generation of slop has resulted in renewed
discussions of “but how do we ensure correctness?” which is a great question to
be trying to answer, but I am still rather disappointed with the state of the
art for data quality tooling.</p>

<hr />

<p>I recommend <a href="https://etbe.coker.com.au/2026/03/29/communication-hostile-ais/">this blog
post</a> which
has some good citations for negative AI behaviors affecting free and open
source communities.</p>

<blockquote>
  <p>This is going to be a difficult problem to solve, more difficult than the
email spam problem we have been unable to solve after 30
years of working on it.</p>

  <p>This is also a very important problem, we are currently in an age where we have
access to information that most people couldn’t even dream of 30 years ago. We
also have disinformation that combines some of the worst aspects of
authoritarian regimes throughout history combined with the worst aspects of
cult brainwashing. If we lose access to the information but the disinformation
remains (or get worse) then the result will be terrible.</p>
</blockquote>

<hr />

<p>I really enjoy <a href="https://planet.debian.org">Planet Debian</a> as an aggregator of an international set of voices from the Debian community. I get exposed to so many different view points from around the free software ecosystem, which I really value. This past week I read 
<a href="https://blog.bofh.it/debian/id_473">this blog post</a> by a debian maintainer which I was so flummoxed by I <a href="/2026/03/25/do-not-comply.html">wrote out my thoughts on the topic here</a></p>

<hr />

<p>Streaming tar over SSH is one of the more novel Unix tricks I don’t get to use
much anymore. <a href="https://drewdevault.com/2026/03/28/2026-03-28-rsync-without-rsync.html">Drew
Devault</a>
shared some helpful tips for using it without needing to use incantations of
<code class="language-plaintext highlighter-rouge">rsync(1)</code>.</p>]]></content><author><name>R. Tyler Croy</name></author><category term="rss" /><category term="deltalake" /><category term="data" /><category term="dataengineering" /><category term="opensource" /><summary type="html"><![CDATA[Similar to last month I have given more intention to some of the interesting things that I have stumbled across in my feed reader or the fediverse. Rather than just a quip, boost, or reply, I have wanted to consolidate these thoughts with more permanance here to my blog.]]></summary></entry></feed>