Query on owned entity produces overly complicated SQL
See original GitHub issueWhen querying an entity and filtering on an owned entity the SQL query that is produced includes a LEFT JOIN
that could be avoided.
Steps to reproduce
Entites:
class Order
{
public int Id { get; set; }
public string Title { get; set; }
public Address Address { get; set; }
}
class Address
{
public string Street { get; set; }
public string City { get; set; }
}
Model configuration:
modelBuilder.Entity<Order>().OwnsOne(x => x.Address);
The database table that is created looks like this:
A simple query like:
context.Orders.Where(x => x.Address == null).ToList();
Produces this SQL:
SELECT o."Id", o."Title", t."Id", t."Address_City", t."Address_Street"
FROM "Orders" AS o
LEFT JOIN (
SELECT o0."Id", o0."Address_City", o0."Address_Street", o1."Id" AS "Id0"
FROM "Orders" AS o0
INNER JOIN "Orders" AS o1 ON o0."Id" = o1."Id"
WHERE (o0."Address_Street" IS NOT NULL) OR (o0."Address_City" IS NOT NULL)
) AS t ON o."Id" = t."Id"
WHERE (t."Id" IS NULL)
Which is overly complicated. The columns Address_City
and Address_Street
are available on the Orders
table without any JOIN.
Same thing when querying a specific owned entity property:
context.Orders.Where(x => x.Address.City == "Rome").ToList();
SELECT o."Id", o."Title", t."Id", t."Address_City", t."Address_Street"
FROM "Orders" AS o
LEFT JOIN (
SELECT o0."Id", o0."Address_City", o0."Address_Street", o1."Id" AS "Id0"
FROM "Orders" AS o0
INNER JOIN "Orders" AS o1 ON o0."Id" = o1."Id"
WHERE (o0."Address_Street" IS NOT NULL) OR (o0."Address_City" IS NOT NULL)
) AS t ON o."Id" = t."Id"
WHERE (t."Address_City" = 'Rome') AND (t."Address_City" IS NOT NULL)
Further technical details
Example project (PostgreSQL): EfCoreOwnedEntity.zip
EF Core version: 3.0.0 Database provider: Npgsql.EntityFrameworkCore.PostgreSQL 3.0.1 Target framework: .NET Core 3.0 Operating system: Windows 10 1903 IDE: e.g. Visual Studio 2019 16.3.2
Issue Analytics
- State:
- Created 4 years ago
- Reactions:64
- Comments:92 (29 by maintainers)
Top Results From Across the Web
Why does the Entity Framework generate nested SQL ...
The simple answer is because Entity Framework breaks your query expression down into an expression tree and then uses that expression tree to ......
Read more >Efficient Querying - EF Core
Performance guide for efficient querying using Entity Framework Core.
Read more >Entity Framework: Common performance mistakes
In this post, I'll go over some common mistakes when working with Entity Framework with Microsoft SQL Server (although some of the examples ......
Read more >Entity Framework Core 5 - Pitfalls To Avoid and Ideas to Try
In this post, we'll look at some pitfalls and ideas EF Core users like yourself may want to consider when developing an application....
Read more >Why use direct sql over entity framework? : r/dotnet
I just started a new job with web api and angular and the first thing I realized is this team is using direct...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I think this should be marked as a type-bug instead of a type-enhancement. In fact, as more rows are added to a table, performance progressively degrades to the point it becomes unusable. Users could not be fully aware of this problem; maybe Microsoft should issue an official statement to discourage using owned types in EFCore 3.0.
My model is identical to @matteocontrini’s except for the fact it has 2 owned type properties in my entity class instead of just 1. Here’s the query generated by EFCore. It’s way too complicated: there are LEFT JOINs of subqueries with nested INNER JOINs.
And here’s a quick benchmark I performed. The blue line represents a SQL query I typed by hand and the orange line is the query generated by the LINQ provider. As you can see, performance starts degrading very fast as more rows are added to the table. I’m talking about just 2000 rows in a Sqlite database. All needed indexes are in place.
@smitpatel Not if you are not using owned entities with table splitting.
For example we are using owned entity for audit-related information
We put this entity on many multiple entities (e.g. manufacturers, products, product translations etc), therefore our EF Core-generated queries are monstrous.
This simple expression
results in
this is ridiculous, since we use owned entities without table splitting, therefore we don’t need to left join table to themselves