我有一个从 ActiveDirectory 检索一些信息的循环。事实证明这是一个很大的性能瓶颈。
此代码段(在执行 31 次的循环内)耗时 00:01:14.6562500(1 分 14 秒):
SearchResult data = searcher.FindOne();
System.Diagnostics.Trace.WriteLine(PropsDump(data));
用此代码段替换它使其降至 00:00:03.1093750(3 秒):
searcher.SizeLimit = 1;
SearchResultCollection coll = searcher.FindAll();
foreach (SearchResult data in coll)
{
System.Diagnostics.Trace.WriteLine(PropsDump(data));
}
结果完全相同,相同的属性以相同的顺序返回。我在另一个线程中发现了一些关于内存泄漏的信息,但他们没有提到性能(我在 .Net 3.5 上)。
以下实际上是一个不同的问题,但它提供了一些背景,说明我为什么首先要循环:
我想在一个查询中获取所有属性,但我无法让 DirectorySearcher 一次性返回所有想要的属性(它省略了 PropertiesToLoad 中指定的大约 30% 的属性(也尝试在构造函数中设置它)区别),我发现其他人也有同样的问题,这是他的解决方案(循环遍历它们)。当我像这样循环遍历它们时,使用 FindOne() 或 FindAll() 我确实得到了所有属性,但实际上它一切都感觉像是一种解决方法。
我错过了什么吗?
编辑:
似乎问题出在我获得第一个使用 DirectorySearcher 的 DirectoryEntry 的方式上。
这是导致 DirectorySearcher 只返回一些属性的代码:
private static DirectoryEntry GetEntry() {
DirectoryContext dc = new DirectoryContext(DirectoryContextType.DirectoryServer, "SERVERNAME", "USERNAME", "PASSWORD");
Forest forest = Forest.GetForest(dc);
DirectorySearcher searcher = forest.GlobalCatalogs[0].GetDirectorySearcher();
searcher.Filter = "OU=MyUnit";
searcher.CacheResults = true;
SearchResultCollection coll = searcher.FindAll();
foreach (SearchResult m in coll)
{
return m.GetDirectoryEntry();
}
throw new Exception("DirectoryEntry not found");
}
仅用这一行替换了那一大口之后,DirectorySearcher 返回了所有属性并且不再需要循环:
private static DirectoryEntry GetEntry2()
{
return new DirectoryEntry(@"LDAP://SERVERNAME/OU=MyUnit,DC=SERVERNAME,DC=local", "USERNAME", "PASSWORD");
}
现在只需不到 18 分之一秒即可获得 31 个条目的所有所需属性。因此,似乎同一个 DirectoryEntry 的两个不同实例会根据其构建方式给出不同的结果……感觉有点毛骨悚然!
编辑
使用JetBrains DotPeek查看实现。FindOne 函数的开头是这样的:
public SearchResult FindOne()
{
SearchResult searchResult1 = (SearchResult) null;
SearchResultCollection all = this.FindAll(false);
...
我的第一反应是啊!难怪......但后来我注意到了这个论点。FindAll 有一个接受布尔值的私有版本,这是 FindAll 的开始:
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public SearchResultCollection FindAll()
{
return this.FindAll(true);
}
private SearchResultCollection FindAll(bool findMoreThanOne)
{
... // other code
this.SetSearchPreferences(adsSearch, findMoreThanOne);
因此,这提供了更多的见解,但并没有真正解释太多。