我们的应用程序具有一个从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))
{
// ...
}
在调试,我发现,搜索根在很大程度上是相同的 - 即它们代表相同的域。
什么可能导致搜索速度减慢?