When you eagerly load related data in Entity Framework Core (EF Core) using Include and ThenInclude, the framework can either generate a single large SQL query with multiple JOIN operations or execute several smaller queries (known as split queries). Selecting the appropriate strategy is essential, as an incorrect choice may lead to excessive row counts, high memory consumption, or additional network round trips. This article describes the concept of split queries, their purpose, safe usage practices, and scenarios where they outperform single-query approaches—along with practical patterns for production environments.

The problem: JOINs, duplication, and the "Cartesian explosion"

When using relational databases, Entity Framework gets related data by combining tables with JOINs in single query. The JOIN operations are a standard feature in SQL; however, improper or inefficient implementation can result in considerable performance overhead.This approach works until the query involves multiple collection navigations at the same level, at which point the result set can grow dramatically.

Consider the following example: the Customer table has relationships with Order and Address at the same level. Loading both Order and Address for each Blog results in a Cartesian product of orders and addresses per customer. For instance, if a customer contains 10 orders and 10 addresses, the query will return 100 rows for that single customer. This is the classic Cartesian explosion.

table relation

Even with a single collection include, JOIN operations replicate the principal entity’s columns for each child row. This can become costly when the principal contains large columns, such as images or lengthy text. Entity Framework Core recommends using projections to avoid retrieving unnecessary large columns.

var query = context.Customer
            .Include(o=>o.Orders)
            .Include(a=>a.Addresses)
            .Where(r=>r.Id==1);

Generated SQL

with single query

What are split queries?

Split queries instruct EF Core to divide a single LINQ query with Include statements into multiple SQL commands, typically one for each included collection. EF Core then assembles the results into the entity graph in memory, preventing the large, duplicated row sets that broad JOIN operations often produce.

Consider above mention example:

var query = context.Customer
            .Include(o=>o.Orders)
            .Include(a=>a.Addresses)
            .AsSplitQuery()
            .Where(r=>r.Id==1);

Generated SQL

with slipt query1

When to Use Split Queries

Enabling split queries globally (at the Context level)

You can also set split queries as the default behavior for your application's DbContext

  
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(
            connectionString,
            o => o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery));
}
  

When split queries are set as the default, you can still configure individual queries to execute as single queries.

Use caution when applying split queries in the following scenarios

Conclusion

Split queries are a powerful, pragmatic tool in EF Core. They help reduce data duplication and mitigate JOIN-related performance issues when eagerly loading complex object graphs—though they introduce additional round trips and potential consistency concerns. The best approach depends on context: benchmark both strategies with production-like data, prefer projections for paging, and ensure stable ordering whenever you combine split queries with pagination.

Use Split Queries When:

Use Single Queries When: