2012-01-31 96 views
7
var queueitem = context.CrawlerQueues. 
       Select(cq => new{cq.Guid,cq.Result}). 
       SingleOrDefault(cq => cq.Guid == guid); 

如果不是一個壞主意,它會首先選擇所有的數據庫行,然後找到它,或者它會很聰明,並且看到它在其中使用的上下文,並且只讀取一行。Linq,是select()。SingleorDefault()是一個壞主意?

這樣做的原因是我想只返回Guid和Result coloums。

return Newtonsoft.Json.JsonConvert.SerializeObject(queueitem, Formatting.Indented); 

如何找到答案而不必監視網絡流量或對數據庫的請求?

回答

13

「將首先選擇所有的數據庫行,然後找到一個」

從技術上說,沒有,其次是.SingleOrDefault。選擇的組合不會那麼做的。 Select()爲查詢設置參數,但它實際上並不提取任何數據。直到事實上必須產生數據結果,LINQ的延遲執行纔會取出任何行。您可以將多個查詢組合在一起(.Select(...)。Select(..)等),直到執行返回數據的操作(如First()或.ToList())時,實際上什麼都不會獲取任何行。

但是,使用Single()可能會導致掃描整個數據集,以證明一個匹配行是唯一匹配的行。

想一想:如何查詢知道一行是只有行的數據集中的匹配?它將不得不嘗試找到下一行。如果數據集中只有一行匹配數以百萬計,則Single()可能必須遍歷所有數百萬行,以證明當前匹配是唯一匹配。

如果您的數據集是SQL,並且您的數據以允許查詢優化的方式建立索引,那麼Single()可能不會那麼糟糕。但是,如果您的SQL數據沒有以對此查詢有幫助的方式建立索引,Single()可能會爲SQL Server創建大量工作。

如果您的程序邏輯確實需要知道返回的行是整個數據集中唯一一行,則Single()是適當的。但是,還有其他方法可以保證唯一性。如果你可以在你的數據上設置一個與你的LINQ條件匹配的主鍵,那麼只有一個匹配的行可以存在/被添加到數據庫中,因此你並不需要Single()。 (具有諷刺意味的是,在這種情況下,Single()的性能也會非常快,因爲主鍵索引可用於優化查詢)

如果您只想匹配條件的第一行,請使用First( )而不是Single()。 First()只需掃描數據行直到找到第一個匹配。它不必繼續掃描行以證明第一場比賽是唯一的比賽,如Single()。

+0

謝謝。我一直在使用firstordefault,但是在提出這個問題時我忘記了。 – 2012-02-03 18:46:32

+0

我也會建議FirstOrDefault()。 – 2012-02-03 22:09:15

1

執行的實際查詢實際上取決於Linq提供程序,但是,Linq提供程序不會評估到最後一個可能的時刻,因此在執行查詢之前它將知道上下文(SingleOrDefault)。一個好的人不會不必要地獲取任何東西。

一個很好的Linq實現實際上會獲取2行,因爲SingleOrDefault處理3個案例;

  • 沒有行返回 - >返回默認
  • 一行返回 - >返回該行
  • 多行返回 - >拋出異常(序列包含多個元素)
2

SingleOrDefault - 返回序列的唯一元素,或者如果序列爲空,則返回默認值; 如果序列中存在多個元素,則此方法會引發異常。

FirstOrDefault - 返回序列的第一個元素,如果序列不包含元素,則返回默認值。

從語義上講,你想FirstorDefault因爲你的問題提到了多行返回。

+1

你是對的。但這不是問題的問題。 – 2012-01-31 15:03:59

3

我很肯定,在過濾之前,不會返回整個數據庫,因爲只有在'evaluation'語句執行後纔會執行查詢,這是此查詢中的SingleOrDefault()。

如果你有

context.CrawlerQueues.ToList().Select(cq => new{cq.Guid,cq.Result}).SingleOrDefault(cq => cq.Guid == guid);

然後這將評估ToList()過濾之前,但查詢就好了。

如果您不確定LINQ語句中的評估路徑或生成的SQL,LINQPad是一個很好的工具,它使得使用Linq,Linq2Sql,EF非常簡單。

相關問題