这个问题不是关于entityframework本身的异步问题,如讨论here。
在方法CalculateSomething
中,您可以看到两个LINQ调用。
第一个LINQ-Call(初始化result
)的性能绝对没问题。
然而,第二个LINQ-Call(初始化resultWithDate
)的性能比第一个慢。
第一个需要2秒,第二个需要15-20秒。
dataBase
是我的DbContext
课程。我使用Entity Framework Core。
private async Task<long> CalculateSomething(string numberOne, MyStatus status)
{
var result = await this.dataBase.Something.CountAsync(item => item.NumberOne== numberOne && item.Status == (short)status);
var resultWithDate = await this.dataBase.Something.CountAsync(item => item.NumberOne== numberOne && item.Status == (short)status && !this.IsOlderThan30Days(item.Date));
return result;
}
private bool IsOlderThan30Days(DateTime? itemDate)
{
bool result = true;
if (itemDate.HasValue)
{
if ((DateTime.Now - itemDate.Value).TotalDays <= 30)
{
result = false;
}
}
return result;
}
问题不在于方法调用IsOlderThan30Days
,问题在于CountAsync
。我知道这是因为我有这样的事情:
private async Task<long> CalculateAmountOfOrders(string numberOne, MyStatus status)
{
var result = this.dataBase.Something.Where(item => item.NumberOne == numberOne && item.Status == (short)status);
var resultWithDate = this.dataBase.Something.Where(item => item.NumberOne == numberOne && item.Status == (short)status && !this.IsOlderThan30Days(item.Date));
var resultCount = await result.CountAsync();
var resultWithDateCount = await resultWithDate.CountAsync();
return resultCount;
}
两次CountAsync()
来电时出现了性能损失。 CountAsync
resultWithDateCount
上的CountAsync
花费了15秒,而resultCount
result
只花了2秒钟。初始化resultWithDate
和select to_char(sysdate,'day') from dual
同样快。
我做错了吗?
谢谢
答案 0 :(得分:3)
试试这个:
var date = DateTime.Now.AddDays(-30);
var result = await this.dataBase.Something.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status);
var resultWithDate = itemDate.HasValue ? await this.dataBase.Orders.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status &&
itemDate.Value < date) : 0;
或者:
var date = DateTime.Now.AddDays(-30);
var result = await this.dataBase.Something.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status);
var resultWithDate = await this.dataBase.Orders.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status &&
itemDate < date);
关键是尝试在LINQ的外进行30天的日期计算。
答案 1 :(得分:1)
好的,这是一段来自@mjwills的代码:
private async Task<long> CalculateSomething(string numberOne, MyStatus status)
{
var date = DateTime.Now.AddDays(-30);
var result = await this.dataBase.Something.CountAsync(item =>
item.NumberOne == numberOne && item.Status == (short)status);
var resultWithDate = await this.dataBase
.Something
.CountAsync(item => item.NumberOne == numberOne && item.Status == (short)status && (!item.Date.HasValue || item.Date.Value <= date));
return result;
}
答案 2 :(得分:1)
问题是IsOlderThan30Days
强制将数据加载到内存中。您应该能够通过在数据库中进行计算来获得一些性能:
var now = DateTime.Now;
var resultWithDate = await this.dataBase
.Something
.CountAsync(item =>
item.NumberOne== numberOne
&& item.Status == (short)status
&& (item.Date != null && EntityFunctions.DiffDays(item.Date, now) <= 30)
);