<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Miguel Paracuellos</title>
    <description>The latest articles on DEV Community by Miguel Paracuellos (@miguelparacuellos).</description>
    <link>https://dev.to/miguelparacuellos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1259872%2F19f26214-83a3-4b09-9ace-23cdaa83cc4e.jpeg</url>
      <title>DEV Community: Miguel Paracuellos</title>
      <link>https://dev.to/miguelparacuellos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/miguelparacuellos"/>
    <language>en</language>
    <item>
      <title>OpenAI Just Went Open Source (For Real This Time)</title>
      <dc:creator>Miguel Paracuellos</dc:creator>
      <pubDate>Wed, 06 Aug 2025 19:18:43 +0000</pubDate>
      <link>https://dev.to/miguelparacuellos/openai-just-went-open-source-for-real-this-time-2dao</link>
      <guid>https://dev.to/miguelparacuellos/openai-just-went-open-source-for-real-this-time-2dao</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Two models. Open weights. No API lock-in. This release is way more than just another LLM drop.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🚀 The Big Moment: OpenAI Open-Sources GPT-OSS
&lt;/h2&gt;

&lt;p&gt;Remember when OpenAI said they &lt;em&gt;might&lt;/em&gt; open source again someday?&lt;/p&gt;

&lt;p&gt;Well, they just did. And it’s not some toy model. It’s a full-blown, reasoning powerhouse that you can run &lt;strong&gt;on your laptop&lt;/strong&gt; or fine-tune for your startup. No paywall. No black box. No strings attached.&lt;/p&gt;

&lt;p&gt;In this article, I’ll break down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What GPT-OSS is&lt;/li&gt;
&lt;li&gt;Why this release is a game-changer&lt;/li&gt;
&lt;li&gt;What you can actually &lt;em&gt;do&lt;/em&gt; with it&lt;/li&gt;
&lt;li&gt;How it stacks up against the current LLM landscape&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive in.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧠 What OpenAI Just Dropped
&lt;/h2&gt;

&lt;p&gt;OpenAI released two new open-weight language models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;gpt-oss-120b&lt;/strong&gt;: A 117 billion parameter model using a Mixture-of-Experts (MoE) architecture. It activates just 5.1 billion parameters per token and competes with o4-mini, outperforming many closed models in reasoning and code tasks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;gpt-oss-20b&lt;/strong&gt;: A more compact 21 billion parameter model that activates 3.6 billion per token. It can run on consumer GPUs — yes, your gaming rig with 16 GB VRAM might handle it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are released under the &lt;strong&gt;Apache 2.0 license&lt;/strong&gt;, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can modify them&lt;/li&gt;
&lt;li&gt;You can deploy them commercially&lt;/li&gt;
&lt;li&gt;You can fine-tune them for your use case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They’re available now via Hugging Face, AWS, Azure, and more.&lt;/p&gt;

&lt;p&gt;This isn’t OpenAI dipping a toe in the water — it’s a cannonball into the open-source LLM pool.&lt;/p&gt;




&lt;h2&gt;
  
  
  💥 Why This Is a Game-Changer
&lt;/h2&gt;

&lt;p&gt;Let’s not understate it: this is &lt;strong&gt;huge&lt;/strong&gt;. Here’s why:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;First real open release since GPT-2 (2019)&lt;/strong&gt;. That’s six years of proprietary-only models — until now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;They’re actually useful&lt;/strong&gt;. Chain-of-thought reasoning, tool use, long-context understanding, and benchmark wins — these aren’t just research artifacts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You can run them locally&lt;/strong&gt;. The 20b model runs on decent consumer hardware. The 120b model needs something heavier (like an 80 GB GPU) but is still accessible for labs or serious devs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;128k context window&lt;/strong&gt;. That’s massive. Think entire books, legal contracts, and huge codebases — all processed in a single go.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;They’re safe&lt;/strong&gt;. OpenAI ran third-party evaluations for biosecurity, cybersecurity, and alignment. Even adversarial fine-tuning didn’t make them go off the rails.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short: OpenAI just handed the world a high-performance, permissionless LLM. For free.&lt;/p&gt;




&lt;h2&gt;
  
  
  🛠 What You Can Do With These Models
&lt;/h2&gt;

&lt;p&gt;So, you’ve got two shiny new models. What can you &lt;em&gt;actually&lt;/em&gt; build with them?&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Run It on Your Own Hardware
&lt;/h3&gt;

&lt;p&gt;Got a decent GPU? The 20b model should run smoothly. No more waiting on API tokens or worrying about rate limits.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fine-Tune for Your Domain
&lt;/h3&gt;

&lt;p&gt;Legal assistants, medical chatbots, internal coding copilots — train it on your dataset and build something tailored to your use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Build AI Agents with Tool Use
&lt;/h3&gt;

&lt;p&gt;Want to create an AI that plans, executes, and explains its actions? These models support chain-of-thought and tool-calling workflows. Perfect for agent-style systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Power Retrieval-Augmented Generation (RAG)
&lt;/h3&gt;

&lt;p&gt;With 128k tokens of context, you can feed in massive docs, search results, logs — and get accurate, coherent output without complex chunking logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 How GPT-OSS Stacks Up
&lt;/h2&gt;

&lt;p&gt;OpenAI’s move clearly targets open-weight rivals like Meta’s LLaMA, Mistral, Qwen, and DeepSeek. But GPT-OSS brings some unique advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Apache license&lt;/strong&gt;: No non-commercial caveats&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning-first design&lt;/strong&gt;: Built for logic, not just language&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Huge context window&lt;/strong&gt;: 128k tokens, no hacks needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MoE architecture&lt;/strong&gt;: Activates fewer parameters for better performance-per-watt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And maybe most important: &lt;strong&gt;transparency&lt;/strong&gt;. You can see what’s happening under the hood. No more mystery-model behavior.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔮 What’s Next?
&lt;/h2&gt;

&lt;p&gt;This feels like the start of something much bigger. A few questions on everyone’s mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Will OpenAI release even larger OSS models?&lt;/li&gt;
&lt;li&gt;Will more companies switch to local fine-tunes over API lock-in?&lt;/li&gt;
&lt;li&gt;How fast will the ecosystem around GPT-OSS grow — adapters, RAG pipelines, fine-tunes?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You could be early to all of it. And this time, you don’t need to be in a research lab to join the fun.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Final Thoughts
&lt;/h2&gt;

&lt;p&gt;OpenAI just open-sourced something that’s not only free — it’s powerful, fast, and &lt;strong&gt;yours&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The best part? You don’t need to be a PhD or a VC-backed founder to use it. Just a laptop, a terminal, and an idea.&lt;/p&gt;




&lt;h2&gt;
  
  
  📣 Want More?
&lt;/h2&gt;

&lt;p&gt;I’ll be writing a hands-on guide next - how to run GPT-OSS locally, fine-tune it, and deploy it in real-world apps.&lt;/p&gt;

&lt;p&gt;Follow me if you want that in your feed. And if you’ve already tried GPT-OSS, leave a comment. I’d love to hear what you're building.&lt;/p&gt;

&lt;p&gt;Let’s make open AI &lt;em&gt;actually&lt;/em&gt; mean something again.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>AI Coding Assistants Don't Suck Anymore</title>
      <dc:creator>Miguel Paracuellos</dc:creator>
      <pubDate>Mon, 04 Aug 2025 13:44:57 +0000</pubDate>
      <link>https://dev.to/miguelparacuellos/ai-coding-assistants-dont-suck-anymore-3gco</link>
      <guid>https://dev.to/miguelparacuellos/ai-coding-assistants-dont-suck-anymore-3gco</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The hype is fading, the hallucinations are dropping, and the robots finally feel like teammates instead of toddlers with keyboards.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  ☕️ Quick Sip Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New models, fewer face-palms.&lt;/strong&gt; Claude Sonnet 4 (via Cursor), GPT-4.5, and Gemini 2.5 crank hallucinations down to ~15%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed is real, trust is tricky.&lt;/strong&gt; A controlled METR study showed a 55% speed boost, but Stack Overflow’s 2025 survey says only 29% of devs actually trust AI output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;My reality check:&lt;/strong&gt; AI now handles the boring 80%, but the final 20% is still very human. I’ve never merged a PR without running tests and giving the code a side-eye.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. The Day My “Intern” Grew Up
&lt;/h2&gt;

&lt;p&gt;Back in early ’24, AI coding tools felt... twitchy. I remember asking it to build a login page and getting something that not only skipped validation but practically whispered "hey, let’s hardcode a password for fun."&lt;/p&gt;

&lt;p&gt;But I didn’t quit on it. I kept using it — more cautiously at first — learning where it helped and where it hallucinated. It was like watching a junior dev slowly grow up. The suggestions started making more sense. The bugs showed up less often. And somewhere between dozens of commits and a few thousand prompts, I realized: I was trusting it more than I thought.&lt;/p&gt;

&lt;p&gt;Then came May 2025. Cursor integrated Claude Sonnet 4, and everything clicked. I typed: “Scaffold a Nuxt 3 page listing Stripe invoices with a Tailwind table.”&lt;/p&gt;

&lt;p&gt;Two lattes later, I had a fully working page: clean props, sensible Tailwind, pagination built-in, no missing imports. It didn’t just look good — it ran.&lt;/p&gt;

&lt;p&gt;Why the glow-up?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://research.aimultiple.com/ai-hallucination" rel="noopener noreferrer"&gt;AI Hallucination Benchmark 2025&lt;/a&gt; clocks GPT-4.5 and Sonnet 4 at ~15% hallucinations (down from over 50%).&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://arxiv.org/abs/2302.06590" rel="noopener noreferrer"&gt;METR study&lt;/a&gt; shows AI can make devs 55% faster on focused tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That aligned with what I was feeling: the tool had matured — and maybe so had I.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Where AI Shines — And Where It Slips
&lt;/h2&gt;

&lt;p&gt;After months with Sonnet 4, here’s what’s felt like magic — and what still gives me pause:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What works well:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Boilerplate scaffolding (components, DTOs)&lt;/li&gt;
&lt;li&gt;Writing unit tests&lt;/li&gt;
&lt;li&gt;Repo Q&amp;amp;A like “Where do we parse JWTs?”&lt;/li&gt;
&lt;li&gt;Project-wide refactors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Where I don’t trust it (yet):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security-critical flows like auth and crypto&lt;/li&gt;
&lt;li&gt;Perf-sensitive logic&lt;/li&gt;
&lt;li&gt;Legacy spaghetti with zero documentation&lt;/li&gt;
&lt;li&gt;Tasks I haven’t mentally designed yet&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If I don’t know exactly what I want, the model will happily hallucinate an entire fantasy architecture. Then I get to debug my own laziness at 2 a.m.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. My Four-Step Prompt Ritual 🙏
&lt;/h2&gt;

&lt;p&gt;Here’s how I talk to the model now:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set the scene.&lt;/strong&gt; “You're a senior dev experienced in Nuxt and Stripe.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Describe the goal.&lt;/strong&gt; “Implement server-side pagination for /api/invoices.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set the stack.&lt;/strong&gt; “Nuxt 3, Prisma, PostgreSQL, limit 50 rows, return totalCount.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guide the scope.&lt;/strong&gt; “Please outline the steps only.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;From there, I review its plan, give feedback, and go step-by-step through implementation. It feels like pair programming — minus the headphone tugging.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Trust Issues: Everyone’s Using It, Nobody’s Sleeping Easy
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;80% of devs use AI tools (according to Stack Overflow 2025).&lt;/li&gt;
&lt;li&gt;Only 29% trust the output unedited.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reddit is full of rants like “Management wants 20% of commits from Copilot.” One post even mentioned execs tracking prompt counts per day.&lt;/p&gt;

&lt;p&gt;That’s not how I roll. I’d rather measure features shipped, not lines of AI-assisted code.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Numbers Don’t Lie
&lt;/h2&gt;

&lt;p&gt;One recent feature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Old-school dev time:&lt;/strong&gt; ~3h 45m&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;45m for scaffolding&lt;/li&gt;
&lt;li&gt;120m for core logic&lt;/li&gt;
&lt;li&gt;60m for tests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;With Cursor + Sonnet 4:&lt;/strong&gt; ~1h 45m&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5m prompt for scaffolding&lt;/li&gt;
&lt;li&gt;90m prompts + tweaks&lt;/li&gt;
&lt;li&gt;10m for tests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;That’s two hours saved — enough for a gym session, or let’s be real, another coffee and a doomscroll.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Five Things I Wish I’d Known Sooner
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Design before you prompt.&lt;/strong&gt; AI isn’t great at mind-reading.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Break it up.&lt;/strong&gt; Big tasks become small, accurate prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test everything.&lt;/strong&gt; No green CI, no merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sleep on major merges.&lt;/strong&gt; AI optimism is real — and sneaky.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t ditch juniors.&lt;/strong&gt; Pair them with AI, then make them explain every line.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  7. So… Should You Trust the Robot?
&lt;/h2&gt;

&lt;p&gt;Yes — but only like you’d trust a hyper-literal intern. Brilliant with grunt work. Hopeless with nuance. When I give it structure and oversight, it makes me faster. When I hand it the wheel, it usually drives into a wall of undefined variables.&lt;/p&gt;




&lt;h2&gt;
  
  
  Your Turn
&lt;/h2&gt;

&lt;p&gt;Are you vibing with the new generation of AI dev tools? Or still fighting ghosts in your PRs?&lt;/p&gt;

&lt;p&gt;Drop a story below — horror or happy ending. And if enough folks ask, I’ll share my prompt cheat sheet in the next post.&lt;/p&gt;




&lt;p&gt;This article was originally published on Medium:&lt;br&gt;
&lt;a href="https://medium.com/@miguel.paracuellos.inf/ai-coding-assistants-dont-suck-anymore-415764f863d2" rel="noopener noreferrer"&gt;AI Coding Assistants No Longer Hallucinate — If You Know What You’re Doing&lt;/a&gt;&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>ai</category>
      <category>cursor</category>
      <category>claude</category>
    </item>
    <item>
      <title>5 PostgreSQL Tricks That Made My SaaS x10 Faster (2025 Edition)</title>
      <dc:creator>Miguel Paracuellos</dc:creator>
      <pubDate>Wed, 30 Jul 2025 07:10:33 +0000</pubDate>
      <link>https://dev.to/miguelparacuellos/5-postgresql-tricks-that-made-my-saas-10x-faster-2025-edition-2llj</link>
      <guid>https://dev.to/miguelparacuellos/5-postgresql-tricks-that-made-my-saas-10x-faster-2025-edition-2llj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Five copy‑pasteable fixes that turned sluggish production queries into lightning‑fast responses. All examples use &lt;strong&gt;generic tables&lt;/strong&gt;—&lt;em&gt;orders&lt;/em&gt;, &lt;em&gt;users&lt;/em&gt;, &lt;em&gt;products&lt;/em&gt;—so you can follow along even if you’re new to Postgres.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Why This Matters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slow queries cost money&lt;/strong&gt; (cloud bills climb, customers churn).&lt;/li&gt;
&lt;li&gt;Most blog posts stop at “just add an index”—real life is messier.&lt;/li&gt;
&lt;li&gt;These five techniques gave my SaaS a &lt;strong&gt;10× speed boost&lt;/strong&gt; this year &lt;em&gt;without&lt;/em&gt; bigger hardware.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you store anything more than a to‑do list, stick around.&lt;/p&gt;




&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Measure First 🔬 — &lt;code&gt;EXPLAIN ANALYZE BUFFERS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Eliminate Duplicate Rows ⚔️ — &lt;code&gt;LEFT JOIN LATERAL&lt;/code&gt; + &lt;code&gt;json_agg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Index Power‑Ups 🚀 — Partial &amp;amp; Covering Indexes&lt;/li&gt;
&lt;li&gt;One‑Pass Stats 📊 — &lt;code&gt;FILTER&lt;/code&gt; Aggregates&lt;/li&gt;
&lt;li&gt;Readable + Fast 🧩 — CTEs (with a dash of LATERAL)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;(Skim the headings now, then read straight through—each trick builds on the last.)&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Measure First 🔬 — &lt;code&gt;EXPLAIN ANALYZE BUFFERS&lt;/code&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule #1 – Never tune blind.&lt;/strong&gt; You need real numbers before you change anything.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;EXPLAIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ANALYZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BUFFERS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'30 days'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Red Flags
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Actual vs Estimated Rows&lt;/strong&gt; &amp;gt; 10× → run &lt;code&gt;ANALYZE&lt;/code&gt; or fix statistics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node Execution Time&lt;/strong&gt; dominates (&amp;gt; 70 %) → add an index or rewrite the join.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Read Blocks&lt;/strong&gt; huge on a “small” query → you’re hitting disk, add an index or more cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Upload the plan to &lt;a href="https://explain.dalibo.com/" rel="noopener noreferrer"&gt;https://explain.dalibo.com/&lt;/a&gt; for an instant visual map of bottlenecks.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Eliminate Duplicate Rows ⚔️ — &lt;code&gt;LEFT JOIN LATERAL&lt;/code&gt; + &lt;code&gt;json_agg&lt;/code&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule #2 – Aggregate as close to the data as possible.&lt;/strong&gt; One parent row in, one parent row out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Use Case
&lt;/h3&gt;

&lt;p&gt;Return every &lt;strong&gt;order&lt;/strong&gt; with its &lt;strong&gt;items&lt;/strong&gt;—but keep the result set to &lt;em&gt;one row per order&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Before&lt;/strong&gt; – Classic join (row explosion)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt;   &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;order_items&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Result
 id | total | item_id | qty
----+-------+---------+-----
101 | 49.00 |  9001   |  1
101 | 49.00 |  9002   |  2
102 | 15.00 |  9003   |  1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;A single order with two items becomes three rows.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;After&lt;/strong&gt; – &lt;code&gt;LATERAL&lt;/code&gt; + &lt;code&gt;json_agg&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;json_agg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt;   &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="k"&gt;LATERAL&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;order_items&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Result
 id | total | items
----+-------+-------------------------------------------------------
101 | 49.00 | [{"id":9001,"qty":1},{"id":9002,"qty":2}]
102 | 15.00 | [{"id":9003,"qty":1}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;One row per order; items are delivered as a tidy JSON array.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outcome:&lt;/strong&gt; Dashboard latency dropped &lt;strong&gt;650 ms → 38 ms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Index &lt;code&gt;order_items.order_id&lt;/code&gt; so each per‑row sub‑query uses an index scan, not a sequential scan.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Index Power‑Ups 🚀 — Partial &amp;amp; Covering Indexes
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule #3 – Build the &lt;em&gt;smallest&lt;/em&gt; index that fully answers the query.&lt;/strong&gt; Smaller indexes read faster &lt;em&gt;and&lt;/em&gt; write faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3.1 Partial Index (only &lt;em&gt;active&lt;/em&gt; rows)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_user_active&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;deleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Indexes just the rows you actually query—often 90 % smaller than a full index.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Covering / INCLUDE Index (avoid heap access)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;idx_orders_status_inc&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;INCLUDE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Postgres can now satisfy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'SHIPPED'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;using &lt;em&gt;only&lt;/em&gt; the index—no table lookup at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On 100 k rows:&lt;/strong&gt; latency &lt;strong&gt;120 ms → 9 ms&lt;/strong&gt;; buffer reads &lt;strong&gt;18 k → 1 k&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Prove the footprint with &lt;code&gt;SELECT pg_size_pretty(pg_relation_size('idx_orders_status_inc'));&lt;/code&gt;—stakeholders love hard numbers.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. One‑Pass Stats 📊 — &lt;code&gt;FILTER&lt;/code&gt; Aggregates
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule #4 – Scan once, compute many metrics.&lt;/strong&gt; Let Postgres do the heavy lifting in a single pass.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Before&lt;/strong&gt; – Two separate scans
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;             &lt;span class="c1"&gt;-- total&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'SHIPPED'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;-- shipped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;After&lt;/strong&gt; – One scan, multiple metrics
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                                           &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'SHIPPED'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;shipped_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;AVG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;FILTER&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'SHIPPED'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;avg_shipped_value&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dashboard latency:&lt;/strong&gt; &lt;strong&gt;45 ms → 12 ms&lt;/strong&gt; on 500 k rows.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Combine with the covering index from Section 3—your aggregate becomes index‑only.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Readable + Fast 🧩 — CTEs (with LATERAL)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule #5 – Isolate heavy logic, then reuse it.&lt;/strong&gt; CTEs make complex queries readable; Postgres 15 inlines them for free speed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Goal
&lt;/h3&gt;

&lt;p&gt;Return every &lt;strong&gt;product&lt;/strong&gt; with its &lt;strong&gt;latest price&lt;/strong&gt;—one row each.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Before&lt;/strong&gt; – Correlated sub‑select (runs per product)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;
        &lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;
        &lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
        &lt;span class="k"&gt;ORDER&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;pr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changed_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
        &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;latest_price&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;After&lt;/strong&gt; – CTE + &lt;code&gt;DISTINCT ON&lt;/code&gt; + LATERAL
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;latest_prices&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;DISTINCT&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;prices&lt;/span&gt;
  &lt;span class="k"&gt;ORDER&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;changed_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;changed_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt;   &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="k"&gt;LATERAL&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;changed_at&lt;/span&gt;
  &lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;latest_prices&lt;/span&gt; &lt;span class="n"&gt;lp&lt;/span&gt;
  &lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;lp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;lp&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On 10 k products: &lt;strong&gt;780 ms → 54 ms&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tip:&lt;/em&gt; Add an index on &lt;code&gt;(product_id, changed_at DESC)&lt;/code&gt; in &lt;em&gt;prices&lt;/em&gt; so &lt;code&gt;DISTINCT ON&lt;/code&gt; is instant.&lt;/p&gt;




&lt;h2&gt;
  
  
  What’s Next?
&lt;/h2&gt;

&lt;p&gt;If you found these tricks helpful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smash &lt;strong&gt;Clap&lt;/strong&gt; so more devs see the post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow&lt;/strong&gt; me for deep‑dive follow‑ups on each technique.&lt;/li&gt;
&lt;li&gt;Drop your slowest Postgres query in the comments—I may refactor it in a future article.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your query planner salutes you 🚀&lt;/p&gt;




&lt;p&gt;This article was originally published on Medium:&lt;br&gt;
&lt;a href="https://medium.com/@miguel.paracuellos.inf/5-postgresql-tricks-that-made-my-saas-10-faster-2025-edition-e8fb7f3f82f7" rel="noopener noreferrer"&gt;5 PostgreSQL Tricks That Made My SaaS x10 Faster (2025 Edition)&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>softwaredevelopment</category>
      <category>performance</category>
      <category>database</category>
    </item>
    <item>
      <title>Understanding git bisect!</title>
      <dc:creator>Miguel Paracuellos</dc:creator>
      <pubDate>Thu, 04 Jul 2024 19:52:52 +0000</pubDate>
      <link>https://dev.to/miguelparacuellos/understanding-git-bisect-hki</link>
      <guid>https://dev.to/miguelparacuellos/understanding-git-bisect-hki</guid>
      <description>&lt;p&gt;Have you ever been put in a situation where a bug has been spotted on your project, which you know was not there some time ago but you do not know when it was introduced. &lt;/p&gt;

&lt;p&gt;This situation forces you into, at least, 2 possible paths 👇🏻&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trying to debug your codebase to find out where the bug is coming from, which in large codebases or certain situations can become difficult.&lt;/li&gt;
&lt;li&gt;Going back to previous commits one by one, which in big projects or those shared by lots of people may imply going back tons of commits, which can become really time consuming to say the least.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this seems like the situation you’re facing or have ever faced, keep reading!&lt;/p&gt;

&lt;p&gt;Imagine you’re facing the following case 👇🏻&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4o5jkybx5ohgitfyg6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg4o5jkybx5ohgitfyg6n.png" alt="Example Image 1" width="800" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you needed to spot where the issue was introduced at, you would start a linear search where you would go back 1 commit by 1 commit and seeing where the issue was introduced&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7wurxi77nmxx2k660ui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx7wurxi77nmxx2k660ui.png" alt="Example Image 2" width="800" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine the issue was introduced 40 commits ago, you would have been forced to checkout 40 times until you found the first commit where the bug did not exist 😱&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does &lt;code&gt;git bisect&lt;/code&gt; offer?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The idea behind &lt;strong&gt;&lt;code&gt;git bisect&lt;/code&gt;&lt;/strong&gt; is to replace the linear search by &lt;a href="https://www.geeksforgeeks.org/binary-search/"&gt;a binary search&lt;/a&gt;. Let’s look at it through an example (for the sake of simplicity, the example will be reduced to a use case with 8 commits) 👇🏻&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9saxs2a2i9nm1wn5w3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9saxs2a2i9nm1wn5w3u.png" alt="Image description" width="800" height="173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When running &lt;code&gt;git bisect&lt;/code&gt;  we will be asked to give a commit in which the issue was not happening (start commit) and a commit where the issue has been spotted (end commit):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start commit → &lt;em&gt;Commit 1&lt;/em&gt; (just try some random older commits and take the first one that works)&lt;/li&gt;
&lt;li&gt;End commit → &lt;em&gt;Commit 8&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviz61ax4ogsu6ht6jiz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fviz61ax4ogsu6ht6jiz1.png" alt="Image description" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Binary search will take a random commit in the middle called pivot, Commit 5 for example, and check if the issue still appeared there or not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ecsaluosl0n1j3o3mca.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ecsaluosl0n1j3o3mca.png" alt="Image description" width="800" height="229"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On our case, &lt;em&gt;Commit 5&lt;/em&gt; still presents the issue so we can ensure that &lt;em&gt;Commit 6 &amp;amp; Commit 7 &amp;amp; Commit 8&lt;/em&gt; won’t be the ones that introduced it. &lt;/p&gt;

&lt;p&gt;Just like this, we have avoided checking &lt;em&gt;Commit 6 &amp;amp; Commit 7&lt;/em&gt;. Way to go!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09ohx6wpuen849vw1jar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09ohx6wpuen849vw1jar.png" alt="Image description" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will just take a pivot around the middle again, on this case &lt;em&gt;Commit 2&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzs6mh762flbpzvpfia0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzzs6mh762flbpzvpfia0.png" alt="Image description" width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, &lt;em&gt;Commit 2&lt;/em&gt; does not present the issue! Therefore, we can ensure that &lt;em&gt;Commit 1&lt;/em&gt; did not introduce it neither. Another commit less to check again!&lt;/p&gt;

&lt;p&gt;We just need to check if the bug was introduced by &lt;em&gt;Commit 3&lt;/em&gt; or &lt;em&gt;Commit 4&lt;/em&gt; 🏃🏻&lt;/p&gt;

&lt;p&gt;We’ll repeat the process!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbi8cq5eu4pfupyg6rb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frbi8cq5eu4pfupyg6rb7.png" alt="Image description" width="800" height="618"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same as before is done and therefore we’ll easily find out that &lt;em&gt;Commit 3&lt;/em&gt; introduced our bug, and now we just need to look through the changes done in that specific commit, easy! 🥳&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You might be wondering…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Okay the drawings look good but, is this really faster? &lt;/p&gt;

&lt;p&gt;In general terms, the costs usually are something like 👇🏻&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fua6wvxf8zbn8rncwjdva.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fua6wvxf8zbn8rncwjdva.png" alt="Image description" width="800" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hope you found this post useful and that it might help you next time you’re facing something similar!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
