<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Today I Learned</title><description>Short notes on things I learn day to day.</description><link>https://til.reight.io/</link><language>en</language><item><title>Partial indexes: index the column you sort by</title><link>https://til.reight.io/postgres-partial-index-order-by/</link><guid isPermaLink="true">https://til.reight.io/postgres-partial-index-order-by/</guid><pubDate>Sat, 12 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A background worker regularly fetched the oldest flagged rows from a table with millions of records:&lt;/p&gt;
&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; FROM&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; posts &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; needs_sync &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; true &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;ORDER BY&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; updated_at &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;LIMIT&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 200&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only a small fraction of the records were flagged, so I started with a partial index on the flag:&lt;/p&gt;
&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; posts (needs_sync) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; needs_sync &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; true;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This turned out to be less useful than I expected. Inside such an index every key is &lt;code&gt;true&lt;/code&gt;, because the value is taken from &lt;code&gt;needs_sync&lt;/code&gt;. The index can be used to find the rows, but cannot be used for sorting. So to get the oldest 200 rows, Postgres still has to fetch &lt;strong&gt;all&lt;/strong&gt; flagged rows and sort them before it can apply the &lt;code&gt;LIMIT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Put the column you &lt;code&gt;ORDER BY&lt;/code&gt; in the key and the flag in the &lt;code&gt;WHERE&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;CREATE&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt; INDEX&lt;/span&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt; ON&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; posts (updated_at) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; needs_sync &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; true;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The index scan can now stop after 200 entries. It can also be used for a fast index-only scan when counting the flagged rows:&lt;/p&gt;
&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;SELECT&lt;/span&gt;&lt;span style=&quot;color:#8BE9FD&quot;&gt; COUNT&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; posts &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;WHERE&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; needs_sync &lt;/span&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; true;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>postgres</category><category>indexing</category></item><item><title>Shim a missing libc header on Alpine</title><link>https://til.reight.io/alpine-shim-missing-libc-header/</link><guid isPermaLink="true">https://til.reight.io/alpine-shim-missing-libc-header/</guid><pubDate>Mon, 09 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In an &lt;code&gt;elixir:*-alpine&lt;/code&gt; image, &lt;code&gt;mix deps.compile&lt;/code&gt; failed on a native dependency (&lt;code&gt;picosat_elixir&lt;/code&gt;, the &lt;span class=&quot;caps&quot;&gt;SAT&lt;/span&gt;-solver &lt;span class=&quot;caps&quot;&gt;NIF&lt;/span&gt; that Ash uses for policies):&lt;/p&gt;
&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;c_src/picosat.c:8150:10: fatal error: sys/unistd.h: No such file or directory&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;sys/unistd.h&gt;&lt;/code&gt; is a &lt;a href=&quot;https://stackoverflow.com/questions/77691856/what-is-the-difference-between-unistd-h-and-sys-unistd-h&quot;&gt;glibc quirk&lt;/a&gt;. All it does is include &lt;code&gt;&amp;lt;unistd.h&gt;&lt;/code&gt;. The latter is the &lt;span class=&quot;caps&quot;&gt;POSIX&lt;/span&gt; header, so it’s the only one that musl provides.&lt;/p&gt;
&lt;p&gt;There’s no need to fork &lt;code&gt;picosat_elixir&lt;/code&gt; to fix this. I just added the same forwarding header to the image:&lt;/p&gt;
&lt;figure class=&quot;shiki-filename&quot;&gt;&lt;figcaption class=&quot;shiki-filename-title&quot;&gt;Dockerfile&lt;/figcaption&gt;&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;dockerfile&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF79C6&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; echo &lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt;&quot;#include &amp;lt;unistd.h&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#F8F8F2&quot;&gt; &gt; /usr/include/sys/unistd.h&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The trick works for other missing glibc forwarding headers too, as long as musl has the header they forward to.&lt;/p&gt;
&lt;p&gt;Other options:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Use Debian. Phoenix’s own generated Dockerfile already does.&lt;/li&gt;
	&lt;li&gt;For Ash specifically, replace &lt;code&gt;{:picosat_elixir, &quot;~&gt; 0.2&quot;}&lt;/code&gt; with the pure-Elixir &lt;code&gt;{:simple_sat, &quot;~&gt; 0.1&quot;}&lt;/code&gt;. It’s a bit slower but avoids &lt;span class=&quot;caps&quot;&gt;NIF&lt;/span&gt;-compilation issues entirely.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>docker</category><category>alpine</category><category>musl</category><category>c</category><category>elixir</category></item><item><title>Simple static web server</title><link>https://til.reight.io/simple-static-server/</link><guid isPermaLink="true">https://til.reight.io/simple-static-server/</guid><pubDate>Wed, 15 Mar 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Sometimes you need to quickly serve some static files for a preview. The good news is that you don’t have to install or configure a web server for that. If you have Python installed on your machine (which you probably do), there’s already a handy little web server ready for you.&lt;/p&gt;
&lt;p&gt;Just run this command to serve the current folder:&lt;/p&gt;
&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;python3&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; http.server&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; 8080&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The caveat is that it doesn’t support the live reload. So if you need that, a better option could be &lt;a href=&quot;https://www.npmjs.com/package/live-server&quot;&gt;live-server&lt;/a&gt; from npm.&lt;/p&gt;
&lt;pre class=&quot;astro-code dracula&quot; style=&quot;background-color:#282A36;color:#F8F8F2; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50FA7B&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#F1FA8C&quot;&gt; live-server&lt;/span&gt;&lt;span style=&quot;color:#BD93F9&quot;&gt; --port=8080&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>python</category><category>npm</category><category>cli</category><category>static-server</category></item></channel></rss>