【问题标题】:Improve performence of querys working with c#, Entity Framework提高使用 c#、实体框架的查询的性能
【发布时间】:2017-08-13 01:33:27
【问题描述】:

问题:我向我的服务器发送请求,并将模型数组添加到数据库中。例如,一个 Array 包含 5000 个模型。现在,所有这些都必须检查它们的引用 ID 是否已存在于表一中,并且该 ID 是否不在实际表中(在示例中命名为二)。如果是这种情况,我会将其添加到数据库中。我会问 5000 次,每个模型一次,这需要很长时间。由于我很少使用数据库和实体框架,我真的不知道如何改进查询。我做错了什么,我可以改进什么?

foreach(twoModel model in Models){
  if (Context.TAB_One.All(m => m.Id != model.RefId_One)) {
    continue;
  }
  if (Context.TAB_Two.Any(m => m.Id == model.Id)) {
    continue;
  }
Context.TAB_Two.Add(model);
}

【问题讨论】:

  • TAB_OneTAB_Two 中分别找到的预期记录总数是多少?
  • 标签一将包含更少。数据将存储在数据库中,并且永远不会/或很少被删除。因此,对于这两个表,记录都会随着时间的推移而增加。对于我添加一组 Tab_two 数据的每个请求,选项卡一个只会添加一次。您可以说有大约 5000 倍的记录,但可能从大约 500 到未知(可能是 20000 个条目/Tab_One 条目)。缩写形式是:1...n,其中 n 可能介于 2000 和 6000 之间。

标签: c# sql database entity-framework linq


【解决方案1】:

您可以过滤模型并添加此过滤器的结果。示例:

// define the array of IDs you want to search
var refIds = Models.Select(x => x.RefId_One).ToArray();
var ids = Models.Select(x => x.Id).ToArray();

// perform the queries to filter
var allModelOne = Context.TAB_One.All(m => !refIds.Contains(m.Id));
var anyModelTwo = Context.TAB_Two.Any(m => ids.Contains(m.Id));

// filter models 
var modelsToSave = model.Where(m => !allModelOne.Contains(m.Id) && !anyModelTwo.Contains(m.Id));

// save them
foreach(twoModel model in modelsToSave) {   
    Context.TAB_Two.Add(model);
}

过滤之前,您的代码将避免循环查询。

Obs:我不确定您的模型,但它应该类似于示例。

【讨论】:

    【解决方案2】:

    我可以给你另一种方法来实现这一点吗?

    首先看一下这个帖子: Fastest Way of Inserting in Entity Framework

    如您所见,实体框架并不是完成大型工作的最佳方式。

    因此考虑使用批量插入,然后执行存储过程来完成艰苦的工作。

    或者,如果你真的想用 C# 和 EF 来做,至少,在分支中做,即一次运行 100 个 SaveChanges()。

    干杯

    【讨论】:

      【解决方案3】:

      最简单的做法是返回数据库中的所有现有值并建立一个哈希列表。

      // I guessed that it is an int, change it accordingly
      var tableOneLookup = new HashSet<int>(Context.TAB_One.Id.Select(x => x.Id));
      var tableTwoLookup = new HashSet<int>(Context.TAB_Two.Id.Select(x => x.Id));
      
      // example of checking (check based on code you had shown before)
      var modelsNotInTabOne = Models.Where(model => !tableOneLookup.Contains(model.RefIdOne)).ToList();
      var modelsNotInTabTwo = Models.Where(model => !tableOneLookup.Contains(model.Id)).ToList();
      
      // now do something with the results like create entity instances
      

      如果您使用字符串作为标识符,那么您应该添加一个字符串比较器。如果您使用 StringComparer.OrdinalIgnoreCase,它将确保不考虑大小写,请选择您需要的正确大小写。

      new HashSet<int>(Context.TAB_Two.Id.Select(x => x.Id), StringComparer.OrdinalIgnoreCase);
      

      选项 2

      如果您的表有大量记录,则上述解决方案不再有效。您可以通过查找数据库中的哪些 id 然后过滤该结果来执行相反的操作。

      // create lists of just the ids
      var modelOneIds = Models.Select(model => model.RefIdOne).ToList();
      var modelTwoIds = Models.Select(model => model.Id).ToList();
      
      // create a list of ids found in the db
      var foundInTableOne = new List<int>();
      var foundInTableTwo = new List<int>();
      
      // iterate over the model in batches of 1000, the translated IN clause in Sql has a limit. You can tweak this number accordingly
      const int batchSize = 1000;
      for(int i = 0; i < Models.Count; i+=batchSize){
          var tmpModelOneIds = modelOneIds.Skip(i).Take(batchSize).ToList();
          var tmpModelTwoIds = modelTwoIds.Skip(i).Take(batchSize).ToList();
      
          foundInTableOne.AddRange(Context.TAB_One.Where(itm => tmpModelOneIds.Contains(itm.Id)).Select(itm => itm.Id));
          foundInTableTwo.AddRange(Context.TAB_Two.Where(itm => tmpModelTwoIds.Contains(itm.Id)).Select(itm => itm.Id));
      }
      
      // find the models not found in the DB
      var modelsNotInTabOne = Models.Where(model => !foundInTableOne.Contains(model.RefIdOne)).ToList();
      var modelsNotInTabTwo = Models.Where(model => !foundInTableTwo.Contains(model.Id)).ToList();
      
      // now do something with the results like create entity instances
      

      【讨论】:

      • 感谢您的回答,正如您所提到的,记录的数量正在迅速增加,因此它将成为一个庞大的数量。尤其是 Tab_Two 的情况。
      • @JSTW1212 - 很高兴它对你有用。请考虑标记答案。
      【解决方案4】:

      我会将表一和表二中的 id 读取到两个 Dictionary 对象中,如果键已经存在,Dictionary 是搜索最快的数据结构之一。您应该会看到性能的巨大改进。然后,您可以将需要添加到表 2 的 id 添加到列表中 并在最后进行批量插入。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多