与 PrincipalSearcher 相比,为什么 DirectorySearcher 如此

时间:2023-02-18
本文介绍了与 PrincipalSearcher 相比,为什么 DirectorySearcher 如此缓慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的应用程序有一个从 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.

我一直在试图寻找原因并发现了以下 SO 答案,它给出了二,声明 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("
{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 几乎快了六倍.

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 的底层搜索器的搜索根,那么我创建的 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 如此缓慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!

上一篇:特定 Active Directory 通讯组中的用户列表 下一篇:如何在 C# 中通过 LDAPS 连接到 Active Directory?

相关文章

最新文章