首页 新闻 会员 周边

EF Core 插入数据一段时间变慢,重新启动程序后恢复

0
[待解决问题]

使用ef core项SqlServer插入数据,目前数据量不算大。每秒插入50条,且更新54条记录。一开始需要50ms左右,但是在程序运行7个小时左右速度骤降,需要800ms左右,最长3500ms。
我的实体类结构大致如下:
Deivice{Guid Id, 属性若干}
DeviceStatus{Guid Id, 状态字段若干}
Module1Status{Guid Id, 状态字段若干}
Module2Status{Guid Id, 状态字段若干}
Part{Guid Id, Guid DeviceId, 属性若干} // Device与Part是OneToMany关系
PartStatus{Guid Id, 状态字段若干}
DeviceStatusHistory{Guid Id, 时间, 状态字段若干} // 这里的状态与DeviceStatus中状态对应
PartStatusHistory{Guid Id, 时间, Guid DeviceStatusHistoryId, 状态字段若干} // 这里的状态与PartStatus中状态对应

其中属性在该程序运行时不进行更新(不发生变化,忽略其他应用引起的修改),状态字段时刻发生变化,也就是该程序进行的处理(更新),Device和Part都有一个对应历史状态表,每次状态发生变化后想起插入当前状态数据
插入数据使用了事务进行批量提交,代码片段如下:

 1 await using (var trans = await dbContext.Database.BeginTransactionAsync())
 2 {
 3     try
 4     {
 5         #region 映射数据
 6 
 7         var loggedTime = DateTime.Now;
 8         
 9         #endregion
10         
11         sw1.Restart();
12         
13         // 添加设备状态日志
14         await dbContext.DeviceStatusHistories.AddAsync(deviceStatusHistory);
15         // 添加部件状态日志
16         await dbContext.PartStatusHistories.AddRangeAsync(partStatusHistories);
17         
18         // 更新设备状态
19         await dbContext.DeviceStatus
20             .Upsert(new DeviceStatus()
21             {
22                 Id = _session.Device.Id,
23                 LoggedTime = loggedTime,
24                 //状态若干
25             }).RunAsync();
26         
27         // 更新休眠模块状态
28         await dbContext.Module1Status
29             .Upsert(new Module1Status()
30             {
31                 Id = _session.Device.Id,
32                 LoggedTime = loggedTime,
33                 //状态若干
34             }).RunAsync();
35         
36         // 更新放电模块状态
37         await dbContext.Module2Status
38             .Upsert(new Module2Status()
39             {
40                 Id = _session.Device.Id,
41                 LoggedTime = loggedTime,
42                 //状态若干
43             }).RunAsync();
44         
45         // 更新电池状态
46         await dbContext.PartStatus
47             .UpsertRange(batteries.Select(c => new PartStatus()
48             {
49                 Id = c.Id,
50                 LoggedTime = loggedTime
51                 //状态若干
52             }))
53             .RunAsync();
54 
55         await dbContext.SaveChangesAsync();
56         await trans.CommitAsync();
57     }
58     catch (Exception ex)
59     {
60         await trans.RollbackAsync();
61         logger.LogError(ex.Message, ex);
62     }
63     finally
64     {
65         // GC.Collect();
66         sw1.Stop();
67         logger.LogDebug($"SAVE:{sw1.ElapsedMilliseconds}");
68     }
69 }

以上每个实体都以Id为主键,时间字段建立的索引。

求园内大神指条明路

Nii Jyeni的主页 Nii Jyeni | 菜鸟二级 | 园豆:202
提问于:2020-06-09 22:50

手动置顶,请各位大神和前辈给点指导意见

Nii Jyeni 3年前
< >
分享
所有回答(3)
0

数据追踪关了试试
推荐博客
https://www.cnblogs.com/zhaow/articles/9335239.html

winds_随风 | 园豆:156 (初学一级) | 2020-06-11 09:58

已经关闭了追踪,使用的这个扩展方法.

.AsNoTracking() // 关闭状态追踪

支持(0) 反对(0) Nii Jyeni | 园豆:202 (菜鸟二级) | 2020-06-12 12:41

@Nii Jyeni: 就是还是没效果吗

支持(0) 反对(0) winds_随风 | 园豆:156 (初学一级) | 2020-06-12 12:45

@winds_随风: 是的

支持(0) 反对(0) Nii Jyeni | 园豆:202 (菜鸟二级) | 2020-06-12 13:03

@winds_随风:刚开始都是很快的,然后就一点一点的变慢了

支持(0) 反对(0) Nii Jyeni | 园豆:202 (菜鸟二级) | 2020-06-12 13:04
0

不要一直用一个 dbContext ,数据太多影响效率,可以每一批次的处理使用一个 dbContext,类似于 .net core 的 Scoped 

WeihanLi | 园豆:217 (菜鸟二级) | 2020-06-11 13:33

是的,我每一次处理都是使用一个新的dbContext.昨晚连续运行到现在数据胡保存时间又从最开始的40毫秒左右增加到了1000毫秒以上.

支持(0) 反对(0) Nii Jyeni | 园豆:202 (菜鸟二级) | 2020-06-12 12:39

@WeihanLi:每一次处理需要新增1+24条数据(两张表),更新1+1+1+24数据(4张表)

支持(0) 反对(0) Nii Jyeni | 园豆:202 (菜鸟二级) | 2020-06-12 12:43

@Nii Jyeni: `Upsert`和 `UpsertRange` 是怎么实现的?

支持(0) 反对(0) WeihanLi | 园豆:217 (菜鸟二级) | 2020-06-12 12:45

@WeihanLi: 使用的开源库(https://github.com/artiomchi/FlexLabs.Upsert),生成upsert或merge into语句

支持(0) 反对(0) Nii Jyeni | 园豆:202 (菜鸟二级) | 2020-06-12 13:03

@Nii Jyeni: 你用  `Upsert` 这里只是想部分更新吧,感觉 Upsert 可能会有点影响性能,部分更新可以直接写一个 EF 的扩展方法,更新对象的状态可能会更好一些,`Upsert` 调用 `RunAsync` 的时候就会更新数据库,而 EF 修改数据状态的方式可以延迟更新,最后批量提交到数据库性能会更好一些

支持(0) 反对(0) WeihanLi | 园豆:217 (菜鸟二级) | 2020-06-12 14:13

@WeihanLi: 感觉还是太慢了,正在尝试Ado.Net,谢谢指导

支持(0) 反对(0) Nii Jyeni | 园豆:202 (菜鸟二级) | 2020-06-15 13:56
0

表里一共多少数据?理论上数据量越来越大,插入速度就会变慢,可以在7个小时后,去掉数据库索引看下时间会不会变快。
其实要是有效率要求的话,批量插入最好使用数据库的批量添加。
最后就是监控一下EF生成的sql语句,自己拿到数据库里去执行一下,看看具体执行计划的耗时,分析到底是数据库原因还是程序原因。

李0539 | 园豆:442 (菜鸟二级) | 2020-07-11 16:04
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册