以下代码导致内存溢出:
是一段连表查询导致查询不到的问题
var onelst = await dbpTasks.Where(Epr).Join(Context.DbpTaskMetadata.AsNoTracking().GroupBy(meta => meta.Taskid).Select(g => new { Key = g.Key, Value = g }), src => src.Taskid, meta => meta.Key, (src, meta) => new { src, meta }).Select(taskinfo => new TaskDbFullInfo { Dbptask = taskinfo.src, CaptureMeta = taskinfo.meta.Value.Where(x => x.Metadatatype == (int)MetaDataType.emCapatureMetaData).FirstOrDefault(), ContentMeta = taskinfo.meta.Value.Where(x => x.Metadatatype == (int)MetaDataType.emContentMetaData).FirstOrDefault(), MaterialMeta = taskinfo.meta.Value.Where(x => x.Metadatatype == (int)MetaDataType.emStoreMetaData).FirstOrDefault(), PlanningMeta = taskinfo.meta.Value.Where(x => x.Metadatatype == (int)MetaDataType.emPlanMetaData).FirstOrDefault(), SplitMeta = taskinfo.meta.Value.Where(x => x.Metadatatype == (int)MetaDataType.emSplitData).FirstOrDefault() } ).ToListAsync();
DbpTaskMetadata全部查询分组了 ,耗时长内存也飙升,主要使用Group
sfenxiFenixql语句如下:
EXPLAIN SELECT dbptask.*, capture_meta.metadata AS capture_metadata, content_meta.metadata AS content_metadata, material_meta.metadata AS material_metadata, planning_meta.metadata AS planning_metadata, split_meta.metadata AS split_metadata FROM dbp_task dbptask LEFT JOIN ( SELECT taskid, metadata FROM dbp_task_metadata WHERE metadatatype = 1 ) capture_meta ON dbptask.taskid = capture_meta.taskid LEFT JOIN ( SELECT taskid, metadata FROM dbp_task_metadata WHERE metadatatype = 2 ) content_meta ON dbptask.taskid = content_meta.taskid LEFT JOIN ( SELECT taskid, metadata FROM dbp_task_metadata WHERE metadatatype = 3 ) material_meta ON dbptask.taskid = material_meta.taskid LEFT JOIN ( SELECT taskid, metadata FROM dbp_task_metadata WHERE metadatatype = 4 ) planning_meta ON dbptask.taskid = planning_meta.taskid LEFT JOIN ( SELECT taskid, metadata FROM dbp_task_metadata WHERE metadatatype = 5 ) split_meta ON dbptask.taskid = split_meta.taskid WHERE dbptask.taskid<10;
mysql分析:
可以看到时全表查询
本地调试运行现象内存飙升不止
内存飙升分析
使用方式:
.Net Core在Linux环境dump分析_.net core dump_iamfrankjie的博客-CSDN博客
如何修改:
如何不是后台服务添加请求接口日志,查找所有请求的接口记录.
定位那个请求连接 然后本地调试观察内存使用情况
然后结合内存情况分析
实现的原理梳理:
表1为任务表
表2为任务元数据表
表1的taskid对应表二taskid有多条记录
如何查询表1的一个taskid和类型对应记录为一个字段加表2对应的多条记录分别为一个字段
如果您需要在查询中添加任务元数据的类型条件,可以这样修改SQL语句:
sql SELECT t1.taskid AS taskid, (SELECT metadata FROM task_metadata WHERE taskid = t1.taskid AND type = 'type1' LIMIT 1) AS metadata1, (SELECT metadata FROM task_metadata WHERE taskid = t1.taskid AND type = 'type2' LIMIT 1 OFFSET 1) AS metadata2, (SELECT metadata FROM task_metadata WHERE taskid = t1.taskid AND type = 'type3' LIMIT 1 OFFSET 2) AS metadata3 FROM tasks t1
msyql分析:
可以看到不存在全表查询
或者在LINQ查询中这样修改:
csharp var result = from t in dbContext.Tasks select new { t.TaskId, Metadata1 = (from tm in dbContext.TaskMetadata where tm.TaskId == t.TaskId && tm.Type == "type1" select tm.Metadata).FirstOrDefault(), Metadata2 = (from tm in dbContext.TaskMetadata where tm.TaskId == t.TaskId && tm.Type == "type2" select tm.Metadata).Skip(1).FirstOrDefault(), Metadata3 = (from tm in dbContext.TaskMetadata where tm.TaskId == t.TaskId && tm.Type == "type3" select tm.Metadata).Skip(2).FirstOrDefault() };
只需要在查询TaskMetadata的条件中添加元数据类型的条件即可。如果某个类型的元数据不存在,相应的Metadata字段将为NULL。例如,如果task_metadata表还有一个Type列,数据如下:| taskid | metadata | Type |
|:-:|:-:|:-:|
| 1 | metadata1 | type1 |
| 1 | metadata2 | type2 |
| 2 | metadata3 | type2 |
| 2 | metadata4 | type3 |那么查询结果为:| taskid | metadata1 | metadata2 | metadata3 |
|:-:|:-:|:-:|:-:|
| 1 | metadata1 | metadata2 | NULL |
| 2 | NULL | metadata3| metadata4 | Metadata1字段包含type1元数据,Metadata2包含type2元数据,Metadata3包含type3元数据。请根据实际业务逻辑选择元数据的类型条件,我这里只作为一个示例。
优化
使用EF Core执行全表查询时,由于需要将整个表的数据加载到内存中,如果表过大 existed内存限制,很容易出现内存溢出的问题。有几种方法可以避免或减少此问题:1. 设置DbContext的MaxResultSetSize限制您可以在DbContext选项中设置MaxResultSetSize来限制返回行数,例如:
csharp optionsBuilder.UseSqlServer(connectionString, o => o.MaxResultsSize(100));
这将限制查询返回不超过100行记录,可以避免返回过多数据导致的内存溢出。2. 使用延迟加载和懒加载在EF Core中,默认启用延迟加载,这意味着关联数据只在真正访问时从数据库加载。您也可以通过设置属性的Load方法手动标记启用延迟加载,例如:
csharp public class Blog { public int Id { get; set; } public string Title { get; set; } public virtual List<Post> Posts { get; set; } } modelBuilder.Entity<Blog>() .HasMany(b => b.Posts) .WithOne(p => p.Blog) .HasForeignKey(p => p.BlogId) .IsRequired() .Load(); // 使用延迟加载
这可以避免在查询博客时立即加载所有的文章数据,减少内存使用。3. 设置查询的PageSize并使用分页您可以在查询中设置PageSize来限制单次返回行数,然后使用分页逐步加载更多数据,而不是立即加载所有行。例如:
csharp int pageSize = 100; var blogs = await dbContext.Blogs.Take(pageSize).ToListAsync(); var nextPage = await dbContext.Blogs.Skip(pageSize).Take(pageSize).ToListAsync(); // ...
这种分页查询方式可以充分控制每次加载的数据量,有效降低内存溢出的风险。4. 避免ToListAsync方法ToListAsync方法会将查询结果缓存到内存列表中,这会占用更多内存。您可以使用其他像Single、SingleOrDefault这样的查询方法,或者用foreach直接枚举查询的每个结果,而不调用ToListAsync。这些是使用EF Core时避免或减少全表查询导致内存溢出的几个常用方法。适当运用可以提高系统的性能和健壮性。
标签:tm,查询,EFCode,meta,内存,taskid,NET,metadata From: https://www.cnblogs.com/futurismme/p/17382189.html