C# 带有通配符的Active directory查询性能较差

C# 带有通配符的Active directory查询性能较差,c#,active-directory,ldap,ldap-query,C#,Active Directory,Ldap,Ldap Query,我正在用C#编写一个方法,它应该查询Active Directory并查找显示名称为{displayName}格式的所有用户和组(带前导和尾随通配符的通配符搜索),该方法将用于自动完成字段 问题是我编写的方法的性能非常差,根据查询字符串的不同,尝试查询AD需要30秒到整整一分钟的时间 我所在组织的广告非常大,但如果需要这么长时间,自动完成字段将毫无意义 以下是我现在使用的代码: // Intialize the results list. result.queryResult = new Lis

我正在用C#编写一个方法,它应该查询Active Directory并查找显示名称为{displayName}格式的所有用户和组(带前导和尾随通配符的通配符搜索),该方法将用于自动完成字段

问题是我编写的方法的性能非常差,根据查询字符串的不同,尝试查询AD需要30秒到整整一分钟的时间

我所在组织的广告非常大,但如果需要这么长时间,自动完成字段将毫无意义

以下是我现在使用的代码:

// Intialize the results list.
result.queryResult = new List<Classses.ADSearchObject>();

// Set up domain context.
PrincipalContext pc = new PrincipalContext(ContextType.Domain, Domain, Constants.adQueryUser, Constants.adQueryPassword);

// Set up a directory searcher.
DirectorySearcher dSearcher = new DirectorySearcher();
// Define a SearchCollection to store the results.
SearchResultsCollection searchCol;
// Define returned result paging for performance.
dSearcher.PageSize = 1000;
// Define the properties to retrieve
dSearcher.PropertiesToLoad.Add("sAMAccountName");
dSearcher.PropertiesToLoad.Add("displayName");
// Define the filter for users.
dSearcher.Filter = $"(|(&(displayName = {result.querystring}*)(objectCategory=person))(&(displayName=*{result.querystring})(objectCategory=person)))";

// Search based in filter and save the results.
searchCol = dSearcher.FindAll();

// Add the results to the returned object 
foreach (SearchResult searchResult in searchCol)
{
   DirectoryEntry de = searchResult.GetDirectoryEntry();
   // Code to get data from the results...
}

// Define the filter for groups.
dSearcher.Filter = $"(|(&(displayName={result.querystring}*)(objectCategory=person))(&(displayName=*{result.querystring})(objectCategory=person)))";

// Search based in filter and save the results.
searchCol = dSearcher.FindAll();

// Add the results to the returned object 
foreach (SearchResult searchResult in searchCol)
{
   DirectoryEntry de = searchResult.GetDirectoryEntry();
   // Code to get data from the results...
}

请注意,我在更新的代码中启动和停止“秒表”的位置,我不知道为什么开始循环需要这么长时间。

当然,子字符串匹配比唯一值的相等匹配成本更高。同样,这也不奇怪大部分的运行时间都落在了迭代器块中,根据您的评测,迭代器块总共消耗了40秒

如果您确信仅仅通过设置一个迭代器,性能就会出现巨大的下降,那么我不是——这是因为您选择了计时点

StartClock("foreach");
foreach (SearchResult searchResult in searchCol)
{
    // use an empty block to speed things up or
    StopClock("foreach");
    // whatever
    RestartClock("foreach");
}
StopClock("foreach");
LogClock("foreach");

如果你注意到我已经评论过的一个最佳实践,我预计会有巨大的性能提升(对于大量条目),那就是:向服务器发送一个请求,接收搜索结果中所需的所有内容,而不要为每个条目发送另一个请求。虽然对GetDirectoryEntry()的一次调用只会使用它,但这是处理Microsoft AD时的工作方式。也许您可以考虑将AD树与某种数据库同步,使您可以在毫秒内执行查询,而不是每次都查询AD。
(&(displayName=*{result.querystring}*)(objectCategory=person))
和你的过滤器一样吗?你能秒表
FindAll
调用吗?这些调用占用的时间最多吗?@rene请看我对帖子的编辑,我添加了从
StopWatch
我在代码的不同部分打开的时间,只需一次调用
FindAll()
。不要使用
GetDirectoryEntry()
无理由地一个接一个地检索完整条目。难怪你老盯着屏幕看。@marabu请参阅我的编辑,当进入
foreach
循环时,性能会受到影响。在首次进入循环后,性能与你预期的一样快,并且调用
GetDirectoryEntry()
不需要特别长的时间
StartClock("foreach");
foreach (SearchResult searchResult in searchCol)
{
    // use an empty block to speed things up or
    StopClock("foreach");
    // whatever
    RestartClock("foreach");
}
StopClock("foreach");
LogClock("foreach");
(&(objectCategory=person)(displayName=*{result.querystring}*))