【发布时间】:2017-07-27 17:55:50
【问题描述】:
我们的应用程序有一个从 Active Directory 获取所有用户并使用他们的信息更新相关 SQL 表的过程。晚上的过程,它是几年前写的——所以它是有效的遗留代码,“如果它没有坏,就不要修复它”。然而,我们正在向我们的应用程序引入一项新功能,该功能需要修改此代码,并且由于多年未触及它,我想我不妨稍微清理一下。
所述进程仅在夜间运行,除了罕见的服务器故障,在这种情况下,我们必须在白天手动运行它。该过程使用良好的旧 System.DirectoryServices 库来完成它的工作,虽然它可以工作,但运行速度很慢。
我考虑改用较新的 System.DirectoryServices.AccountManagement 库,所以我开始重写整个过程(几百行代码),我惊讶地发现 PrincipalSearcher 大大 优于 @ 987654325@.
我一直在寻找原因,发现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);
}
}
查询数千名用户,结果是PrincipalSearcher 每位用户大约 0.9 毫秒(约 34k 用户约 30 秒)和DirectorySearcher 每位用户约 5.2 毫秒(约 34k 用户约 2 分 30 秒) ) - PrincipalSearcher 几乎快了六倍。
我尝试调试并将PrincipalSearcher 的底层DirectorySearcher 与我创建的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))
{
// ...
}
在调试时我发现搜索根在很大程度上是相同的 - 即它们代表同一个域。
什么会导致搜索速度这样变慢?
【问题讨论】:
标签: c# active-directory