<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Postgres on</title><link>/tags/postgres/</link><description>Recent content in Postgres on</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 10 Nov 2024 15:37:00 +0000</lastBuildDate><atom:link href="/tags/postgres/index.xml" rel="self" type="application/rss+xml"/><item><title>Lesson 10: Redis, MongoDB, and Non-Relational Stores — Beyond SQL</title><link>/post/rust/rust-db-nosql/</link><pubDate>Sun, 10 Nov 2024 15:37:00 +0000</pubDate><guid>/post/rust/rust-db-nosql/</guid><description>&lt;p&gt;I spent a week optimizing a Postgres query that powered a leaderboard. It involved a complex window function over millions of rows, and no amount of indexing got it under 200ms. Then a senior engineer walked over, looked at the query, and said &amp;ldquo;Why isn&amp;rsquo;t this in Redis?&amp;rdquo; He was right. I replaced 30 lines of SQL with a sorted set and the response time dropped to 2ms.&lt;/p&gt;
&lt;p&gt;Not every data problem is a SQL problem. Sometimes you need the right tool, not a better query plan.&lt;/p&gt;</description></item><item><title>Lesson 9: N+1 Queries, Indexes, and EXPLAIN — Database performance in Rust</title><link>/post/rust/rust-db-performance/</link><pubDate>Wed, 06 Nov 2024 07:52:00 +0000</pubDate><guid>/post/rust/rust-db-performance/</guid><description>&lt;p&gt;A coworker asked me to look at an endpoint that was taking 8 seconds to return 50 orders. The table had 200K rows — not big by any standard. I opened the code, and the pattern was immediately obvious: fetch 50 orders, then for each order, fetch its items in a separate query. Fifty-one database round trips where one would do.&lt;/p&gt;
&lt;p&gt;The N+1 query problem is the most common performance mistake in database-backed applications, and Rust doesn&amp;rsquo;t magically prevent it. You need to know what to look for.&lt;/p&gt;</description></item><item><title>Lesson 8: Testing with Real Databases — No more mocking SQL</title><link>/post/rust/rust-db-testing/</link><pubDate>Sun, 03 Nov 2024 13:15:00 +0000</pubDate><guid>/post/rust/rust-db-testing/</guid><description>&lt;p&gt;I spent two days debugging a production issue where a query returned duplicate rows. The unit tests all passed — every mock returned exactly the expected data. The problem was a missing &lt;code&gt;DISTINCT&lt;/code&gt; in a JOIN query that only manifested with real data containing multiple matching rows. The mocks were too perfect. They never produced the messy data that real databases contain.&lt;/p&gt;
&lt;p&gt;That was when I stopped mocking SQL.&lt;/p&gt;
&lt;h2 id="the-problem-with-mocking-database-calls"&gt;The Problem with Mocking Database Calls&lt;/h2&gt;
&lt;p&gt;Mocking databases is popular because it&amp;rsquo;s convenient. You don&amp;rsquo;t need Docker, you don&amp;rsquo;t need a test database, your tests run in milliseconds. But you&amp;rsquo;re testing the wrong thing.&lt;/p&gt;</description></item><item><title>Lesson 7: Building Type-Safe Query Builders — Queries that can't be wrong</title><link>/post/rust/rust-db-query-builder/</link><pubDate>Fri, 01 Nov 2024 09:28:00 +0000</pubDate><guid>/post/rust/rust-db-query-builder/</guid><description>&lt;p&gt;I was reviewing a PR that had a search endpoint with 12 optional filters. The handler was a 200-line function full of &lt;code&gt;if let Some(...)&lt;/code&gt; blocks, each appending a different SQL fragment to a &lt;code&gt;String&lt;/code&gt;. It worked — until someone forgot a space between &lt;code&gt;AND&lt;/code&gt; and a column name, and the query silently returned zero results instead of erroring. No compile error. No test failure. Just a missing space in a string.&lt;/p&gt;</description></item><item><title>Lesson 6: The Repository Pattern in Rust — Abstracting persistence</title><link>/post/rust/rust-db-repository-pattern/</link><pubDate>Wed, 30 Oct 2024 16:40:00 +0000</pubDate><guid>/post/rust/rust-db-repository-pattern/</guid><description>&lt;p&gt;I once inherited a codebase where every HTTP handler had raw SQL queries inline — &lt;code&gt;sqlx::query!&lt;/code&gt; calls scattered through 80+ route handlers. Changing a table name meant grep-and-replace across the entire project. Adding a cache layer meant touching every handler. Testing a handler meant spinning up a real database. It worked, technically, but nobody wanted to touch it.&lt;/p&gt;
&lt;p&gt;The repository pattern fixes this. It puts a wall between your business logic and your database, and that wall pays for itself fast.&lt;/p&gt;</description></item><item><title>Lesson 5: Transactions and Error Rollback — Atomic operations</title><link>/post/rust/rust-db-transactions/</link><pubDate>Mon, 28 Oct 2024 10:05:00 +0000</pubDate><guid>/post/rust/rust-db-transactions/</guid><description>&lt;p&gt;A payment service I worked on had a subtle bug: it deducted money from the user&amp;rsquo;s wallet, then tried to create an order record. If the order insert failed — constraint violation, timeout, anything — the money was already gone. The user&amp;rsquo;s balance was decremented but they had no order. We called these &amp;ldquo;ghost charges&amp;rdquo; internally, and customers called them something less polite.&lt;/p&gt;
&lt;p&gt;The fix was embarrassingly simple: wrap both operations in a transaction.&lt;/p&gt;</description></item><item><title>Lesson 4: Schema Migrations in Rust Projects — Evolving your database</title><link>/post/rust/rust-db-migrations/</link><pubDate>Sat, 26 Oct 2024 19:12:00 +0000</pubDate><guid>/post/rust/rust-db-migrations/</guid><description>&lt;p&gt;A teammate once ran &lt;code&gt;ALTER TABLE orders DROP COLUMN status&lt;/code&gt; on the production database because he&amp;rsquo;d tested it locally and &amp;ldquo;it worked fine.&amp;rdquo; What he didn&amp;rsquo;t realize was that three other services depended on that column, and they all started throwing errors simultaneously. We spent the evening restoring from a backup.&lt;/p&gt;
&lt;p&gt;Schema migrations exist to prevent exactly this — they&amp;rsquo;re version control for your database.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Your database schema isn&amp;rsquo;t static. Features get added, requirements change, data models evolve. You need a way to:&lt;/p&gt;</description></item><item><title>Lesson 3: Connection Pooling with deadpool and bb8 — Managing database connections</title><link>/post/rust/rust-db-connection-pools/</link><pubDate>Thu, 24 Oct 2024 14:35:00 +0000</pubDate><guid>/post/rust/rust-db-connection-pools/</guid><description>&lt;p&gt;I once watched a Rust service fall over under modest load — maybe 200 concurrent requests — because every request opened a new Postgres connection, used it for one query, and dropped it. The database was spending more time on TLS handshakes and connection setup than on actual queries. CPU was fine, memory was fine, but &lt;code&gt;pg_stat_activity&lt;/code&gt; showed 200+ connections churning constantly. The fix took ten lines of code: add a connection pool.&lt;/p&gt;</description></item><item><title>Lesson 2: Diesel — The ORM approach</title><link>/post/rust/rust-db-diesel-intro/</link><pubDate>Tue, 22 Oct 2024 08:47:00 +0000</pubDate><guid>/post/rust/rust-db-diesel-intro/</guid><description>&lt;p&gt;I was two weeks into a project where I had to write about 40 CRUD endpoints for an admin panel. Each one needed the same pattern: validate input, build a query, map results to a struct, handle errors. By endpoint number six, I was copy-pasting SQLx queries and changing column names. That&amp;rsquo;s when a colleague asked, &amp;ldquo;Why aren&amp;rsquo;t you using Diesel?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;He was right. Sometimes you don&amp;rsquo;t want to write SQL. Sometimes you want the boilerplate to disappear.&lt;/p&gt;</description></item><item><title>Lesson 1: SQLx — Compile-time checked queries</title><link>/post/rust/rust-db-sqlx-intro/</link><pubDate>Sun, 20 Oct 2024 11:23:00 +0000</pubDate><guid>/post/rust/rust-db-sqlx-intro/</guid><description>&lt;p&gt;I shipped a typo in a SQL column name to production last year. The column was &lt;code&gt;user_nme&lt;/code&gt; instead of &lt;code&gt;user_name&lt;/code&gt;. The Go service compiled fine, the tests passed (they used mocks), and the bug sat in production for three hours before a customer reported it. Three hours of silent failures because the query returned zero rows instead of erroring out.&lt;/p&gt;
&lt;p&gt;That was the day I started using SQLx in Rust. I haven&amp;rsquo;t shipped a SQL typo since.&lt;/p&gt;</description></item></channel></rss>