2012-07-13 5 views
0

데이터베이스에서 비즈니스 모델 엔터티를 가져온 다음 문자열을 검색하기 위해 반복합니다. 그러나 내 로컬 호스트에서이 작업은 약 7 to 9 seconds for 500 objects 걸립니다.데이터베이스에서 가져온 모델 개체의 Clowing 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 루프는 폴더에 액세스하는 동안 더 이상 db 호출을하지 않아야합니다. 또한 .Include 방법을 점검하고 잘 작동합니다.

이 느린 반복의 원인은 무엇입니까?

감사합니다.

+0

ToList 또는 FirstOrDefault입니다. 왜 둘 다 필요하니? Parallel.ForEach를 사용하지 않는 이유는 무엇입니까? – Dimitri

+0

ToList를 삭제했습니다. Parallel.ForEach는 절대로 사용하지 않겠지 만, 고려해 보겠지 만 단지 500 개의 객체에 대해서는 너무 많이 사용하지 않습니까? –

+0

이것이 실행되는 기계의 사양은 무엇입니까? – Dimitri

답변

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

기억하십시오, 이것은 linq입니다. 상황이 즉시 발생하지 않습니다. foreach()의 첫 번째 반복 전에 실제로 쿼리를 실행하지 않습니다. 이 쿼리 정말 느리다 무엇

는 진짜 문제가 dbSet의 "폴더"정의하는 방법이다이

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

입니다. FK 조인이 많이 내장되어 있습니까? 그렇다면 간단한 요청으로 전체 데이터베이스를 가져올 수 있습니다. 그것은 모두 "폴더"에 의존하는 것에 달려 있습니다.

foreach 루프를 건너 뛸 때 linq 줄에 "팝"하는 것을 볼 수 있기 때문에 디버거에서도이를 볼 수 있습니다.

+0

실제로 붙여 넣은 코드에는 OP가 수행하는 .ToList()가 포함되지 않습니다. .ToList()는 쿼리 실행을 강제 실행합니다. 그렇습니까? 적어도, Linq 2 SQL 않습니다. –

+0

@CB - 당연히 잘못된 코드를 보았을 것입니다. – Hogan

+0

아, 디미트리와 비슷합니다. 전적으로. –

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

+0

Linq가 반복보다 빠르다는 것을 발견했습니다. 그래서 나는 그것을 사용하도록 제안했다. – Dimitri

+0

감사합니다. – HatSoft

0

당신의 라인에 대해서 : 나는 추측하고있어

foreach (FileFolder f in folder.Folders) 

, 하지만 그것은 당신이 하나의 폴더 테이블을 가지고있는 것처럼 보입니다. 하위 폴더는 같은 테이블에 저장되며, ID는 다시 t로 연결됩니다 o FK 관계를 사용하는 부모 ID? 깊은 폴더 계층 구조를 가지고 있다면, 부모는 자식 링크, 자식 링크, 자식 링크 등으로 인해 재귀 문제로 끝날 것입니다. EF (EF에 익숙하지 않은)가 어떻게 처리 할 지 모르겠습니다. ,하지만 내 추측은 그것이 문제가있는 곳입니다.

+0

예. 내 스키마가 정확히 그런 것 같습니다. 그러나, 내 메서드는 재귀 적으로 실행되지 않습니다, 그것은 단지 하나의 폴더의 폴더를 확인합니다. –

+0

저는 EF가 당신을 "도우 려"하고 스스로하기 위해 노력하고 있는지 확실하지 않았습니다. 그 특별한 루프가 왜 그렇게 느린지에 대한 나의 유일한 추측이었습니다. 행운을 빌어 요! –

관련 문제