2

使用 LINQ,我无法以有效的方式查询我的 DbContext。该数据库包含 700,000 多个具有日期和名称以及其他信息的实体。

在我的代码中,我有一个新的对象列表(可能有 100,000 个元素)进来,我想查询我的数据库并扣除哪些信息是新实体或哪些信息是需要更新的现有实体。

我想以一种非常有效的方式来做(如果可能的话,用一个查询)。

这是我的代码:

public class MyDbContext : DbContext
    {
        public DbSet<MyEntity> MyEntities { get; set; }
    }

    public class MyEntity
    {
        [Key]
        public Guid Id { get; set; }
        public DateTime Date { get; set; }
        public string Name { get; set; }
        public double Amount { get; set; }
        public string Description { get; set; }
    }

    public class IncomingInfo
    {
        public DateTime Date { get; set; }
        public string Name { get; set; }
        public double Amount { get; set; }
    }

    public class Modifier
    {
        public void AddOrUpdate(IList<IncomingInfo> info)
        {
            using (var context = new MyDbContext())
            {                 
                //Find the new information 
                //to add as new entities
                IEnumerable<MyEntity> EntitiesToAdd = ??

                //Find the information 
                //to update in existing entities
                IEnumerable<MyEntity> EntitiesToUpdate = ?? 
            }
        }
    }

有人可以帮我构建我的查询吗?非常感谢你。

编辑:对不起,我忘了解释我如何认为两个实体相等。如果 Date 和 Name 属性相同,则它们相等。

我首先尝试使用 LinqKit PredicateBuilder 构建谓词,但没有取得多大成功(遇到参数太大的错误,不得不进行多次查询,这需要时间)。

到目前为止,我发现的最成功的方法是实现 LEFT OUTER join 并将传入列表加入我以这种方式实现的 DbSet :

var values = info.GroupJoin(context.MyEntities,
                    inf => inf.Name + inf.Date.ToString(),
                    ent => ent.Name + ent.Date.ToString(),
                    (inf, ents) => new { Info = inf, Entities = ents })
                 .SelectMany(i => i.Entities.DefaultIfEmpty(),
                    (i, ent) => new { i.Info.Name, i.Info.Amount, i.Info.Date, ToBeAdded = ent == null ? true : false });

IEnumerable<MyEntity> EntitiesToAdd = values.Where(i => i.ToBeAdded)
    .Select(i => new MyEntity
    {
        Id = Guid.NewGuid(),
        Amount = i.Amount,
        Date = i.Date,
        Name = i.Name,
        Description = null
    }).ToList();

我的测试在数据库中包含 700,000 个实体。传入的信息列表包含 70,000 个项目;其中 50,000 个是现有实体,20,000 个是新实体。此查询大约需要 15 秒才能执行,这对我来说似乎不合适。

希望这足以寻求帮助。有人可以帮我一个吗?非常感谢你。

4

1 回答 1

1

我阅读了来自@Leniency 的 pastebin 回复,它涵盖了我要说的一些相同内容,例如查询日期范围并在那里进行比较。但是,该方法的问题在于(取决于这些日期的设置方式)它可能会返回数据库中的所有 700K+ 记录,这会给您带来绝对最差的性能。

我的建议是你分析你的网络拓扑,看看你对数据库的调用到底有多昂贵。我假设这是在IncomingInfo从客户端接收这些对象的(Web)服务器上运行的。如果此服务器与您的数据库服务器紧密连接(或在同一台机器上),那么您最好不要优化对数据库的调用。

此外,如果您可以控制客户端的行为,您可能希望强制他们在每个请求中仅发送 25 到 100 条记录。这将使您可以以更易于管理的方式处理它们。客户端可能必须向服务器发送 100 个或更多请求(您可以执行异步操作,以便它们一次发送约 5 个,具体取决于预期的负载配置文件),但至少它不会坐在那里超过 5 个等待从服务器返回单个请求的响应的分钟数。

顺便说一句,GroupJoin您所说的通话需要 15 秒,可能是在加入之前必须下载所有 700K 记录。你看,连接不能在同一台机器上不存在的对象上完成,它要么必须将所有IncomingInfo对象(或至少 Name+Date.ToString() 连接)发送到数据库,要么它有在可以完成任何连接之前从数据库中请求所有记录。您可能必须查看发送到数据库的 SQL 以判断正在使用哪种方法。但是您可能会发现,在这种情况下,一次查询一个匹配项可能比连接要快。

希望有帮助!;)

于 2013-07-10T21:34:11.890 回答