【问题标题】:What is the best method to access a large database using MVC 4 and Entity Framework 6使用 MVC 4 和 Entity Framework 6 访问大型数据库的最佳方法是什么
【发布时间】:2014-05-08 20:14:08
【问题描述】:

我有一个用 MVC 4 和 Entity Framework 6 编写的电子邮件营销 Web 应用程序。该应用程序将 10K 多个电子邮件地址以及联系信息存储在网络场的 sql 数据库中。

当数据库很小,只有几百条记录时,一切正常。但是,当我完全填充数据库时,使用“Foreach”语句检索和写入每条记录的速度非常缓慢。对于某些操作,最多可能需要 14 分钟才能完成。我试图在任何时候尽量减少我使用的记录数量,但这会使应用程序变得笨拙。

我想知道,有没有其他方法可以用来加快速度。可能是 SQL 存储过程,或者 GitHub 上的一些东西可以让它变得更容易。如果有,请告诉我在哪里可以了解更多信息。任何帮助,将不胜感激。这是其中一个查询。

private int AddOrUpdateCampaigns(Campaign campaign
        , IEnumerable<AssignEmailContacts> assignEmailContacts)
{
    DataBaseContext db = new DataBaseContext();
    int TotalAssigned = 0;
    if (assignEmailContacts == null) return(TotalAssigned);

    if (campaign.CampaignId != 0)
    {   
      foreach (var emailContact 
                in assignEmailContacts.Where(a => a.Assigned == false))
      {   
        campaign.EmailContacts.Remove(
                db.EmailContacts.Find(emailContact.EmailContactId));
      }
      foreach (var emailContact 
                in assignEmailContacts.Where(a => a.Assigned))
      {                            
        campaign.EmailContacts.Add(
                db.EmailContacts.Find(emailContact.EmailContactId));
            TotalAssigned += 1;
      }
    }
    return (TotalAssigned);
}

【问题讨论】:

  • 10K 记录是一个小数据库:)
  • 10K 不是一个大型数据库。您的查询是什么样的?您是否想一次全部收回所有记录?
  • @Dismissile 同意你的看法。看到在这样的数据库上执行 14 分钟的查询会很有趣
  • 我确信 marcgravell 会谈到速度和 EF 的含义,但我会研究 SPROC 或批处理执行。如果您在迭代中更新(每次调用 SaveChanges)肯定会增加延迟。
  • 正如其他人所说,10K是一个非常小的数据库,但回答你的问题,对于批量操作,存储过程会更快,应该使用。看看这个。 stackoverflow.com/questions/2698151/…

标签: c# sql asp.net-mvc entity-framework


【解决方案1】:

当您本可以获取所需的所有数据时,有关 EF 的缓慢之处在于对数据库进行大量往返;跟踪对象的变化。考虑到这一点,您可以在 EF 中使用两种主要的性能工具:

  1. Include 扩展方法。
  2. AsNoTracking 扩展方法(仅对读取有用,但在中型以上数据集上可大幅提升性能,可能与 Include 冲突)。

第一种方法允许您在单个查询中提取所有数据(前提是您的对象图中没有继承)。第二个停止 EF 执行所有跟踪工作,这使得读取速度更快。

当某些事情看起来很慢时,我通常会启动SQL Profiler,在我的数据库上运行跟踪,然后运行需要时间的方法。然后我添加包含,直到我减少到最少数量的查询。

还记得你可以添加索引等。

还有一件事。您的数据库可能是垃圾!如果您在配置错误的服务器上有一个数据库,其中包含许多其他活动数据库,那么您的性能问题可能只是由于磁盘争用造成的。如果 EF 和索引调整效果不大,请查看服务器:硬件确实很重要。

【讨论】:

  • +1 因为您没有说 EF 非常适合小型数据库。我每天在大型数据库上使用 EF,但有时您必须启动 SQL Profiler、Glimpse 等以了解您的查询、执行计划。由于所有工具 EF 都可能被滥用。您还可以使用有界上下文msdn.microsoft.com/en-us/magazine/jj883952.aspx
  • 感谢您的提示;我们有一个相当大的上下文,虽然大部分时间只有大约 10% 被使用,但明天会读完。
【解决方案2】:

在 EF 中更新多个数据库行很慢!

我假设有一个名为 CampaignContacts 的表,其中包含来自 Campaign 和 Contacts 的 n 对 n 关系的数据。幸运的是,EF6 允许您执行原始查询。

using System.Collections.Generic;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Text;

public class YourDbContext : DbContext
{
    public void DeleteBatchCampaignContacts(IList<int> ids)
    {
        if (ids == null) return;
        if (ids.Count == 0) return;         

        //ONLY because the parameter comes from a list of Int, else you might risk injection
        Database.ExecuteSqlCommand(string.Format("DELETE FROM CampainContacts WHERE CampaignId in ({0})", string.Join(",", ids)));
    }

    public void UpdateBatchCampaignContacts(int campaignId, IList<int> ids)
    {
        if (ids == null) return;
        if (ids.Count == 0) return;

        Database.ExecuteSqlCommand(string.Format("UPDATE CampaignContacts SET CampaignId = @campaignId WHERE EmailContactId in ({0})", string.Join(",", ids),
            new SqlParameter("@campaignId", campaignId)));
    }
}

注意代码重复。您可以重构这些函数,但这会比您当前的解决方案更快。您可以添加功能,例如以 50 个 ID 为一组执行查询,以处理数千个 ID 更新。这是一个开始。

【讨论】:

  • 这看起来可能对我有用。我不熟悉这些查询,我有一点要学习。不过只有三件事:1) 在 Database.ExecuteSqlCommand 上出现错误。我已经导入了 system.data.entity 命名空间。它说,我缺少对象引用。和 2) 我将如何更改它以根据导入的 ID 添加记录。我可以将“.Remove”更改为“.Add”吗?最后,我在哪里可以了解更多信息。感谢您的帮助。
  • 要添加大量新记录,请使用SqlBulkCopy
  • 看来我做错了什么。当我实施您建议的删除代码时,出现错误。 “将 nvarchar 值 '39432,39431,39430,39429,39428' 转换为数据类型 int 时转换失败。”有什么建议吗?
  • 我正在努力解决这个问题。你帮了我很大的忙。谢谢。
【解决方案3】:

在处理 RDBM 中的记录时,我通常使用存储过程,您将获得执行速度更快的优势。

可能只是您可以通过将电子邮件作为 ID 散列并根据这些参数进行搜索来加快查询速度,但这取决于项目的阶段或阶段。

您也可以直接查询您的数据库,看看需要多长时间,然后您就会知道它是否是您的代码

【讨论】:

    猜你喜欢
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多