2012-07-13 10 views
0

我想從數據庫中獲取業務模型實體,然後迭代它們以搜索字符串。但是,在我的本地主機上,該操作大約需要7 to 9 seconds for 500 objects從數據庫中取出的模型對象緩慢的C#迭代

public List<FileFolder> SearchFolders(int id, string searchString) 
{ 
    /* Placeholder that references folders that passes search criteria */ 
    List<FileFolder> addedFolders = new List<FileFolder>(); 

    /* Get the folder with specified id, also include Folders 
    * that this folder has. No problem here works perfectly fine 
    * and fast */ 
    FileFolder folder = dbSet.Include("Folders"). 
          .Where(q => q.FileFolderID == id) 
          .ToList().FirstOrDefault(); 

    /* This takes too much time as I mention, up to 9 seconds 
    * for 500 Folders */ 
    foreach (FileFolder f in folder.Folders) 
    { 
     if (f.Name.Contains(searchString)) 
     { 
      addedFolders.Add(f); 
     } 

    } 
    return addedFolders; 
} 

我將我提取的數據轉換爲List,所以我可以安全地說所有的數據現在在內存中?所以foreach循環不應該在訪問文件夾時進行更多的數據庫調用。我也檢查了.Include方法,它工作正常。

這種緩慢的迭代可能是什麼原因?

謝謝。

+0

其ToList或FirstOrDefault。你爲什麼需要兩個?另外爲什麼不使用Parallel.ForEach? – Dimitri 2012-07-13 23:58:33

+0

我刪除了ToList謝謝。從來沒有使用過Parallel.ForEach,我會考慮它,但不是它只需要太多的500個對象? – 2012-07-14 00:02:23

+0

該機器執行的規格是什麼? – Dimitri 2012-07-14 00:04:11

回答

0
/* This takes too much time as I mention, up to 9 seconds 
* for 500 Folders */ 

請記住,這是linq。事情不會馬上發生。在foreach()的第一次迭代之前,它實際上並未開始運行查詢。

什麼是這個查詢很慢,這是

FileFolder folder = dbSet.Include("Folders"). 
         .Where(q => q.FileFolderID == id) 
         .FirstOrDefault(); 

真正的問題是dbSet的「文件夾」是如何定義的。你有很多FK加入內置?如果是這樣的簡單請求可以拉你的整個數據庫。這一切都取決於什麼取決於「文件夾」。

你甚至可以在調試器中看到這一點,當你跨越foreach循環時,你會看到它「彈出」回linq行。

+0

實際上,你粘貼的代碼不包括OP的.ToList()。 .ToList()將強制執行查詢,是嗎?至少,它在Linq 2 SQL中有效。 – 2012-07-14 04:19:25

+0

@CB - 當然是的,我一定看過錯誤的代碼。 – Hogan 2012-07-14 05:01:19

+0

啊,像迪米特里的。完全。 – 2012-07-14 14:22:20

2

嘗試使用這種替代的foreach:

if (folder!=null) 
     { 
      addedFolders.AddRange(folder.Folders.Where(f=>f.Name.Contains(searchString))); 
     } 

完整的代碼會是這個樣子:

public List<FileFolder> SearchFolders(int id, string searchString) 
{ 
    /* Placeholder that references folders that passes search criteria */ 
    List<FileFolder> addedFolders = new List<FileFolder>(); 

    /* Get the folder with specified id, also include Folders 
    * that this folder has. No problem here works perfectly fine 
    * and fast */ 
    FileFolder folder = dbSet.Include("Folders"). 
          .Where(q => q.FileFolderID == id) 
          .FirstOrDefault(); 

    if (folder!=null) 
    { 
     addedFolders.AddRange(folder.Folders.Where(f=>f.Name.Contains(searchString))); 
    } 
    return addedFolders; 
} 
+0

請你可以詳細說明這將如何提高性能 – HatSoft 2012-07-14 00:09:15

+0

我發現Linq在某些情況下比迭代更快。所以我建議使用它。 – Dimitri 2012-07-14 00:10:59

+0

我同意你的答謝 – HatSoft 2012-07-14 00:11:44

0

關於你行:

foreach (FileFolder f in folder.Folders) 

我猜,但它看起來像是有一個文件夾表,其中子文件夾存儲在同一個表中,並且標識鏈接回t o使用FK關係的父母ID?如果你有一個深層次的文件夾層次結構,那麼當父母鏈接到孩子,鏈接到孩子,鏈接到孩子等等時,你可能最終會遇到遞歸問題。我不知道EF(不太熟悉EF)如何處理,但我的猜測是這就是問題所在。

+0

是的,我的模式就是這樣。但是,我的方法不會遞歸運行,它只檢查單個文件夾的文件夾。 – 2012-07-14 09:36:54

+0

我只是不確定EF可能試圖「幫助」你並自己做一些事情。這是我唯一的猜測,爲什麼這個特定的循環如此瘋狂緩慢。祝你好運! – 2012-07-14 14:21:36

相關問題