<?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: Muhammad Naveed Ashraf</title>
    <description>The latest articles on DEV Community by Muhammad Naveed Ashraf (@naveed).</description>
    <link>https://dev.to/naveed</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%2F704996%2Fd61b2ec3-4e27-4b90-bd45-eb1715182bf7.jpeg</url>
      <title>DEV Community: Muhammad Naveed Ashraf</title>
      <link>https://dev.to/naveed</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/naveed"/>
    <language>en</language>
    <item>
      <title>How to Use Common Table Expressions (CTEs) to Avoid N+1 Queries in Hierarchical Data</title>
      <dc:creator>Muhammad Naveed Ashraf</dc:creator>
      <pubDate>Sat, 14 Sep 2024 09:29:20 +0000</pubDate>
      <link>https://dev.to/naveed/how-to-use-common-table-expressions-ctes-to-avoid-n1-queries-in-hierarchical-data-95k</link>
      <guid>https://dev.to/naveed/how-to-use-common-table-expressions-ctes-to-avoid-n1-queries-in-hierarchical-data-95k</guid>
      <description>&lt;p&gt;As software engineers, we're always striving to optimize our applications for better performance. One common pitfall that can silently degrade performance is the infamous N+1 query problem. In this article, we'll explore how Common Table Expressions (CTEs), including recursive CTEs, can help you avoid N+1 queries, especially when dealing with hierarchical data structures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the N+1 Query Problem
&lt;/h2&gt;

&lt;p&gt;The N+1 query problem occurs when an application executes one query to fetch a list of items (the "1") and then executes an additional query for each item in that list (the "N"). This results in a total of N+1 queries, which can severely impact performance, particularly with large datasets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Scenario: Traversing Hierarchical Data
&lt;/h3&gt;

&lt;p&gt;Consider a file management system where you need to display a folder and all its subfolders. A naive implementation might look like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query 1&lt;/strong&gt;: Fetch the root folder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queries 2 to N+1&lt;/strong&gt;: For each subfolder, fetch its immediate children.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your folder structure is deep and complex, the number of queries can quickly escalate, leading to performance bottlenecks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Common Table Expressions (CTEs)
&lt;/h2&gt;

&lt;p&gt;A Common Table Expression (CTE) is a temporary result set that you can reference within a &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt;, or &lt;code&gt;DELETE&lt;/code&gt; statement. CTEs improve the readability and maintainability of complex queries by breaking them into simpler, more manageable parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recursive CTEs
&lt;/h3&gt;

&lt;p&gt;Recursive CTEs are a special type of CTE that references itself, allowing you to perform recursive operations like traversing hierarchical data structures (e.g., organizational charts, category trees).&lt;/p&gt;

&lt;h2&gt;
  
  
  Solving the N+1 Problem with Recursive CTEs
&lt;/h2&gt;

&lt;p&gt;By using recursive CTEs, you can fetch all the necessary hierarchical data in a single query, thus eliminating the N+1 queries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-by-Step Solution
&lt;/h3&gt;

&lt;p&gt;Let's take the example of folders and subfolders stored in a single table.&lt;/p&gt;

&lt;h4&gt;
  
  
  Table Structure
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;folders&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; (primary key)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;parent_id&lt;/code&gt; (foreign key referencing &lt;code&gt;folders.id&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Goal
&lt;/h4&gt;

&lt;p&gt;Retrieve a folder and all its subfolders (no matter how deep) in a single query.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Define the Recursive CTE
&lt;/h4&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="k"&gt;RECURSIVE&lt;/span&gt; &lt;span class="n"&gt;folder_hierarchy&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;-- Base case: Start with the root folder&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;parent_id&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;folders&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;root_folder_id&lt;/span&gt;

    &lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;

    &lt;span class="c1"&gt;-- Recursive case: Find subfolders of the current level&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;f&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;f&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;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;folders&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
    &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;
        &lt;span class="n"&gt;folder_hierarchy&lt;/span&gt; &lt;span class="n"&gt;fh&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fh&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;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;folder_hierarchy&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;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base Case&lt;/strong&gt;: Select the root folder where &lt;code&gt;id&lt;/code&gt; equals the given &lt;code&gt;:root_folder_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Case&lt;/strong&gt;: Join the &lt;code&gt;folders&lt;/code&gt; table with the &lt;code&gt;folder_hierarchy&lt;/code&gt; CTE on &lt;code&gt;f.parent_id = fh.id&lt;/code&gt; to find all subfolders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final Query&lt;/strong&gt;: Select all folders from &lt;code&gt;folder_hierarchy&lt;/code&gt;, which now includes the root folder and all its subfolders.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  2. Execute the Query
&lt;/h4&gt;

&lt;p&gt;This single query retrieves the entire folder hierarchy, regardless of depth, in one database call.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoiding the N+1 Problem
&lt;/h3&gt;

&lt;p&gt;By using a recursive CTE, we avoid executing a separate query for each folder and its subfolders. This approach significantly reduces the number of queries and improves performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Example: Organizational Chart
&lt;/h2&gt;

&lt;p&gt;Let's consider an employee management system where each employee may manage other employees.&lt;/p&gt;

&lt;h4&gt;
  
  
  Table Structure
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;employees&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt; (primary key)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;manager_id&lt;/code&gt; (foreign key referencing &lt;code&gt;employees.id&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Goal
&lt;/h4&gt;

&lt;p&gt;Retrieve an employee and all their subordinates, at all levels.&lt;/p&gt;

&lt;h4&gt;
  
  
  Recursive CTE Query
&lt;/h4&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="k"&gt;RECURSIVE&lt;/span&gt; &lt;span class="n"&gt;employee_hierarchy&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;-- Base case: Start with the specified employee&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;manager_id&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;employees&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;employee_id&lt;/span&gt;

    &lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;

    &lt;span class="c1"&gt;-- Recursive case: Find employees managed by the current level&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;e&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;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manager_id&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;employees&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
    &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;
        &lt;span class="n"&gt;employee_hierarchy&lt;/span&gt; &lt;span class="n"&gt;eh&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manager_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eh&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;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;employee_hierarchy&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;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base Case&lt;/strong&gt;: Select the employee with the given &lt;code&gt;:employee_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursive Case&lt;/strong&gt;: Join &lt;code&gt;employees&lt;/code&gt; with &lt;code&gt;employee_hierarchy&lt;/code&gt; to find subordinates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final Query&lt;/strong&gt;: Retrieve all employees in the hierarchy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Benefits of Using Recursive CTEs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Improvement&lt;/strong&gt;: Reduces the number of database queries from N+1 to just one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability&lt;/strong&gt;: Makes complex hierarchical queries more understandable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Efficiently handles deep and broad hierarchies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing Recursive CTEs in Application Code
&lt;/h2&gt;

&lt;p&gt;While SQL provides the power of CTEs, you might be using an Object-Relational Mapping (ORM) tool in your application. Here's how you can implement a recursive CTE using SQLAlchemy in Python.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Fetching Nested Categories
&lt;/h3&gt;

&lt;p&gt;Assume you have a &lt;code&gt;Category&lt;/code&gt; model with a self-referential relationship.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;union_all&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;aliased&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_nested_categories&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Define the base case CTE
&lt;/span&gt;    &lt;span class="n"&gt;category_cte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;category_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;cte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;category_hierarchy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recursive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Alias for recursive reference
&lt;/span&gt;    &lt;span class="n"&gt;parent_alias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;aliased&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category_cte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Define the recursive part
&lt;/span&gt;    &lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;parent_alias&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Combine base and recursive queries
&lt;/span&gt;    &lt;span class="n"&gt;category_cte&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;category_cte&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;union_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Final query
&lt;/span&gt;    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;category_cte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scalars&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;all&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;Note&lt;/strong&gt;: Adjust the code according to your ORM and database configurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Application: E-commerce Categories
&lt;/h2&gt;

&lt;p&gt;In e-commerce platforms, products are often organized into categories and subcategories. Using recursive CTEs, you can retrieve all products under a specific category, including those in nested subcategories, with a single query.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Query
&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="k"&gt;RECURSIVE&lt;/span&gt; &lt;span class="n"&gt;category_hierarchy&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;-- Base case: Start with the selected category&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;parent_id&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;categories&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;category_id&lt;/span&gt;

    &lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt;

    &lt;span class="c1"&gt;-- Recursive case: Find subcategories&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="k"&gt;c&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;c&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="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;categories&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
    &lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;
        &lt;span class="n"&gt;category_hierarchy&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ch&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;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;p&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;products&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;
    &lt;span class="n"&gt;category_hierarchy&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="k"&gt;ON&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;category_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ch&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;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CTE (&lt;code&gt;category_hierarchy&lt;/code&gt;)&lt;/strong&gt;: Builds a hierarchy of categories starting from the selected category.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final Query&lt;/strong&gt;: Retrieves all products belonging to any category in the hierarchy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Considerations and Best Practices
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database Support&lt;/strong&gt;: Ensure your database supports recursive CTEs (e.g., PostgreSQL, SQL Server, MySQL 8.0+).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: While recursive CTEs reduce the number of queries, they can be resource-intensive for very deep hierarchies. Use with caution and test performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexing&lt;/strong&gt;: Proper indexing on key columns (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;parent_id&lt;/code&gt;) can significantly improve query performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit Depth&lt;/strong&gt;: If appropriate, limit the recursion depth to prevent potential infinite loops due to data anomalies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The N+1 query problem is a common issue that can hinder the performance of your applications. By leveraging recursive Common Table Expressions (CTEs), you can optimize your database queries to fetch all necessary hierarchical data in a single operation. This approach not only improves performance but also enhances code readability and maintainability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Takeaways:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recursive CTEs are powerful tools for handling hierarchical data.&lt;/li&gt;
&lt;li&gt;They help avoid the N+1 query problem by consolidating multiple queries into one.&lt;/li&gt;
&lt;li&gt;Be mindful of the potential performance impact with large datasets.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Have you encountered the N+1 query problem in your projects? How did you solve it? Share your experiences or ask questions in the comments below! Happy coding!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>performance</category>
      <category>postgres</category>
      <category>sql</category>
      <category>database</category>
    </item>
  </channel>
</rss>
