2017-10-18 15 views
0

약 5,000 개의 행이있는 데이터베이스가 있습니다. 또한 많은 다 대다 관계가 있습니다. "고급 검색"쿼리의 일부로 테이블에서 자유 텍스트 검색을 수행해야합니다.강력한 형식의 데이터 집합에 대해 느린 LINQ 쿼리

앱을 시작할 때 강력하게 형식화 된 데이터 집합을 만들고 SQL Server에서 모든 데이터를 가져 왔습니다. 데이터 집합에 대해 LINQ 쿼리를 수행하면 쿼리가 매우 느리게 실행됩니다 (약 15 초). 메모리 내 데이터 집합에 대해 쿼리를 실행하는 것이 SQL Server보다 훨씬 빠를 것이라고 생각했지만 그럴 수는 없습니다. Where 조인에 더 많은 조인과 "검색"을 추가해야하기 때문에 상황이 더 악화 될뿐입니다.

내가 검색하는 필드에서 가장 긴 것은 요약이며 데이터베이스에서 가장 긴 것은 2,000 바이트 미만이므로 검색 할 데이터가 많지 않습니다. 여기에 잘못된 트리를 사용하고 있습니까? 아니면이 쿼리의 성능을 향상시킬 수있는 방법이 있습니까?

var results = from e in _data.ds.Employee 
     join es in _data.ds.EmployeeSkill on e.EmployeeId equals es.EmployeeId into esGroup from esItem in esGroup.DefaultIfEmpty() 
     join s in _data.ds.Skill on esItem?.SkillId equals s.SkillId into sGroup from skillItem in sGroup.DefaultIfEmpty() 
     join er in _data.ds.EmployeeRole on e.EmployeeId equals er.EmployeeId into erGroup from erItem in erGroup.DefaultIfEmpty() 
     join r in _data.ds.Role on erItem?.RoleId equals r.RoleId into rGroup from rItem in rGroup.DefaultIfEmpty() 
     join et in _data.ds.EmployeeTechnology on e.EmployeeId equals et.EmployeeId into etGroup from etItem in etGroup.DefaultIfEmpty() 
     join t in _data.ds.Technology on etItem?.TechnologyId equals t.TechnologyId into tGroup from tItem in etGroup.DefaultIfEmpty() 
     where 
     e.FirstName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
     e.LastName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
     e.RMMarket.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
     !e.IsSummaryNull() && e.Summary.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 
     select new SearchResult 
     { 
      EmployeeId = e.EmployeeId, 
      Name = e.FirstName + " " + e.LastName, 
      Title = e.Title, 
      ImageUrl = e.IsImageUrlNull() ? string.Empty : e.ImageUrl, 
      Market = e.RMMarket, 
      Group = e.Group, 
      Summary = e.IsSummaryNull() ? string.Empty : e.Summary.Substring(1, e.Summary.Length < summaryLength ? e.Summary.Length - 1 : summaryLength), 
      AdUserName = e.AdUserName 
     }; 
+2

"메모리 내"LINQ는 수년 간의 RA/SQL 최적화 및 통계 수집/쿼리 계획 선택의 이점을 누리지 못합니다. 예 : IndexOf를 통해 '인덱스 찾기'를 수행 할 수있는 기회가 없다고 상상해보십시오. SQL Server-LINQ는 (string.Contains를 통해) 수행 할 수 있습니다. – user2864740

+0

LINQ는 조인을 조회 테이블로 변환하므로 상대적으로 많은 작업량에도 불구하고 여전히 조속해야합니다. 속도가 느린 경우 데이터 세트 사용과 거의 관련이 있습니다. –

+2

데이터를'DataSet's에 로딩하고 쿼리와 함께 동적으로'join'하는 대신에 POCO (그냥 클래스를 생성)를 사용하고로드시'join'을 미리 실행하는 것을 고려하십시오. 조회 할 때마다 조회 테이블을 작성하십시오. 또한 이것을 Code Review로 전환하는 것을 고려할 수도 있습니다. – NetMage

답변

1

대신 객체 목록 (그 부분을 번역하는 것만으로는 충분하지 정보)의이야, 여기에 내가 제안 것입니다 :

var searchBase = (from e in _data.ds.Employee 
      join es in _data.ds.EmployeeSkill on e.EmployeeId equals es.EmployeeId into esGroup 
      from esItem in esGroup.DefaultIfEmpty() 
      join s in _data.ds.Skill on esItem?.SkillId equals s.SkillId into sGroup 
      from skillItem in sGroup.DefaultIfEmpty() 
      join er in _data.ds.EmployeeRole on e.EmployeeId equals er.EmployeeId into erGroup 
      from erItem in erGroup.DefaultIfEmpty() 
      join r in _data.ds.Role on erItem?.RoleId equals r.RoleId into rGroup 
      from rItem in rGroup.DefaultIfEmpty() 
      join et in _data.ds.EmployeeTechnology on e.EmployeeId equals et.EmployeeId into etGroup 
      from etItem in etGroup.DefaultIfEmpty() 
      join t in _data.ds.Technology on etItem?.TechnologyId equals t.TechnologyId into tGroup 
      from tItem in etGroup.DefaultIfEmpty() 
      select new { 
       e.FirstName, e.LastName, e.RMMarket, e.Summary, 
       e.EmployeeID, e.Title, e.ImageUrl, e.Group, e.AdUserName 
      }).ToList(); 
:

Prejoin에게 데이터가 검색 인덱스로 사용

이로드에 대한 검색을 실행하고 데이터에 가입 : BTW

var results = from e in searchBase 
      where 
       e.FirstName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
       e.LastName.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
       e.RMMarket.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 || 
       !e.IsSummaryNull() && e.Summary.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase) >= 0 
      select new SearchResult { 
       EmployeeId = e.EmployeeId, 
       Name = e.FirstName + " " + e.LastName, 
       Title = e.Title, 
       ImageUrl = e.IsImageUrlNull() ? string.Empty : e.ImageUrl, 
       Market = e.RMMarket, 
       Group = e.Group, 
       Summary = e.IsSummaryNull() ? string.Empty : e.Summary.Substring(1, e.Summary.Length < summaryLength ? e.Summary.Length - 1 : summaryLength), 
       AdUserName = e.AdUserName 
      }; 

를, 샘플 코드는이 조의 없음으로 결합 할 수있는 이유를 보여줍니다 범위 변수에서 조건이나 해답을 사용하고 있으며, 어쨌든 각각에 합류하게되므로 빠져 나가는 것이 가장 빠를 것입니다.

1

일부의 생각 :

먼저 검색하는 문자열

여기에 코드입니다. 검색 할 항목이 많으면 속도를 높이기 위해 전체 텍스트 인덱스를 유지 관리하는 것이 좋습니다.

두 번째로 join 절 앞에 where 절을 넣습니다. 데이터를 필터링하는 것은 LINQ 문에서 가능한 한 높게 설정해야합니다. 현재 where 절이 false 인 경우 사용되지 않는 곳에서도 모든 행에 대해 많은 데이터가 합쳐집니다. 당신은 여전히 ​​DataSet에로드 가정