升级到 Asp.Net Core 2015.1 后,我注意到很多 EF 查询的运行速度变得慢了很多。
我做了一些调查,发现许多带有 where 过滤器的查询现在在代码中进行评估,而不是将过滤器作为 where 子句的一部分传递给 SQL 来与查询一起运行。
我们最终不得不将许多查询重写为存储过程以恢复性能。请注意,这些在 2015.1 版本之前曾经是高效的。显然有些事情发生了变化,许多查询正在选择表上的所有查询,然后在代码中过滤数据。这种方法对性能来说很糟糕,例如读取一个有很多行的表,过滤除两行之外的所有内容。
我必须问发生了什么变化,以及是否其他人也看到了同样的事情?
例如:我有一个 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
第二个查询是导致速度缓慢的查询。如果表有很多行,那么它本质上是获取整个表并在代码中过滤数据
这在最新版本中发生了变化,因为这曾经在 EF 的 RC 版本中工作
我曾经遇到过的另一个查询如下
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 秒减少到毫秒。并注意这用于在升级之前高效运行
最佳答案
这是 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()
进行查询。这也将提高查询性能。
Sometimes you may want to get entities back from a query but not have those entities be tracked by the context. This may result in better performance when querying for large numbers of entities in read-only scenarios.
关于sql - 有没有人注意到 EF Core 1.0 2015.1 使查询效率非常低,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39158596/