在实体框架中处理大数据的最佳方法
Posted
技术标签:
【中文标题】在实体框架中处理大数据的最佳方法【英文标题】:Best way to handle large data in entity framework 【发布时间】:2019-02-14 20:48:26 【问题描述】:您好,我正在使用 EF6,我有大量数据可以从数据库中进行选择,我的查询如下:
var EntityInfo = _contextRegister.Entities.Where(x => x.IsDeleted != true).ToList();
foreach (var itm in EntityInfo)
Entity.Entity entity = new Entity.Entity();
entity.MainActivityId = itm.MainActivityId;
entity.SubGroupId = itm.SubGroupId;
entity.Id = Convert.ToInt32(itm.Id);
-------
entity.UAECityRegion = _contextFRAMEWORK.UAECityRegions.Where(m => m.Id == itm.UAECityRegionId).Select(m => m.RegionName).FirstOrDefault();
var voucherstautus = _contextRegister.EPayVoucherDatas.Where(m => m.EntityId == itm.Id).ToList();
foreach (var item in voucherstautus)
if (item.VoucherStatus == 10)
entity.PaymentStatus = Convert.ToInt32(item.VoucherStatus);
break;
entityList.Add(entity);
这个查询需要超过 10 分钟,我怎样才能使这个查询更好,或者我应该使用存储过程而不是框架?
【问题讨论】:
哪个查询?我数到 3。 所有这些都在一个方法中,您将看到嵌套循环,因此循环每个实体的速度很慢。 您将从数据库中拉出所有未删除的实体。然后你在本地迭代所有这些,为它们中的每一个获取来自数据库的另一组数据的列表。您如何期望这会很快? 是的@Oliver。我需要简化这个查询,或者我可以使用存储过程来克服时间问题吗? 一次写一个包含所有条件的查询会很快。那么写成LINQ查询或者存储过程也没什么区别。 【参考方案1】:据我所知,Entities
和 EPayVoucherDatas
之间存在 1:1 的关系(否则您的代码 _contextRegister.EPayVoucherDatas.Where(m => m.EntityId == itm.Id)
将不起作用)。所以首先确保你已经模拟了this relationship in your EF model。
如果是这样,你可以这样写:
_contextRegister.EPayVoucherDatas.Where(m => !m.Entity.IsDeleted);
这已经解决了你的部分问题。
另一部分是您使用另一个数据库_contextFRAMEWORK
,它似乎包含相同ID下的一些其他数据。在您当前的实现中,您分别为每个项目请求一个特定区域。但是根据该表的大小,将整个表拉一次(在 for 循环之外)并在本地进行查找可能更明智。如果 VoucherStatus 也是 10,您还有这个 if 语句将 PaymentStatus 设置为 10。在所有其他情况下是什么?也许您总是可以从 VoucherStatus 映射 PaymentStatus?
很多问题而不是真正的答案,因为像往常一样这取决于。尽量减少对数据库的调用量,并检查每个调用返回多少实体。尽早按一些条件进行过滤,以尽量减少服务器返回的数据量,并尽量减少与服务器的连接。即使这会导致非常复杂的查询。对于 SQL 服务器而言,这通常不是问题,因为它的用途就是如此。
【讨论】:
【参考方案2】:1) 检查是否为 WHERE 条件中使用的每个字段创建了数据库索引,例如:
x.IsDeleted
m.Id
m.EntityId
您可以使用模型构建器创建索引:
modelBuilder.Entity<Person>()
.HasIndex(p => p.Name)
.IsUnique();
见https://***.com/a/47031294/194717
您也可以使用 IndexAttribute 创建索引
public class Blog
public int Id get; set;
public string Title get; set;
[Index]
public int Rating get; set;
public virtual ICollection<Post> Posts get; set;
见https://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with-indexattribute/
2) 您不应为每个实体记录两次访问数据库。尝试将其写为 JOIN (.Include()
)。
【讨论】:
这是一个非常通用的解决方案,实际问题是每个Entities
记录不应该两次访问数据库。他们应该将其写为 JOIN (.Include()
)。以上是关于在实体框架中处理大数据的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章