在实体框架中处理大数据的最佳方法

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】:

据我所知,EntitiesEPayVoucherDatas 之间存在 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())。

以上是关于在实体框架中处理大数据的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

Spark 大数据处理最佳实践

在 mysql 中处理大数据的最佳方法是啥? (成员之间的跟进、通知等)

处理复杂+大数据文件的建议

Bossies 2016:最佳开源大数据工具

Bossies 2016:最佳开源大数据工具

大数据生态安全框架的实现原理与最佳实践(下篇)