后台数据处理超时,行列转换差不多2分多钟

yuyi1991616 2019-12-04 05:10:29


public List<KPISupplierReportShow> GetKPIReport
(bool? purchaseStatus,List<string> facs, List<string> status, List<string> types, string searchKey, string startDate, string endDate)
{
using (SRMDatabaseEntities entity = new SRMDatabaseEntities())
{
DateTime start = string.IsNullOrEmpty(startDate) ? DateTime.MinValue : Convert.ToDateTime(startDate);
DateTime end = string.IsNullOrEmpty(endDate) ? DateTime.MaxValue : Convert.ToDateTime(endDate);

var model = from p in entity.KPISupplierReport
join q in entity.SupplierInfoReport on p.SupplierCode equals q.SupplierCode
join j in entity.SystemUser on p.CreatedUser.ToUpper() equals j.UserId.ToUpper() into temp
from k in temp.DefaultIfEmpty()
where
(
status.Contains(p.Status)
&& facs.Contains(p.FactoryCode)
&& types.Contains(p.ReportCycle)
&& (purchaseStatus == null || q.PurchaseStatus == purchaseStatus)
&& (p.CreatedDate > start && p.CreatedDate < end)
&&
(string.IsNullOrEmpty(searchKey)
|| p.SupplierCode.Contains(searchKey)
|| p.SupplierName.Contains(searchKey)
|| p.ReportNumber.Contains(searchKey)
|| k.UserName.Contains(searchKey)
|| p.CreatedUser.Contains(searchKey)
|| p.ReportName.Contains(searchKey)
)
)
orderby p.Id descending
select new
{
q.PurchaseStatus,
p.Id,
p.ApprovalStatus,
p.CreatedDate,
k.UserName,
p.FactoryCode,
p.FactoryName,
p.FeedbackDate,
p.KPIMonthEnd,
p.KPIMonthStart,
p.KPIYear,
p.MaterielCode,
p.ReportCycle,
p.ReportName,
p.ReportNumber,
p.Score,
p.SendDate,
p.Status,
p.SupplierCode,
p.SupplierName
};

var modelList = model.ToList();
var numberList = modelList.Select(i => i.ReportNumber).ToList();
var itemList = entity.KPISupplierItem.Where(i => numberList.Contains(i.ReportNumber)).ToList();
//上面部分取数都是很快的,就是下面这部分要进行行列转换,
//把明细里对应的列写到头的行里,测试用10000条记录,这个foreach大概要2分多钟,
//除了修改超时时间限制,还有别的办法么?
List<KPISupplierReportShow> reportList = new List<KPISupplierReportShow>();
KPISupplierReportShow rshow;
List<KPISupplierItem> tempItemList;
KPISupplierItem tempItem;
foreach (var kpi in modelList)
{
rshow = new KPISupplierReportShow()
{
PurchaseStatus=kpi.PurchaseStatus? "激活":"暂停",
ApprovalStatus = EnumHelper.GetEnumDescription<WorkflowStatus>(EnumHelper.GetEnum<WorkflowStatus>(kpi.ApprovalStatus)),
CreatedDate = kpi.CreatedDate.ToString("yyyy-MM-dd"),
CreatedUser = kpi.UserName,
FactoryCode = kpi.FactoryCode,
FactoryName = kpi.FactoryName,
FeedbackDate = kpi.FeedbackDate,
Id = kpi.Id,
KPIMonthEnd = kpi.KPIMonthEnd,
KPIMonthStart = kpi.KPIMonthStart,
KPIYear = kpi.KPIYear,
MaterielCode = kpi.MaterielCode,
ReportCycle = kpi.ReportCycle,
ReportName = kpi.ReportName,
ReportNumber = kpi.ReportNumber,
Score = kpi.Score,
SendDate = kpi.SendDate,
Status = EnumHelper.GetEnumDescription<ExaminationStatus>(EnumHelper.GetEnum<ExaminationStatus>(kpi.Status)),
SupplierCode = kpi.SupplierCode,
SupplierName = kpi.SupplierName
};

tempItemList = itemList.Where(t => t.ReportNumber == kpi.ReportNumber).ToList();
//品质
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key1));
if (tempItem != null)
{
rshow.Penalty1 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark1 = tempItem.Reason;
}
//交付
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key2));
if (tempItem != null)
{
rshow.Penalty2 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark2 = tempItem.Reason;
}
//服务
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key3));
if (tempItem != null)
{
rshow.Penalty3 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark3 = tempItem.Reason;
}
//附加运费
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key4));
if (tempItem != null)
{
rshow.Penalty4 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark4 = tempItem.Reason;
}
//体系
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key5));
if (tempItem != null)
{
rshow.Penalty5 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark5 = tempItem.Reason;
}
//成本
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key6));
if (tempItem != null)
{
rshow.Penalty6 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark6 = tempItem.Reason;
}
//技术
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key7));
if (tempItem != null)
{
rshow.Penalty7 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark7 = tempItem.Reason;
}

//----add by chenyuyi on 2018-09-10 begin----
//加分项
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key8));
if (tempItem != null)
{
rshow.Penalty8 = 0 - (tempItem.TargetScore - (tempItem.Score.HasValue ? tempItem.Score.Value : 0));
rshow.PenaltyRemark8 = tempItem.Reason;
}
//风险
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key9));
if (tempItem != null)
{
rshow.PenaltyRemark9 = tempItem.Reason;
}
//红线
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key10));
if (tempItem != null)
{
rshow.PenaltyRemark10 = tempItem.Reason;
}
//----add by chenyuyi on 2018-09-10 end----

reportList.Add(rshow);
}

return reportList;
}
}
...全文
145 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
andy_wanhl 2019-12-06
  • 打赏
  • 举报
回复
它这个是全部数据导入到Excel慢
正怒月神 2019-12-06
  • 打赏
  • 举报
回复
引用 8 楼 yuyi1991616 的回复:
[quote=引用 2 楼 正怒月神 的回复:] 而且,必定要1W条数据显示出去吗?
显示没问题,我做了分页,至对查询页数据进行处理。 这是导出到Excel报表用的。 另外,ReportNumber是主表的主键,明细表的外键[/quote] 你既然做了分页,那为何还要一下子拿这么多出来? 根据currentPage和pageSize。分批拿取就没加载慢的问题了。
andy_wanhl 2019-12-06
  • 打赏
  • 举报
回复
小范围的改动,那就是循环体中,代码越少越快,或者断点跟踪,循环体哪的代码运行时间长,想办法把它移到循环体外。
andy_wanhl 2019-12-06
  • 打赏
  • 举报
回复
你这关键是这10000+的循环。能不能去掉呢?读数据返回的实体类,就是报表类,数据处理,可以放着报表类作处理,增加字段,但又是不是全部能转换成功呢?功能都完成不了,还优化效率,此其一,其二是改动非常大,又决心动手吗?
yuyi1991616 2019-12-06
  • 打赏
  • 举报
回复
引用 2 楼 正怒月神 的回复:
而且,必定要1W条数据显示出去吗?
显示没问题,我做了分页,至对查询页数据进行处理。 这是导出到Excel报表用的。 另外,ReportNumber是主表的主键,明细表的外键
Eason0807 2019-12-05
  • 打赏
  • 举报
回复
试试 Parallel.ForEach
datafansbj 2019-12-05
  • 打赏
  • 举报
回复
很明显瓶颈在 EF(Entity Framework) 上。在复杂的场景,EF 效率低下。原因是复杂场景下,微软对 EF 到数据库 SQL 之间的优化没有搞好,还不如手写 SQL 语句快。如果先把数据查询出来再使用 Linq 处理会快很多,但注意大数据量时查询耗时比数据处理耗时要多很多。
MYsce 2019-12-05
  • 打赏
  • 举报
回复
是否可以在数据库转换,大数据展示可否分页展示处理,这要效果会快
MikeCheers 2019-12-05
  • 打赏
  • 举报
回复
这个看着就比较头疼了。
首先,LinQ本身有自己的性能劣势,不适合这种大数据量遍历查找,比如:
tempItemList = itemList.Where(t => t.ReportNumber == kpi.ReportNumber).ToList();
itemList可以定义为一个以ReportNumber为Key,List<T>为Value的Dictionary<T1,List<T2>>,利用Hash的优势,会吃点内存,但是提升查找效率。
//品质
tempItem = tempItemList.FirstOrDefault(t => t.Title.Contains(KPISupplierReportShow.Key1));
诸如此类的Contains,效率都不会太高,如果你的Key1...KeyN都是固定值,那我还是建议你把它们做成Dictionary的Key。否则的话,会比较难搞。

另外数据量庞大的话,如果正常情况就是1W甚至更多条数据需要同时遍历的话,也建议去开辟多线程处理。
圣殿骑士18 2019-12-05
  • 打赏
  • 举报
回复
加个stopwatch,看看哪里慢。我看循环里用到了反射,这可能效率不高。
EnumHelper.GetEnumDescription......
正怒月神 2019-12-04
  • 打赏
  • 举报
回复
而且,必定要1W条数据显示出去吗?
正怒月神 2019-12-04
  • 打赏
  • 举报
回复
1 考虑在数据库行转列,而不是程序里。 2 你跟踪过linq生成的sql语句吗?看一下有没有优化空间。

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧