2017-07-27 56 views
0

我们的应用程序具有一个从Active Directory中获取所有用户并使用其信息更新相关SQL表的过程。这个过程在晚上是几年前编写的 - 所以这是传统的代码,它起作用,“如果它没有被破坏,不会修复它”。然而,我们正在向我们的应用程序引入一项新功能,该功能需要对此代码进行修改,并且由于多年来未触及它,所以我想我可能会稍微清理一下它。为什么DirectorySearcher与PrincipalSearcher相比如此缓慢?

上述过程只在夜间运行,除了罕见的服务器故障,在这种情况下,我们必须在白天手动运行它。这个过程使用好旧的System.DirectoryServices库来完成它的工作,尽管它有效,但它运行速度很慢。

我想过使用较新的System.DirectoryServices.AccountManagement库,而不是,所以我开始重写的整个过程(代码几百行),我很惊讶地看到,PrincipalSearcher大大优于DirectorySearcher

我一直在寻找原因,并发现the following SO answer它给出了两者之间的比较,说明DirectorySearcher应该比PrincipalSearcher更快。

我启动了一个测试项目,以确保我是不是产生了幻觉:

class Program 
{ 
    static void Main(string[] args) 
    { 
     // New stuff 
     var context = new PrincipalContext(ContextType.Domain, "mydomain.com"); 
     var properties = new[] { "cn", "name", "distinguishedname", "surname", "title", "displayname" }; 
     var i = 0; 
     var now = DateTime.Now; 

     new Thread(delegate() 
     { 
      while (true) 
      { 
       Console.Write("\r{0} ms, {1} results", (DateTime.Now - now).TotalMilliseconds, i); 
       Thread.Sleep(1000); 
      } 
     }).Start(); 

     using (var searcher = new PrincipalSearcher(new UserPrincipal(context))) 
     { 
      var underlying = searcher.GetUnderlyingSearcher() as DirectorySearcher; 
      underlying.PageSize = 1000; 
      underlying.PropertiesToLoad.Clear(); 
      underlying.PropertiesToLoad.AddRange(properties); 
      underlying.CacheResults = false; 

      using (var results = searcher.FindAll()) 
      { 
       foreach (var result in results) 
       { 
        i++; 
       } 
      } 
     } 

     Console.WriteLine("It took {0}", (DateTime.Now - now).TotalMilliseconds); 
     now = DateTime.Now; 
     i = 0; 

     // Old stuff 
     var root = new DirectoryEntry("LDAP://DC=mydomain,DC.com"); 
     var filter = "(&(objectCategory=user)(objectClass=user))"; 

     using (var searcher = new DirectorySearcher(root, filter, properties)) 
     { 
      searcher.PageSize = 1000; 
      searcher.CacheResults = false; 

      using (var results = searcher.FindAll()) 
      { 
       foreach (var result in results) 
       { 
        i++; 
       } 
      } 
     } 

     Console.WriteLine("It took {0}", (DateTime.Now - now).TotalMilliseconds); 
    } 
} 

查询几千用户,结果是各地的每用户0.9ms与PrincipalSearcher(约30秒〜34K用户)每用户约为5.2ms,用户数为DirectorySearcher(大约2分30秒约34k用户) - PrincipalSearcher几乎快了6倍。

我试着调试并比较了PrincipalSearcher的底层DirectorySearcher和我创建的那个,他们看起来非常相似。

我试图研究进一步的前进,似乎如果我使用搜索根从PrincipalSearcher的底层搜索,然后我竟然创造DirectorySearcher优于PrincipalSearcher

 // ... 

     DirectoryEntry psRoot; 

     using (var searcher = new PrincipalSearcher(new UserPrincipal(context))) 
     { 
      var underlying = searcher.GetUnderlyingSearcher() as DirectorySearcher; 
      psRoot = underlying.SearchRoot; 

      // ... 
     } 

     // ... 

     using (var searcher = new DirectorySearcher(psRoot, filter, properties)) 
     { 
      // ... 
     } 

在调试,我发现,搜索根在很大程度上是相同的 - 即它们代表相同的域。

什么可能导致搜索速度减慢?

回答

2

在写这个问题时,我正在修补测试代码并设法找到问题。通过提供构建根DirectoryEntry时域地址:

// var root = new DirectoryEntry("LDAP://DC=mydomain,DC.com"); 
var root = new DirectoryEntry("LDAP://mydomain.com/DC=mydomain,DC.com"); 

DirectorySearcher搜索跑赢说的PrincipalSearcher。我不确定为什么 - 也许这与搜索者寻找结果的位置有关 - 但它绝对提高了搜索速度。

相关问题