C# 如何改进此LINQ的性能?
更新 多亏了@usr,我只需改变一下,就可以把时间缩短到~3秒C# 如何改进此LINQ的性能?,c#,sql-server,linq,C#,Sql Server,Linq,更新 多亏了@usr,我只需改变一下,就可以把时间缩短到~3秒 .Select( log => log.OrderByDescending( d => d.DateTimeUTC ).FirstOrDefault() ) 到 我有一个包含两个表的数据库——日志和收集器——我正在使用实体框架来读取它们。共有86条收集器记录,每条记录有50000+条对应的日志记录 我想为每个收集器获取最新的日志记录,这很容易用这个SQL完成 SELECT Collecto
.Select(
log => log.OrderByDescending(
d => d.DateTimeUTC
).FirstOrDefault()
)
到
我有一个包含两个表的数据库——日志和收集器——我正在使用实体框架来读取它们。共有86条收集器记录,每条记录有50000+条对应的日志记录
我想为每个收集器获取最新的日志记录,这很容易用这个SQL完成
SELECT CollectorLogModels_1.Status, CollectorLogModels_1.NumericValue,
CollectorLogModels_1.StringValue, CollectorLogModels_1.DateTimeUTC,
CollectorSettingsModels.Target, CollectorSettingsModels.TypeName
FROM
(SELECT CollectorId, MAX(Id) AS Id
FROM CollectorLogModels GROUP BY CollectorId) AS RecentLogs
INNER JOIN CollectorLogModels AS CollectorLogModels_1
ON RecentLogs.Id = CollectorLogModels_1.Id
INNER JOIN CollectorSettingsModels
ON CollectorLogModels_1.CollectorId = CollectorSettingsModels.Id
执行此操作需要约2秒的时间
我能与LINQ取得的最接近的结果如下
var logs = context.Logs.Include(co => co.Collector)
.GroupBy(
log => log.CollectorId, log => log
)
.Select(
log => log.OrderByDescending(
d => d.DateTimeUtc
).FirstOrDefault()
)
.Join(
context.Collectors,
(l => l.CollectorId),
(c => c.Id),
(l, c) => new
{
c.Target,
DateTimeUTC = l.DateTimeUtc,
l.Status,
l.StringValue,
CollectorName = c.TypeName
}
).OrderBy(
o => o.Target
).ThenBy(
o => o.CollectorName
)
;
这会产生我想要的结果,但执行需要约35秒
这将成为以下SQL语句
SELECT
[Distinct1].[CollectorId] AS [CollectorId],
[Extent3].[Target] AS [Target],
[Limit1].[DateTimeUtc] AS [DateTimeUtc],
[Limit1].[Status] AS [Status],
[Limit1].[StringValue] AS [StringValue],
[Extent3].[TypeName] AS [TypeName]
FROM (SELECT DISTINCT
[Extent1].[CollectorId] AS [CollectorId]
FROM [dbo].[CollectorLogModels] AS [Extent1] ) AS [Distinct1]
OUTER APPLY (SELECT TOP (1) [Project2].[Status] AS [Status], [Project2].[StringValue] AS [StringValue], [Project2].[DateTimeUtc] AS [DateTimeUtc], [Project2].[CollectorId] AS [CollectorId]
FROM ( SELECT
[Extent2].[Status] AS [Status],
[Extent2].[StringValue] AS [StringValue],
[Extent2].[DateTimeUtc] AS [DateTimeUtc],
[Extent2].[CollectorId] AS [CollectorId]
FROM [dbo].[CollectorLogModels] AS [Extent2]
WHERE [Distinct1].[CollectorId] = [Extent2].[CollectorId]
) AS [Project2]
ORDER BY [Project2].[DateTimeUtc] DESC ) AS [Limit1]
INNER JOIN [dbo].[CollectorSettingsModels] AS [Extent3] ON [Limit1].[CollectorId] = [Extent3].[Id]
ORDER BY [Extent3].[Target] ASC, [Extent3].[TypeName] ASC
如何使性能更接近仅使用SQL即可实现的性能?在原始SQL中,您可以从不同于MAX(ID)的行中选择集合DateTimeUTC。那可能是个错误。EF没有这个问题。它在语义上不完全相同,这是一个更难的查询 如果将EF查询重写为与SQL查询在结构上相同,则将获得相同的性能。我在这里没有看到EF不支持的内容
用EF计算
max(id)
,并加入其中。我遇到了完全相同的问题,我通过添加索引解决了这个问题
我的一个查询需要45秒才能完成,我设法在不到一秒钟的时间内完成。这只是一个想法,但也许你在ti有一个收获:如果你真的想获得最佳性能,你可以编写一个存储过程并通过EF处理它。描述工作原理:-1如果您接受了答案,则应创建一个新问题,而不是编辑您的问题。这使得usr的答案看起来是错误的。这是有道理的,因为DateTimeUTC不由Id isThanks索引,这是一个很大的帮助。我已经用结果更新了问题,现在缩短到~3秒!
SELECT
[Distinct1].[CollectorId] AS [CollectorId],
[Extent3].[Target] AS [Target],
[Limit1].[DateTimeUtc] AS [DateTimeUtc],
[Limit1].[Status] AS [Status],
[Limit1].[StringValue] AS [StringValue],
[Extent3].[TypeName] AS [TypeName]
FROM (SELECT DISTINCT
[Extent1].[CollectorId] AS [CollectorId]
FROM [dbo].[CollectorLogModels] AS [Extent1] ) AS [Distinct1]
OUTER APPLY (SELECT TOP (1) [Project2].[Status] AS [Status], [Project2].[StringValue] AS [StringValue], [Project2].[DateTimeUtc] AS [DateTimeUtc], [Project2].[CollectorId] AS [CollectorId]
FROM ( SELECT
[Extent2].[Status] AS [Status],
[Extent2].[StringValue] AS [StringValue],
[Extent2].[DateTimeUtc] AS [DateTimeUtc],
[Extent2].[CollectorId] AS [CollectorId]
FROM [dbo].[CollectorLogModels] AS [Extent2]
WHERE [Distinct1].[CollectorId] = [Extent2].[CollectorId]
) AS [Project2]
ORDER BY [Project2].[DateTimeUtc] DESC ) AS [Limit1]
INNER JOIN [dbo].[CollectorSettingsModels] AS [Extent3] ON [Limit1].[CollectorId] = [Extent3].[Id]
ORDER BY [Extent3].[Target] ASC, [Extent3].[TypeName] ASC