2014-04-10 34 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集合。

相關問題