2015-12-20 3 views
2

Entity Framework формирует очень неэффективный SQL для следующего запроса LINQ:Linq делает очень неэффективного Entity Framework запрос

var query = _context.Sessions 
        .Where(s => s.OrganizationId == orgId && s.Device != null && s.Device.User != null) 
        .Select(s => s.Device.User) 
        .Distinct(); 

Формирует этот 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 

SQL, я на самом деле хочу выполнить является следующим, который работает молниеносно:

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 

Как я могу получить Entity Framework-gen связанный с этим SQL, как можно ближе к этому запросу?

+0

Кажется, что вам нужно '.select (s => s.Device.User.Email)' –

+1

Это не эквивалентные запросы, так что это не удивительно, почему они будут выполнять иначе. –

+0

Как выполняется последний (отредактированный) SQL-запрос? –

ответ

3

Попробуйте начать с таблицей пользователей:

var query = (
    from u in _context.Users 
    where u.Devices.Any(d => d.Sessions 
     .Any(s => s.OrganisationId == orgId) 
    ) 
    select u 
); 

Он не будет делать запрос, заданный, но то, что он делает возвращение может иметь такую ​​же хорошую производительность.

+0

Я тоже думал. По моему опыту это может быть даже лучше, чем исходный sql-запрос. +1 –

+0

Это значительно улучшило производительность запроса. Отличное решение. – drewob

4

Почему вы хотите выбрать целое лицо User, если вы просто хотите его отправить по электронной почте?

Попробуйте это:

var query = _context.Sessions 
        .Where(s => s.OrganizationId == orgId && s.Device != null && s.Device.User != null) 
        .Select(s => s.Device.User.Email) 
        .Distinct(); 
+0

Я исправил свой вопрос, чтобы отразить, что я ищу различные пользовательские записи, а не только отдельный User.Email. – drewob

+0

Чем отличается пользователь? Все поля объединены? Или просто какое-то значение первичного ключа? –

+0

Мой первоначальный вопрос был плохим и не задал правильного вопроса. Я исправил это. – drewob

0

Вы можете сделать это довольно просто:

_context.Sessions 
    .Where(s => s.OrganizationId == 2) 
    .Select(s => s.Device.User) 
    .Distinct(); 

Вам не нужно проверять null, как он будет выполнять INNER JOIN для вас.

0

Мне не нравится использовать DISTINCT, если запрос содержит его, тогда запрос неверен.

Другой способ сделать это

var query = _context.Sessions.Include("Device.User.Email") 
        .Where(s => s.OrganizationId == orgId); 
Смежные вопросы