Reputation: 507
Entity Framework generates very poorly performing SQL for the following LINQ query:
var query = _context.Sessions
.Where(s => s.OrganizationId == orgId && s.Device != null && s.Device.User != null)
.Select(s => s.Device.User)
.Distinct();
Generates this SQL:
exec sp_executesql N'SELECT
[Distinct1].[Id] AS [Id],
[Distinct1].[Email] AS [Email],
[Distinct1].[Sex] AS [Sex],
[Distinct1].[Age] AS [Age]
FROM ( SELECT DISTINCT
[Extent4].[Id] AS [Id],
[Extent4].[Email] AS [Email],
[Extent4].[Sex] AS [Sex],
[Extent4].[Age] AS [Age]
FROM (SELECT [Extent1].[OrganizationId] AS [OrganizationId], [Extent3].[UserId] AS [UserId1]
FROM [dbo].[Sessions] AS [Extent1]
INNER JOIN [dbo].[Devices] AS [Extent2] ON [Extent1].[DeviceId] = [Extent2].[Id]
LEFT OUTER JOIN [dbo].[Devices] AS [Extent3] ON [Extent1].[DeviceId] = [Extent3].[Id]
WHERE [Extent2].[UserId] IS NOT NULL ) AS [Filter1]
LEFT OUTER JOIN [dbo].[Users] AS [Extent4] ON [Filter1].[UserId1] = [Extent4].[Id]
WHERE [Filter1].[OrganizationId] = @p__linq__0
) AS [Distinct1]',N'@p__linq__0 int',@p__linq__0=2
The SQL I'm actually looking to execute is the following, which runs lightning fast:
select distinct u.*
from Sessions s
inner join Devices d on s.DeviceId = d.Id
inner join Users u on d.UserId = u.Id
where OrganizationId = 2
How can I get the Entity Framework-generated SQL to be as close to this query as possible?
Upvotes: 2
Views: 552
Reputation: 155
I dont like use the DISTINCT , if a query contains it then the query's wrong.
Other way to do it
var query = _context.Sessions.Include("Device.User.Email")
.Where(s => s.OrganizationId == orgId);
Upvotes: 0
Reputation: 27357
You can do it pretty simply:
_context.Sessions
.Where(s => s.OrganizationId == 2)
.Select(s => s.Device.User)
.Distinct();
You do not need to check for null
, as it will perform an INNER JOIN
for you.
Upvotes: 0
Reputation: 2713
Try starting with the users table:
var query = (
from u in _context.Users
where u.Devices.Any(d => d.Sessions
.Any(s => s.OrganisationId == orgId)
)
select u
);
It won't do the query you specified but what it does return might have the same good performance.
Upvotes: 3
Reputation: 27861
Why select the whole User
entity if you just want the email?
Try this:
var query = _context.Sessions
.Where(s => s.OrganizationId == orgId && s.Device != null && s.Device.User != null)
.Select(s => s.Device.User.Email)
.Distinct();
Upvotes: 4