EF4导入/查找数千条记录 - 我的表现很糟糕!

时间:2010-12-28 03:44:21

标签: performance entity-framework

我正在尝试为电影商店网站设置一些东西(使用ASP.NET,EF4,SQL Server 2008),在我的场景中,我想允许“会员”商店导入他们存储的电影目录包含ActorName,MovieTitle和CatalogNumber的文本文件,如下所示:

演员,电影,CatalogNumber
John Wayne,True Grit,4577-12(每个记录重复)

这些数据将用于查找演员和电影,并创建一个“MemberMovie”记录,如果我使用这些表导入超过100个左右的记录,我的导入速度很糟糕:

  • 演员表:字段= {ID,名称等}
  • 电影表:字段= {ID,Title,ActorID等}
  • MemberMovie表:字段= {ID,CatalogNumber,MovieID等}

我从文本文件将数据导入MemberMovie表的方法如下(文件成功上传后):

  1. 创建一个上下文。
  2. 对于文件中的每一行,在Actor表中查找艺术家。
  3. 对于Artist表中的每个Movie,查找匹配的标题。
  4. 如果找到匹配的电影,请将新的MemberMovie记录添加到上下文并调用ctx.SaveChanges()。
  5. 我的实施表现非常糟糕。我的期望是,这可以在几秒钟内完成(在文件上传之后)数千条记录,并且我有一些东西超出浏览器。

    我的问题是:执行批量查找/插入的最佳方法是什么?我应该只调用一次SaveChanges而不是每个新创建的MemberMovie吗?使用像存储过程这样的东西来实现它会更好吗?

    我的循环片段大致就是这样(为简洁起见而编辑):

    while ((fline = file.ReadLine()) != null)
    {
        string [] token = fline.Split(separator);
    
        string Actor = token[0];
        string Movie = token[1];
        string CatNumber = token[2];
    
        Actor found_actor = ctx.Actors.Where(a => a.Name.Equals(actor)).FirstOrDefault();
    
        if (found_actor == null)
            continue;
    
        Movie found_movie = found_actor.Movies.Where( s => s.Title.Equals(title, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
    
        if (found_movie == null)
            continue;
    
        ctx.MemberMovies.AddObject(new MemberMovie()
        {
            MemberProfileID = profile_id,
            CatalogNumber = CatNumber,
            Movie = found_movie
        });
    
        try
        {
            ctx.SaveChanges();
        }
        catch
        {
        }
    }
    

    感谢任何帮助!

    谢谢,丹尼斯

1 个答案:

答案 0 :(得分:1)

<强>首先

前段时间我写了一篇关于在 1,n或所有行之后调用SaveChanges的答案:

When should I call SaveChanges() when creating 1000's of Entity Framework objects? (like during an import)

实际上,在超过1行之后调用SaveChanges会更好,但毕竟不是。

<强>第二

确保你在Actors表中的名字和电影中的标题都有索引,这应该有所帮助。如果你只需要他的ID,你也不应该选择整个Actor:

而不是:

Actor found_actor = ctx.Actors.Where(a => a.Name.Equals(actor)).FirstOrDefault();

您可以选择:

int? found_actor_id = ctx.Actors.Where(a => a.Name.Equals(actor)).Select(a => a.ID).FirstOrDefault();

然后

Something.ActorID = found_actor_id;

这可以更快,因为不需要整个Actor实体,也不需要额外的查找,特别是与索引结合使用时。

<强>第三

如果发送一个非常大的文件,即使性能良好,仍有可能超时。您应该在单独的线程中运行此导入并立即返回响应。您可以为每个导入提供某种标识符,并允许用户通过此ID检查状态。