<?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: Maithreyan</title>
    <description>The latest articles on DEV Community by Maithreyan (@maithreyan11).</description>
    <link>https://dev.to/maithreyan11</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F527949%2F527ae63c-412d-4463-8c47-e15a7547d511.jpeg</url>
      <title>DEV Community: Maithreyan</title>
      <link>https://dev.to/maithreyan11</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maithreyan11"/>
    <language>en</language>
    <item>
      <title>Why CTE vs Subquery Matters More on Redshift Than Anywhere Else</title>
      <dc:creator>Maithreyan</dc:creator>
      <pubDate>Mon, 03 Aug 2026 12:00:00 +0000</pubDate>
      <link>https://dev.to/maithreyan11/why-cte-vs-subquery-matters-more-on-redshift-than-anywhere-else-llm</link>
      <guid>https://dev.to/maithreyan11/why-cte-vs-subquery-matters-more-on-redshift-than-anywhere-else-llm</guid>
      <description>&lt;p&gt;On Snowflake or modern Postgres, CTE vs subquery barely matters for performance. On Redshift, it can matter a lot — and I learned this the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  The assumption I carried over
&lt;/h2&gt;

&lt;p&gt;I carried an assumption over from Snowflake: that the optimizer would treat a CTE and an equivalent subquery the same way. Redshift doesn't play by those rules. Redshift's query planner is derived from an older Postgres lineage, and it historically doesn't inline CTEs the way newer engines do — it can materialize them as a separate step before the outer query even runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters on an MPP engine
&lt;/h2&gt;

&lt;p&gt;This matters a lot on Redshift specifically because it's a columnar, MPP (massively parallel processing) engine. Materializing a CTE means writing an intermediate result set across the cluster's compute nodes before the next step even starts. On a small CTE, that's harmless. On a CTE scanning millions of rows from a big fact table, that's a real cost — extra I/O and redistribution across nodes that a well-written subquery or a join might avoid entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually happened
&lt;/h2&gt;

&lt;p&gt;I hit this on a Redshift ETL query pulling from a large events table. I had it as a CTE, referenced once in the outer query, nothing complex. When I flattened it into a subquery instead, the query planner pushed filters down earlier and pruned way more data before the expensive join — noticeably faster on that specific table.&lt;/p&gt;

&lt;h2&gt;
  
  
  My rule of thumb for Redshift now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use a subquery when it's referenced once and simple — let the planner push predicates down early&lt;/li&gt;
&lt;li&gt;Use a CTE mainly for readability on complex multi-step logic, but check &lt;code&gt;EXPLAIN&lt;/code&gt; before trusting it won't materialize unnecessarily&lt;/li&gt;
&lt;li&gt;Always check the query plan (&lt;code&gt;EXPLAIN&lt;/code&gt;) rather than assuming CTE behavior — Redshift doesn't guarantee the same optimizations as Snowflake or Postgres 12+&lt;/li&gt;
&lt;li&gt;For genuinely reused logic, a temp table often beats both if the CTE is being scanned multiple times&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Patterns that are "safe defaults" on one warehouse can be real performance traps on another. Always validate with &lt;code&gt;EXPLAIN&lt;/code&gt; before assuming.&lt;/p&gt;

&lt;p&gt;Anyone else been burned by carrying optimizer assumptions across warehouses?&lt;/p&gt;

</description>
      <category>redshift</category>
      <category>sql</category>
      <category>dataengineering</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
