2014-04-10 33 views
1

我遇到了EF6非常奇怪的错误。我在第一遍上传了〜38K条记录。然后在我的第二轮,我用条件linq语句查询表。该行代码需要大约4分钟才能运行。这是我的实体。EF6需要5分钟才能在少于40,000条记录上运行查询

[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; } 
} 

}

首先我运行此:

AdWord objAdWord = adwordsContext.AdWords.Where(c => c.ClientID == iCampaignID).FirstOrDefault(); 

然后

AdWordCampaign objAdWordCampaign = objAdWord.Campaigns.Where(c => c.CampaignID == iElementCampaignID && c.Day == sElementDate).FirstOrDefault(); 

线之上似乎加载所有它的第一次查询之前的记录。如果我在查询中添加Take(5),它仍然需要4分钟。

+0

你有'ClientID'上的索引吗?如果不是,它显然会扫描整个桌子。 – abatishchev

回答

0

尝试:

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

.Where复杂度为O(n)的操作,我不知道如果Where然后FirstOrDefault条款将得到优化,但如果它不是你正在使用Where浪费了大量的时间。为了进一步提高性能,请确保CampaignID已编入索引

+0

最近我看到另一个线程说,有时候在第一个地方做的时候会更快,但这绝对值得一试。 – DLeh

+0

我不明白为什么会这样。哪里会迭代每个结果,而First会停在第一个结果上。 –

+0

它生成的SQL基本上是相同的,因为它需要Where和First并将它们编译为一个查询。一般来说,他们真的不应该有太大的差别。 – DLeh

1

我希望此信息有用。

  1. 尝试添加索引到您的表的字段,您将包括到LINQ中的WHERE。

  2. 您可以随时创建额外的视图并将其添加到EF模型中并对它们执行LINQ。它也会减少时间。

  3. 如果您预计1个记录始终尝试使用SingleOrDefault

+0

我会假设它被编入索引。我如何用代码做到这一点?假设EF是一个C#工具,我不希望MS有C#创建表,将它交给一个DBA来索引它,然后将其交回,尽管这是一个好主意。 – user3521111

+1

@ user3521111请参阅以下链接以获取有关如何在表格上“索取”索引的线索:** http://blog.oneunicorn.com/2014/02/15/ef-6-1-creating-indexes-with- indexattribute/** –

0

你需要观察所生成的服务器上执行&查询,并确保他们进行了优化。

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

我只使用过Database First,而不是Code First,所以我不知道如何告诉Entity Framework在Code First场景中创建索引,对不起。但是你仍然需要优化你的所有查询。即当你做

AdWordCampaign objAdWordCampaign = objAdWord.Campaigns.Where(...).FirstOrDefault(); -

0

我已经通过了“主要目的”引用链接的对象时,EF见过这个。

很简单,它迭代所有记录一个接一个 - 因此慢查询。

如果更改为以下,你应该得到一个几乎瞬间响应:在尖括号

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(); 

我已经把改变,我不知道哪一个AdWordCampaign内财产商标的标识AdWord可以查看您的模型,但我相信您会明白 - 通过上下文直接转到Capaigns表,使用AdWord作为子句Where,而不是通过AdWord的Campaigns集合。

相关问题