C# EF6在少于40000条记录上运行查询需要5分钟

C# EF6在少于40000条记录上运行查询需要5分钟,c#,performance,entity-framework,entity-framework-6,C#,Performance,Entity Framework,Entity Framework 6,我在EF6上遇到了一个非常奇怪的错误。我在第一次通过时上传了约38K条记录。然后在第二轮中,我使用条件linq语句查询表。这行代码运行大约需要4分钟。这是我的实体 [Table("RAW_ADWORDS")] public class AdWord { [Key] public int ID { get; set; } public bool Processed { get; set; } public string Client { get; set; }

我在EF6上遇到了一个非常奇怪的错误。我在第一次通过时上传了约38K条记录。然后在第二轮中,我使用条件linq语句查询表。这行代码运行大约需要4分钟。这是我的实体

[Table("RAW_ADWORDS")] 
public class AdWord
{
    [Key]
    public int ID { get; set; }
    public bool Processed { get; set; }
    public string Client { get; set; }
    public long ClientID { get; set; }
    public bool Active { get; set; }
    public bool ProcessedAllFile { get; set; }
    public DateTime LastTimeRun{ get; set; }
    public DateTime? LastDateTimeProcessed { get; set; }
    public virtual List<AdWordCampaign> Campaigns { get; set; }
}

[Table("foobar")] 
public class AdWordCampaign
{
    [Key]
    public int ID { get; set; }
    public string Campaign { get; set; }
    public long CampaignID { get; set; }
    public string Day { get; set; }
    public long Clicks { get; set; }
    public string CampaignStatus { get; set; }
    public long Cost { get; set; }
    public long Impressions { get; set; }
    public double CTR { get; set; }
    public long AvgCPC { get; set; }
    public double AvgPosition { get; set; }
    public DateTime DownloadDate { get; set; }
}
然后

上面的行似乎在执行查询之前先加载所有记录。此外,如果在查询中添加Take(5),仍需要4分钟。

尝试:

objAdWord.Campaigns.FirstOrDefault(c => c.CampaignID == iElementCampaignID && c.Day == sElementDate)

.Where
是一个O(n)操作,我不确定
Where
then
FirstOrDefault
子句是否会得到优化,但如果不是这样,那么使用
Where
会浪费很多时间。为了进一步提高性能,请确保对
活动ID
进行索引

我希望此信息有用

  • 尝试将索引添加到要包括到LINQ中WHERE的表的字段中

  • 您总是可以创建额外的视图,并将其添加到EF模型中,然后对它们执行LINQ。这也将减少时间

  • 如果需要1条记录,请始终尝试使用
    SingleOrDefault


  • 您需要观察在服务器上生成和执行的查询,并确保它们得到优化

    如果您使用的是MS SQL Server,则需要运行SQL Server探查器工具。在调用执行查询的方法之前,在代码中放置断点。清除探查器的显示,然后执行该方法。您可以从那里捕获SQL,然后将其放入SSMS并查看计划。如果查询不使用索引,则需要添加下次运行时将使用的索引


    我只使用过数据库优先,而不是代码优先,所以我不知道如何让实体框架在代码优先的场景中创建索引,对不起。但您仍然需要优化所有查询。

    我以前在通过“主对象”引用链接对象时见过EF,也就是当您这样做时

    AdWordCampaign-objAdWordCampaign=objAdWord.campaings.Where(…).FirstOrDefault()

    非常简单,它一个接一个地迭代所有记录,因此查询速度很慢

    如果您更改为以下内容,您应该会得到几乎即时的响应:

    AdWord objAdWord = adwordsContext.AdWords.Where(c => c.ClientID == iCampaignID).FirstOrDefault();
    
    AdWordCampaign objAdWordCampaign = <adwordsContext>.Campaigns
    .Where(c => <c.AdwordId = objAdWord.Id> && c.CampaignID == iElementCampaignID && c.Day == sElementDate)
    .FirstOrDefault();
    
    AdWord objAdWord=adwordsContext.AdWords.Where(c=>c.ClientID==iCampaignID.FirstOrDefault();
    AdWordCampaign objAdWordCampaign=.Campaigns
    其中(c=>&&c.CampaignID==IELEmentCompagignId&&c.Day==sElementDate)
    .FirstOrDefault();
    

    我已将更改放在角括号中,我不确定AdWordCampaign中的哪个属性标记了AdWord的Id(从您的模型中可以看出),但我相信您已经了解了这一点-通过上下文直接转到Capaigns表,使用AdWord作为附加的
    Where
    子句,而不是通过AdWord的活动集合。

    您是否在
    ClientID
    上有索引?如果没有,它会扫描整个表,很明显。我最近看到另一个帖子说,它有时比以前更快,但这绝对值得一试。我不明白为什么会这样。Where将迭代每个结果,而First将在第一个结果处停止。它生成的SQL基本相同,因为它接受Where和First,并将它们编译成一个查询。一般来说,它们根本不应该有太大的区别。我不知道,我无法查看SQL:p如果SQL被编译(正如我怀疑的那样),那么除了index.DLeh之外,我不知道还有什么建议。好主意。我下载了它并运行了相同的查询。拍了00:00.125。那现在怎么办?我本以为它被索引了。如何使用代码来实现这一点?假设EF是一个C#工具,我不希望MS让C#创建表,然后交给DBA对其进行索引,然后再交还给它,尽管这是一个好主意。@user3521111请查看以下链接,以了解如何“要求”表上的索引:
    objAdWord.Campaigns.FirstOrDefault(c => c.CampaignID == iElementCampaignID && c.Day == sElementDate)
    
    AdWord objAdWord = adwordsContext.AdWords.Where(c => c.ClientID == iCampaignID).FirstOrDefault();
    
    AdWordCampaign objAdWordCampaign = <adwordsContext>.Campaigns
    .Where(c => <c.AdwordId = objAdWord.Id> && c.CampaignID == iElementCampaignID && c.Day == sElementDate)
    .FirstOrDefault();