Fog Creek Software
Discussion Board




Welcome! and rules

Joel on Software

Querying Active Directory takes an age

Hi,

I've written the code below to cycle through the results of a query to the (LDAP) active directory. The code works fine, except that it takes an absolute age to run - presumeably because each time I call a method it sends a query to the server across the network. Is there any way to speed this up?



Dim propertyName As String
For Each ldapResult In ldapResults
    Dim row = dt.NewRow()

    For Each propertyName In ldapResult.GetDirectoryEntry.Properties.PropertyNames()
        Dim val As String
        If ldapResult.GetDirectoryEntry.Properties(propertyName).Item(0).GetType Is GetType(String) Then
            'get value from directory entry
            val = CType(ldapResult.GetDirectoryEntry().Properties(propertyName)(0), String)

            'create column if it doesn't exist
            If dt.Columns.Contains(propertyName) Then
                row(propertyName) = val
            Else
                Dim column As DataColumn = New DataColumn(propertyName)
                column.DataType = System.Type.GetType("System.String")
                dt.Columns.Add(column)
                row(propertyName) = val
            End If
        End If
    Next

    dt.Rows.Add(row)
Next


Many thanks.

C O'Connor
Monday, January 17, 2005

Not sure if this is what you're looking for but, I found that fully qualifying the name of the AD server helped a lot with speed in my environment.

Hash550
Tuesday, January 18, 2005

ADSI and LDAP are slow. There's not much you can do about that. I have a test case that enumerates the users and groups in a very small domain -- about 2 dozen users, about 2 dozen groups -- and it takes 4 SECONDS to run.

We finally gave up doing real-time queries into LDAP. We periodically refresh a database with all the information about the domain; then we can write SQL queries against the database. Basically, it's the bare beginnings of what MIIS is, except it's one way (just what we needed).

Brad Wilson (dotnetguy.techieswithcats.com)
Wednesday, January 19, 2005

I've speeded it up a little by hardcoding in only the fields I need. It still takes about 40 seconds to return 300 users though.

I noticed that the same search (albeit only on one field) returns the same number of people in roughly 3 seconds when using 'search active directory' from My Network Places.

C O'Connor
Wednesday, January 19, 2005

You are calling GetDirectoryEntry too many times. Each call to GetDirectoryEntry takes time. In fact, the documentation for the method specifically mentions that calling GetDirectoryEntry on each SearchResult returned thorugh a DirectorySearcher can be slow, which is exactly what seems to be happenning in your code.

From your code, you seem to be populating a Datatable with the properties of each directory entry that your search returns. If you know ahead of time what properties you require, specify them at the time of instantiating the DirectorySearcher (via the PropertiesToLoad member). Then, read the properties from the SearchResult itself. This will be much faster than your approach.

If you do not know the properties you want, or want all the properties of the directory entry, call GetDirectoryEntry once, store it in a variable, and use the variable thereafter. For example:

For Each ldapResult In ldapResults

    Dim row As DataRow = dt.NewRow()

    Dim currentEntry As DirectoryEntry = _
        ldapResult.GetDirectoryEntry

    For Each propertyName In _
        currentEntry.Properties.PropertyNames()
       
       
etc. ALternatively, use the With statement for the same effect.

Mr. Wilson, ADSI and LDAP require a different approach than do databases. The idea is to specify as exact a query as possible, get all neccessary results in one operation, and process them disconnected. I struggled with this for a long time, but now I generally get results that are fast enough.

Raj Chaudhuri
Thursday, January 20, 2005

Worked like a charm. Thanks Raj.

C O'Connor
Thursday, January 20, 2005

<< ADSI and LDAP are slow. >>

Not all LDAP is slow.  Maybe AD is.  OpenLDAP is fast as blazes, for reads.  Updates are another story but directories are normally assumed to have a very high read-to-update ratio.

AMS
Friday, January 21, 2005

I have to agree with Raj Chaudhuri. The AD will not warn you if you make a poor query, it will just get slow. If you want to play around with LDAP, look for LDP.EXE. It's one of the support tools on your Windows Server CD. This tool will allow you to see how fast or slow your query is. With a fast query, the AD can return thousands of objects in a second. With a slow query... well, you know the answer to that.

Try to use indexed attributes in your LDAP filter. You can use MSDN to find which attributes are indexed.

If you need to search for hundreds of objects, try using paged searches. That way you can process some of the directory entries while the AD is looking up the rest.

Also, as Raj mentioned, be mindful of your API. Functions that have to talk directory have much more overhead than functions that stay on the box. Be sure to cache your results.

Harvey Rook
Monday, January 24, 2005

The biggest single downfall of LDAP via ADSI to AD for us is the lack of joins. It's not that any single query took a long time, but rather the sum total of the queries we needed to do to find all the information we needed was slow.

Brad Wilson (www.dotnetdevs.com)
Tuesday, January 25, 2005

*  Recent Topics

*  Fog Creek Home