You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过DirectoryServices高效查询Active Directory指定字段的去重值?

高效获取Active Directory指定字段去重值的优化方案

原代码的性能瓶颈在于遍历所有AD记录后,用List(Of String).Contains做线性去重判断,数据量大时效率极低;同时上层封装的DirectorySearcher在处理海量数据时不如底层API高效。以下是针对性的优化方案:

方案1:优化内存去重逻辑(快速见效)

将List(Of String)替换为HashSet(Of String),利用其O(1)的查找性能大幅提升去重效率,同时保留原查询逻辑:

Public Function GetAllCountries() As List(Of String)
    Dim searcher As DirectorySearcher = ActiveDirectory.Forest.GetCurrentForest.FindGlobalCatalog.GetDirectorySearcher
    Dim searchResults As SearchResultCollection
    Dim countrySet As New HashSet(Of String)
    Dim country As String

    Try
        With searcher
            ' 使用更精准的过滤器,objectCategory为索引属性,查询更快
            .Filter = "(&(objectCategory=person)(objectClass=user)(co=*))"
            .PageSize = 1000
            .SizeLimit = 0
            .SearchScope = SearchScope.Subtree
            .CacheResults = False
            .PropertiesToLoad.Add("co")
            searchResults = .FindAll
        End With

        For Each result As SearchResult In searchResults
            country = GetPropertyValue(result.Properties("co")).SingleItem
            ' HashSet自动处理去重,无需手动判断Contains
            countrySet.Add(country)
        Next

    Catch ex As Exception
        ' 建议添加异常日志,避免吞掉错误
    End Try

    ' 转换为List返回,保持原方法返回类型一致
    Return countrySet.ToList()
End Function

方案2:使用底层DirectoryServices.Protocols提升查询性能

System.DirectoryServices.Protocols是更底层的LDAP操作API,比DirectorySearcher性能更高,适合处理大量AD数据:

Imports System.DirectoryServices.Protocols
Imports System.Net

Public Function GetAllCountriesWithSDS() As List(Of String)
    Dim countrySet As New HashSet(Of String)
    ' 获取全局编录的LDAP地址(默认端口3268)
    Dim gcServer As String = ActiveDirectory.Forest.GetCurrentForest.FindGlobalCatalog.Name & ":3268"
    Dim ldapConn As New LdapConnection(gcServer)
    ldapConn.AuthType = AuthType.Negotiate ' 使用当前上下文认证

    Try
        ' 构建LDAP查询请求
        Dim searchRequest As New SearchRequest(
            "", ' 全局编录的根节点为空
            "(&(objectCategory=person)(objectClass=user)(co=*))",
            SearchScope.Subtree,
            New String() {"co"} ' 仅请求需要的co属性
        )
        ' 启用分页,每页1000条
        searchRequest.Controls.Add(New PageResultRequestControl(1000))

        Dim response As SearchResponse = CType(ldapConn.SendRequest(searchRequest), SearchResponse)

        ' 处理分页结果
        Do
            For Each entry As SearchResultEntry In response.Entries
                If entry.Attributes.Contains("co") Then
                    Dim country As String = entry.Attributes("co").GetValues(GetType(String))(0)
                    countrySet.Add(country)
                End If
            Next

            ' 获取下一页的分页控件
            Dim pageControl As PageResultResponseControl = CType(response.Controls.Find(Function(c) c.Type = "1.2.840.113556.1.4.319"), PageResultResponseControl)
            If pageControl Is Nothing OrElse pageControl.Cookie.Length = 0 Then
                Exit Do
            End If

            ' 更新分页Cookie,请求下一页数据
            searchRequest.Controls.Remove(searchRequest.Controls.Find(Function(c) c.Type = "1.2.840.113556.1.4.319"))
            searchRequest.Controls.Add(New PageResultRequestControl(1000, pageControl.Cookie))
            response = CType(ldapConn.SendRequest(searchRequest), SearchResponse)
        Loop

    Catch ex As Exception
        ' 添加自定义异常处理逻辑
    Finally
        ldapConn.Dispose()
    End Try

    Return countrySet.ToList()
End Function

额外优化建议

  • 限定查询范围:如果无需跨域查询,直接连接本地域控制器(而非全局编录),减少数据传输量。
  • 启用AD字段索引:通过AD架构管理工具为co字段启用索引,大幅提升AD端的查询速度。
  • 最小化返回属性:仅请求需要的字段,避免返回不必要的数据,降低传输和解析开销。

内容的提问来源于stack exchange,提问作者Alan O'Brien

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 17:50:28