2010-03-01 3 views
4

데이터베이스에 저장된 날짜 이후에 사용자가 Windows에 로그인했는지 확인하는 유틸리티를 작성하려고합니다.Enumerable 개체에서 결과를 빠르게 찾습니다.

private void bwFindDates_DoWork(object sender, DoWorkEventArgs e) 
{ 
    UserPrincipal u = new UserPrincipal(context); 
    u.SamAccountName = "WebLogin*"; 
    PrincipalSearcher ps = new PrincipalSearcher(u); 
    var result = ps.FindAll(); 
    foreach (WebAccess.WebLoginUsersRow usr in webAccess.WebLoginUsers) 
    { 
     UserPrincipal b = (UserPrincipal)result. 
      Single((a) => a.SamAccountName == usr.WEBUSER); 
     if (b.LastLogon.HasValue) 
     { 
      if (b.LastLogon.Value < usr.MODIFYDATE) 
       usr.LastLogin = "Never"; 
      else 
       usr.LastLogin = b.LastLogon.Value.ToShortDateString(); 
     } 
     else 
     { 
      usr.LastLogin = "Never"; 
     } 
    } 
} 

그러나 성능이 매우 느립니다. 내가 당기는 사용자 목록은 약 150 명의 Windows 사용자가 있으므로 UserPrincipal b = (UserPrincipal)result.Single((a) => a.SamAccountName == usr.CONVUSER);은 사용자 당 완료하는 데 10-15 초가 걸립니다. (단계별로 진행되는 것을 볼 수 있습니다.) a.SamAccountName == usr.CONVUSE은 모든 사람을 위해 실행됩니다. 최악의 경우는 O (n^2) 회 실행 중임

효율성을 향상시키는 방법에 대한 권장 사항은 무엇입니까?

+2

코드 섹션에서 탭을 처리하는 데 때때로 somtimes가 좋아하는 것을 싫어합니다. –

답변

3

Single()은 아주 작은 목록에서 상당히 오래 걸리는 것이 놀랍습니다. 다른 일이 벌어지고있는 것 같아. ps.FindAll()에 대한 호출은 결과를 캐시하지 않는 개체를 반환 할 수 있으며 Single() 내의 각 반복마다 일부 리소스에 값 비싼 호출을해야합니다.

프로파일 러를 사용하여 해당 행에 도달 할 때 시간을 조사 할 수 있습니다. 또한 반복 수행하는 데 비정상적으로 비용이 많이 드는 것을 반환하기 때문에 FIndAll() 구현을 살펴볼 것을 제안합니다.

코드를 조금 더 자세히 읽고 나면, 왜 Single()이 그렇게 비싸게되는지 이해가됩니다. PrincipalSearcher 클래스는 디렉터리 서비스 저장소를 검색 대상 저장소로 사용합니다. 이 결과는 캐시되지 않습니다.. 그것이 귀하의 실적에 영향을 미칩니다.

ToList() 또는 ToDictionary()을 사용하여 목록을 구체화하여 주 정보에 로컬로 액세스 할 수 있습니다.

또한이 종류의 코드를 완전히 피할 수 있으며 대신 FindOne() 메서드를 사용하여 원하는 주체를 직접 쿼리 할 수 ​​있습니다. 당신이를 사용할 수없는 경우

그러나,이 같은 더 나은 작동합니다 :

result.ToDictionary(u => u.SamAccountName)[usr.WEBUSER] 
4

내가 제안 :

var result = ps.FindAll().ToList(); 

PrincipalSearchResult 때문에 다른 일처럼 캐시하지 않습니다,이 O (n) 성능 수준 근처로 내려갈 것입니다.

3
var userMap = result.ToDictionary(u => u.SamAccountName); 

foreach (WebAccess.WebLoginUsersRow usr in webAccess.WebLoginUsers) 
{ 
    UserPrincipal b = userMap[usr.WEBUSER]; 

    // ... 
} 
+0

나는 이것을 좋아한다. +1 – Randolpho

+0

'ToDictionary'는'Single'을 사용했기 때문에'WebLoginUsersRow'마다 정확하게 하나의 일치가 올 것이라는 것을 의미하기 때문에 사용했습니다. 필요한 경우 조정하십시오. – mquander

+0

감사합니다. 첫 번째 입장은 약 15 초, 나머지는 순간적으로 진행됩니다. –