升级到Asp.Net Core 2015.1后,我注意到很多EF查询的运行速度都慢了很多。
我做了一些调查,发现很多查询过滤器现在都在Code中进行评估,而不是将过滤器作为where子句的一部分传递给SQL来运行查询。
我们最终不得不重新编写一些查询作为存储过程来恢复性能。请注意,这些在2015.1发布之前一直很有效。显然有些东西被改变了,很多查询正在选择表上的所有查询,然后在代码中过滤数据。这种方法对于性能来说很糟糕,例如读一个有很多行的表,过滤所有东西,但可能是2行。
我必须问一下有什么变化,以及其他人是否也看到同样的事情了?
例如:我有一个ForeignExchange
表以及ForeignExchangeRate
表格,这些表格通过ForeignExchangeid = ForeignExchangeRate.ForeignExchangeId
链接
await _context.ForeignExchanges
.Include(x => x.ForeignExchangeRates)
.Select(x => new ForeignExchangeViewModel
{
Id = x.Id,
Code = x.Code,
Name = x.Name,
Symbol = x.Symbol,
CountryId = x.CountryId,
CurrentExchangeRate = x.ForeignExchangeRates
.FirstOrDefault(y => (DateTime.Today >= y.ValidFrom)
&& (y.ValidTo == null || y.ValidTo >= DateTime.Today)).ExchangeRate.ToFxRate(),
HistoricalExchangeRates = x.ForeignExchangeRates
.OrderByDescending(y => y.ValidFrom)
.Select(y => new FxRate
{
ValidFrom = y.ValidFrom,
ValidTo = y.ValidTo,
ExchangeRate = y.ExchangeRate.ToFxRate(),
}).ToList()
})
.FirstOrDefaultAsync(x => x.Id == id);
我用它来获取用于编辑外汇汇率的数据
因此生成的SQL不是预期的。它生成以下2个SQL语句来获取数据
SELECT TOP(1) [x].[ForeignExchangeId], [x].[ForeignCurrencyCode], [x].[CurrencyName], [x].[CurrencySymbol], [x].[CountryId], (
SELECT TOP(1) [y].[ExchangeRate]
FROM [ForeignExchangeRate] AS [y]
WHERE ((@__Today_0 >= [y].[ValidFrom]) AND ([y].[ValidTo] IS NULL OR ([y]. [ValidTo] >= @__Today_1))) AND ([x].[ForeignExchangeId] = [y].[ForeignExchangeId])
)FROM [ForeignExchange] AS [x]
WHERE [x].[ForeignExchangeId] = @__id_2
和
SELECT [y0].[ForeignExchangeId], [y0].[ValidFrom], [y0].[ValidTo], [y0].[ExchangeRate]
FROM [ForeignExchangeRate] AS [y0]
ORDER BY [y0].[ValidFrom] DESC
第二个查询导致缓慢。如果表有很多行,那么它基本上获取整个表并过滤代码中的数据
这在最新版本中有所改变,因为它曾用于RC版本的EF
我曾经遇到过的另一个问题是以下
return await _context.CatchPlans
.Where(x => x.FishReceiverId == fishReceiverId
&& x.FisherId == fisherId
&& x.StockId == stockId
&& x.SeasonStartDate == seasonStartDate
&& x.EffectiveDate >= asAtDate
&& x.BudgetType < BudgetType.NonQuotaed)
.OrderBy(x => x.Priority)
.ThenBy(x => x.BudgetType)
.ToListAsync();
并且此查询最终执行了表读取(整个表中包含数万行)以获取2到10条记录之间的过滤器子集。非常低效。这是我必须用存储过程替换的一个查询。从大约1.5-3.0秒减少到毫秒。请注意,这在升级之前用于高效运行
答案 0 :(得分:6)
这是EF core 1.0
上的一个已知问题。现在的解决方案是将所有关键查询转换为sync
一个。问题出现在Async
查询中。在EF core 1.1.0
版本上解决了这个问题。但它尚未发布。
以下是EF核心开发团队成员完成的测试:
您可以在此处找到更多信息:EF Core 1.0 RC2: async queries so much slower than sync
我想做的另一个建议。那就是使用.AsNoTracking()
尝试您的查询。这也会提高查询效果。
有时您可能希望从查询中获取实体但不具备 这些实体由上下文跟踪。这可能会带来更好的结果 以只读方式查询大量实体时的性能 场景。