У меня есть цикл, который извлекает некоторую информацию из 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 вернуть все нужные свойства за один раз (он пропускает около 30% свойств, указанных в PropertiesToLoad (также пытался установить его в конструкторе, который не делает разница), я обнаружил, что у кого-то еще была такая же проблема, и это его решение (для циклического их). Когда я перебираю их таким образом, используя FindOne() или FindAll(), я получаю все свойства, но на самом деле все это похоже на обходной путь.
Я что-то упускаю?
Редактировать:
Похоже, проблема была в том, как я получил первый DirectoryEntry, для которого я использовал DirectorySearcher.
Это был код, из-за которого 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");
}
Теперь для получения всех требуемых свойств 31 записи требуется менее одной 18-й секунды. Итак, кажется, что два разных экземпляра одного и того же 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);
Так что это дает немного больше понимания, но на самом деле мало что объясняет.