2017-06-13 28 views
2

這是一個關於性能的問題。這裏有個模式我看到在這兩個我自己的代碼有很多和我的同事當結果很可能時,IQueryable ToList()更喜歡.Count()嗎?

var items = GetItems(); 

變量items的代碼現在包含一個IQueryable將從數據庫返回一個,多個或沒有行。

然後:

if (items.Any()) { 
    //do something, but only if there are items 
    foreach (var item in items) { 
     ... 
    } 
    //do something else, but only if there are items 
} 

因此,我們將執行兩個動作和循環的情況下,也有項目。假設會有通常是退回的貨品,那豈不是更有意義編輯上面的代碼:

var items = GetItems().ToList(); 

所以我Any()(有時甚至.Count() > 0

你認爲怎麼樣這個?假設GetItems()返回一個本身不慢的複雜查詢,但仍然非常複雜。

+5

它可以返回很多結果,您不希望將它們都放在內存中嗎? –

回答

1

你最好只是做:

bool anyItems = false; 
foreach (var item in items) { 
    anyItems = true; 
    // do stuff  
} 

這樣,你執行的查詢只有一次,而不是把所有的項目到內存中一次。如果您不需要知道是否有物品 - 您可以刪除anyItems標誌。

如果你需要處理之前的項目做一些事情 - 做環路上的第一次迭代,處理第一個項目之前:

bool firstItem = true; 
foreach (var item in items) { 
    if (firstItem) { 
     // do something, but only if there are items 
     firstItem = false; 
    } 
    // handle item   
} 

如果這將會提供多少好處,取決於你的情況。如果您不希望成千上萬的項目 - 您可以使用ToList。如果您希望很多這些查詢返回0個項目 - 您可能更願意執行Any查詢,但前提是它們要快得多(您應該自己測量)。如果您不希望大多數查詢返回0個項目 - 最好始終使用此方法(或ToList)來保存一個數據庫查詢。

+0

這是爲什麼被拒絕投票?這是一個有效的答案 –

+0

我認爲這並不是那麼簡單。在你的情況下,你總是執行返回GetItems查詢的查詢,該查詢可能很大且很慢。如果你只是想知道是否有任何記錄Any()或者你想知道查詢Count()中的行數,你應該使用這些方法,因爲它會執行不同的查詢,這可能會更快。所以這取決於你想達到的目標。 –

+0

@LukaszCokot但如果有項目,你會執行2個查詢。如果沒有額外的信息(例如沒有知道95%的時間沒有項目),你最好執行一個查詢。如果沒有項目 - 我不認爲獲取項目的查詢會比查詢得到它們的計數慢(這是0)。 – Evk

2

如果性能是至關重要的,你不希望將所有加載到內存中一次,你可以使用這種方法,並不需要執行查詢多次:如果你不

bool anyItems = false; bool firstItem = true; 
foreach (var item in items) 
{ 
    anyItems = true; 
    if(firstItem) 
    { 
     //do something, but only if there are items and only once 
     firstItem = false; 
    } 
    // do something with this item 
} 
if(anyItems) 
{ 
    //do something else, but only if there are items 
} 

不要期望你可以使用ToList許多項目,那麼你不需要關心多個AnyCount調用,你甚至可以訪問給定索引(for循環中的fe)的項目。

所以ToList成本的內存,但

  • 向你的項目的未連接snapshpot
  • 使你的代碼更易於閱讀
  • 能夠使用索引或一個for循環

使用IQueryable可以節省內存,但是可以節省內存但是

  • 給你總是當前狀態(items.Any可以產生不同的結果後)
  • 代碼是少可讀你可以看到上面
  • 就像是一個流,所以你不能使用一個for循環或索引
+0

OP需要代碼才能在迭代之前執行,但只有在有項目時纔會執行。用你的答案,可以通過在循環體的頂部添加一個'if(!anyItems){...}'來完成。在這種情況下,變量名變得有點誤導。 – hvd

+0

@hvd:我知道了,更正了,thx –

+1

使用foreach仍然執行像ToList這樣的整個查詢,所以你沒有保存任何內存或時間。它不會從數據庫中逐一檢索項目。對於來自@Evk的其他解決方案也是如此 –