问题描述
我们的应用程序具有一个从Active Directory中获取所有用户并使用其信息更新相关SQL表的过程。该过程是在几年前完成的,所以它是在几年前编写的,因此它的旧代码可以工作,并且如果没有损坏,请不要修复它。但是,我们正在向我们的应用程序引入一项新功能,该功能需要对此代码进行修改,并且由于多年没有被使用过,我想我也应该对其进行一些清理。
Our application has a process which fetches all users from Active Directory and updates the relevant SQL tables with their information. The process at nights and it was written a few years ago - so it's legacy code which works and "if it ain't broken, don't fix it". However we're introducing a new feature to our application which requires modifications to this code, and since it hasn't been touched for years I thought I might as well clean it up a little.
所说的进程仅在夜间运行,除了极少数的服务器故障外,在这种情况下,我们必须在白天手动运行。该过程使用了良好的旧 System.DirectoryServices
库来完成其工作,尽管它可以运行,但运行起来非常缓慢。
Said process runs ONLY during the night except for rare server faults, in which case we have to run it manually during the day. The process uses the good old System.DirectoryServices
library to do its job, and although it works, it runs quite slowly.
我考虑过使用更新的 System.DirectoryServices.AccountManagement
库,所以我开始重写整个过程(几百行代码),我对此感到惊讶看到 PrincipalSearcher
戏剧性优于 DirectorySearcher
。
I thought about using the newer System.DirectoryServices.AccountManagement
library instead, so I started rewriting the whole process (a few hundreds lines of code) and I was amazed to see that PrincipalSearcher
dramatically outperforms DirectorySearcher
.
我一直在寻找原因,并进行了比较两者之间,指出 DirectorySearcher
应该比 PrincipalSearcher
快。
I've been trying to look for the reason and came upon the following SO answer which gives a comparison between the two, stating that DirectorySearcher
should be faster than PrincipalSearcher
.
我启动了一个测试项目以确保自己不会产生幻觉:
I fired up a test project to make sure I was not hallucinating:
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
的每个用户(约30k用户约30秒),使用 DirectorySearcher
的每个用户约5.2ms分钟和30秒(约34000个用户))- PrincipalSearcher
快六倍。
Querying some thousand users, the results were around 0.9ms per user with PrincipalSearcher
(around 30 seconds for ~34k users) and around 5.2ms per user with DirectorySearcher
(around 2 minutes and 30 seconds for ~34k users) - PrincipalSearcher
being almost six times faster.
我尝试调试和比较 PrincipalSearcher
的基础 DirectorySearcher
与我创建的一个基础,它们看起来非常相似。
I tried debugging and comparing the PrincipalSearcher
's underlying DirectorySearcher
with the one I created and they seemed pretty much similar.
我尝试进一步检查,似乎如果使用 PrincipalSearcher
的基础搜索器的搜索根,则<$ c我创建的$ c> DirectorySearcher 实际上胜过 PrincipalSearcher
:
I tried examining further ahead and it seems that if I use the search root from the PrincipalSearcher
's underlying searcher, then the DirectorySearcher
I create actually outperforms the 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))
{
// ...
}
在进行调试时,我发现搜索根在很大程度上是相同的-即它们表示相同的域。
While debugging I found out that the search roots are largely the same - i.e., they represent the same domain.
是什么会导致搜索速度降低呢? ?
What could cause the search speed to slow down like this?
推荐答案
在撰写此问题时,我正在修改测试代码并设法找到了问题。通过在构造根 DirectoryEntry
时提供域名地址:
While writing this question I was tinkering with the test code and managed to find the issue. By providing the domain address when constructing the root DirectoryEntry
:
// var root = new DirectoryEntry("LDAP://DC=mydomain,DC=com");
var root = new DirectoryEntry("LDAP://mydomain.com/DC=mydomain,DC=com");
使用 DirectorySearcher
的搜索的效果优于 PrincipalSearcher
。我不确定为什么-也许与搜索者寻找结果的位置有关-但这确实提高了搜索速度。
The search with DirectorySearcher
outperformed that of PrincipalSearcher
. I'm not exactly sure why - perhaps it's something to do with where the searcher looks for the results - but it definitely boosted the search speed.
这篇关于与PrincipalSearcher相比,为什么DirectorySearcher这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!