Я пытаюсь реплицировать результат любого существующего запроса из старого классического ASP-проекта. Запрос довольно прямолинейный.Entity Framework - Distinct и Max генерируют чудовищный (и медленный) запрос
SELECT DISTINCT TOP 10 MAX(H.HistID) as MaxHID, C.CompanyID,C.CompanyName, P.ProsID, P.ProsName, P.Online
FROM HISTORY H, PROSPECTUS P, COMPANY C
WHERE H.ProsID = P.ProsID
and P.CompanyID = C.CompanyID
and H.UserID = 2712
GROUP BY C.CompanyID, C.CompanyName, P.ProsID, P.ProsName, P.Online
ORDER BY MaxHID DESC
Я (по крайней мере, пытался) повторить это с помощью Entity Framework с помощью следующего запроса:
MyContext.HistoryItems.Where(h => h.UserId == userId)
.GroupBy(h => new { h.Prospectus.Family.Id, h.ProsId })
.Select(h => new { Max = h.Max(i => i.Id), Item = h.FirstOrDefault() })
.OrderByDescending(h => h.Max)
.Take(10)
.Select(h => h.Item);
(GroupBy()
предназначен для репликации DISTINCT
поведения от исходного запроса.)
Этот запрос приводит к тем же данным, но для выполнения требуется около 10 секунд. Я посмотрел на запрос, который создал EF, и это монстр.
SELECT TOP (10)
[Project6].[HistId] AS [HistId],
[Project6].[UserID] AS [UserID],
[Project6].[ProsID] AS [ProsID],
[Project6].[HDate] AS [HDate],
[Project6].[ProsDocId] AS [ProsDocId]
FROM (SELECT
[Project5].[HistId] AS [HistId],
[Project5].[UserID] AS [UserID],
[Project5].[ProsID] AS [ProsID],
[Project5].[HDate] AS [HDate],
[Project5].[ProsDocId] AS [ProsDocId],
[Project5].[C1] AS [C1]
FROM (SELECT
[Project4].[HistId] AS [HistId],
[Project4].[UserID] AS [UserID],
[Project4].[ProsID1] AS [ProsID],
[Project4].[HDate] AS [HDate],
[Project4].[ProsDocId] AS [ProsDocId],
(SELECT
MAX([Extent5].[HistId]) AS [A1]
FROM [dbo].[History] AS [Extent5]
INNER JOIN [dbo].[Prospectus] AS [Extent6] ON [Extent5].[ProsID] = [Extent6].[ProsId]
WHERE ([Extent5].[UserID] = @p__linq__0) AND (([Project4].[CompanyId] = [Extent6].[CompanyId]) OR (1 = 0)) AND ([Project4].[ProsID] = [Extent5].[ProsID])) AS [C1]
FROM (SELECT
[Project2].[ProsID] AS [ProsID],
[Project2].[CompanyId] AS [CompanyId],
[Limit1].[HistId] AS [HistId],
[Limit1].[UserID] AS [UserID],
[Limit1].[ProsID] AS [ProsID1],
[Limit1].[HDate] AS [HDate],
[Limit1].[ProsDocId] AS [ProsDocId]
FROM (SELECT
@p__linq__0 AS [p__linq__0],
[Distinct1].[ProsID] AS [ProsID],
[Distinct1].[CompanyId] AS [CompanyId]
FROM (SELECT DISTINCT
[Extent1].[ProsID] AS [ProsID],
[Extent2].[CompanyId] AS [CompanyId]
FROM [dbo].[History] AS [Extent1]
INNER JOIN [dbo].[Prospectus] AS [Extent2] ON [Extent1].[ProsID] = [Extent2].[ProsId]
WHERE [Extent1].[UserID] = @p__linq__0
) AS [Distinct1]) AS [Project2]
OUTER APPLY (SELECT TOP (1)
[Extent3].[HistId] AS [HistId],
[Extent3].[UserID] AS [UserID],
[Extent3].[ProsID] AS [ProsID],
[Extent3].[HDate] AS [HDate],
[Extent3].[ProsDocId] AS [ProsDocId]
FROM [dbo].[History] AS [Extent3]
INNER JOIN [dbo].[Prospectus] AS [Extent4] ON [Extent3].[ProsID] = [Extent4].[ProsId]
WHERE ([Extent3].[UserID] = @p__linq__0) AND (([Project2].[CompanyId] = [Extent4].[CompanyId]) OR (1 = 0)) AND ([Project2].[ProsID] = [Extent3].[ProsID])) AS [Limit1]
) AS [Project4]
) AS [Project5]
) AS [Project6]
ORDER BY [Project6].[C1] DESC
В моем запросе Linq, очевидно, что-то не так, что EF создаст такой беспорядок. Я создал запрос EF как-то неэффективно?
Вашего SQL-запрос неправильно также, вы должны были использовать INNER JOIN и поставить условия в пункт ON вместо того, чтобы все в ИНЕКЕ. – jannagy02
Я знаю, что исходный запрос несколько неэффективен, хотя он не является «неправильным» каким-либо образом. И это утверждение никоим образом не является конструктивным. Я пытаюсь воспроизвести старые функции; говоря, что старый код не прав, ничего не помогает мне. –
Это у вас GroupBy, которая вызывает вашу проблему. Позвольте мне посмотреть, смогу ли я построить более четкую для вас. –