C# tutorials > Frameworks and Libraries > Entity Framework Core (EF Core) > What are split queries and single queries?

What are split queries and single queries?

In Entity Framework Core (EF Core), when dealing with related data, you have options on how to load that data. Two primary approaches are using 'single queries' and 'split queries'. This tutorial explains the differences between them and how they impact performance.

Understanding Single Queries

A single query, by default in EF Core versions before 5.0, fetches all the required data (including related entities) in a single SQL query. This is achieved through the use of JOIN operations in the generated SQL.

Example of a Single Query

In this example, context.Blogs.Include(b => b.Posts).ToList() generates a single SQL query with a JOIN between the Blogs and Posts tables. All blog and post data are retrieved in one go.

using Microsoft.EntityFrameworkCore;

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

public class BloggingContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("YourConnectionStringHere");
    }
}

// Fetching blogs and their posts using a single query (default behavior before EF Core 5.0):
using (var context = new BloggingContext())
{
    var blogs = context.Blogs.Include(b => b.Posts).ToList();
}

Understanding Split Queries

A split query, introduced in EF Core 5.0, fetches related data using multiple SQL queries. Instead of a single query with JOINs, it executes separate queries for the main entity and its related entities.

Enabling Split Queries

You can enable split queries either globally for the entire DbContext or for a specific query using AsSplitQuery().

// Enable split queries globally in OnConfiguring:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer("YourConnectionStringHere").UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
}

// Enable split query for a specific query:
using (var context = new BloggingContext())
{
    var blogs = context.Blogs.Include(b => b.Posts).AsSplitQuery().ToList();
}

Example of a Split Query

When split queries are enabled, the code snippet above generates two separate SQL queries: one to fetch all blogs and another to fetch the posts for those blogs. This avoids the use of JOINs.

using (var context = new BloggingContext())
{
    // Assuming SplitQuery is configured globally or using AsSplitQuery()
    var blogs = context.Blogs.Include(b => b.Posts).ToList();
}

//This would result in 2 queries being executed. One for the Blog and one for the Posts

When to Use Single Queries

Single queries can be more efficient when the dataset is small and the database is optimized for handling complex joins. They are often the default behavior in older EF Core versions.

When to Use Split Queries

Split queries can significantly improve performance when dealing with large datasets or complex relationships where the JOIN operation becomes a bottleneck. They can also be beneficial when dealing with many-to-many relationships or deep object graphs.

Memory Footprint

Single Queries: The entire result set, including related entities, is materialized into memory at once. This can lead to a larger memory footprint if you're dealing with a large number of related entities.
Split Queries: The main entity and related entities are materialized separately. This can lead to a smaller initial memory footprint compared to single queries, as you're not loading everything at once. However, it might require more round trips to the database, potentially impacting overall performance if not optimized.

Pros and Cons

  • Single Queries
    • Pros: Potentially fewer round trips to the database.
    • Cons: Can lead to performance issues with large datasets due to complex joins (Cartesian explosion). Higher memory usage in certain scenarios.
  • Split Queries
    • Pros: Avoids Cartesian explosion, leading to improved performance with large datasets and complex relationships. May reduce memory usage.
    • Cons: More round trips to the database, which can increase latency.

Real-Life Use Case

Consider a scenario where you have a Customer entity with a one-to-many relationship to Order entities. Each customer can have many orders. If you are fetching a list of customers and their orders, and each customer has hundreds of orders, a single query with a JOIN could result in a very large result set (Cartesian explosion). In such a case, using split queries to fetch customers and their orders separately would significantly improve performance.

Best Practices

  • Benchmark: Always benchmark both single queries and split queries in your specific scenario to determine which performs better.
  • Index: Ensure your database tables are properly indexed, especially on foreign key columns, to optimize query performance.
  • Profile: Use database profiling tools to analyze the generated SQL queries and identify potential bottlenecks.
  • Consider the network latency: if network latency is high the overhead of multiple roundtrips might be larger than the cost of the join.

Interview Tip

When asked about query performance in EF Core, mentioning single and split queries demonstrates a good understanding of data loading strategies. Be prepared to discuss their tradeoffs and when each approach is most appropriate. Also, mention the importance of benchmarking to make informed decisions.

FAQ

  • Which query splitting behavior is used by default in EF Core 5.0 and later?

    From EF Core 5.0, the default behavior is that EF Core decides based on the query. Complex queries will automatically use Split Queries.
  • Can I force EF Core to always use single queries, even in EF Core 5.0+?

    Yes, you can configure the DbContext to use single queries globally by setting QuerySplittingBehavior.SingleQuery in the OnConfiguring method, or for a specific query using .AsSingleQuery().
  • How can I tell if EF Core is using a single query or split query?

    You can enable logging in EF Core to see the generated SQL queries. If you see multiple queries being executed for a single Include statement, it's likely using split queries.