Active Directory Directory foundations

Diagnose an expensive LDAP query

Connect a slow application request to event 1644, query statistics, indexing and the actual cost of returning the result.

Reproduce the query, not merely its filter

Save the target DC and port, bind identity and method, base DN, scope, filter, requested attributes, paging/sorting controls, client timeout and request rate. Two searches with the same filter can have very different costs if one searches an OU and the other searches a GC with every attribute requested.

Separate bind or TLS latency from search execution and from the time the client spends processing returned entries. If LDP completes the same search promptly while the application still stalls, compare its connection reuse, referral behavior, returned data and per-object follow-up queries before changing the DC.

Capture the slow interval

Directory Service event 1644 can report expensive, inefficient or long-running searches. The thresholds decide which requests get logged. If no event appears, check those settings and whether you reproduced the slow request during collection.

Read the current state locally on the selected DC:

$diagnostics = 'HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics'
$parameters = 'HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters'
Get-ItemProperty -LiteralPath $diagnostics -Name '15 Field Engineering'
Get-ItemProperty -LiteralPath $parameters |
    Select-Object 'Expensive Search Results Threshold',
        'Inefficient Search Results Threshold','Search Time Threshold (msecs)'

For a planned collection, record whether each registry value existed as well as its data. Enable Field Engineering level 5 and the appropriate query thresholds for a bounded period, with enough event-log capacity. A change to logging can produce substantial traffic; start with a threshold that isolates the symptom. Restore the exact previous configuration afterward, including removing a temporary threshold if it was originally absent. Microsoft’s logging procedure supplies the prerequisites and categories.

Get-WinEvent -FilterHashtable @{
    LogName = 'Directory Service'
    Id = 1644
    StartTime = (Get-Date).AddMinutes(-15)
} | Select-Object TimeCreated,MachineName,Message

Save the original EVTX. The Event1644Reader guide shows how to group results by caller, filter and cost. One terrible query and thousands of moderately costly queries may need different fixes.

Read the fields together

Evidence What it can suggest What it does not establish alone
Many entries visited, few returned Broad candidate set or a poorly selective access path That a new index is the best fix
Many entries returned The caller genuinely requested a large result That the query optimizer failed
High disk reads and latency A cold or oversized working set, or storage pressure That more CPU will help
Low search time, slow application response Bind, network, result transfer or client work That directory execution is the bottleneck
One fast query repeated continuously Excessive polling or connection/application design That per-request tuning alone is enough

Modern event fields can include the index used, pages referenced/read and search time. Availability varies with OS and updates; inspect the recorded fields rather than assuming an old event template. Microsoft’s search-statistics improvements explain their interpretation.

Start lower in the tree when the application owns a known OU. Ask only for attributes it consumes. Compare an exact or prefix match with a leading-wildcard substring search. Avoid retrieving a complete group membership list to answer whether one principal is a member.

Use LDP’s search statistics control to compare candidate and result counts. Request attribute 1.1 to test matching work without returning values, then repeat with the attributes the application actually needs. The cost of retrieving and transmitting large multivalues can make the second test quite different.

Use the same identity, replica and data set for each comparison. A second run may benefit from warm database and filesystem caches; retain both warm and cold observations when that matters to the application.

Indexes have specific jobs

An ordinary index can help equality and prefix searches. A tuple index can help a suitable substring search, but adds storage and maintenance work. ANR is its own configured attribute set. Bitwise and transitive matching rules also have their own cost; putting an indexed term somewhere in a filter does not guarantee a cheap access path.

Inspect the attribute definition before proposing a schema change:

$dc = 'dc1.contoso.com'
$schema = (Get-ADRootDSE -Server $dc).schemaNamingContext
Get-ADObject -Server $dc -SearchBase $schema -SearchScope OneLevel `
    -LDAPFilter '(lDAPDisplayName=description)' `
    -Properties searchFlags,isSingleValued,attributeSyntax |
    Select-Object Name,searchFlags,isSingleValued,attributeSyntax

See schema flags before modifying a forest-wide definition. An index is built locally on replicas and must be maintained on subsequent writes. Collect evidence from the actual query workload first.

Do not remove paging as a universal optimization

Paging retrieves objects in batches; range retrieval retrieves values of one multivalued attribute in slices. Sorting and paging can also affect query optimization. Microsoft’s AD LDS/ADAM paged-query case describes an indexed filter that still performs poorly. Check whether that case fits before disabling paging in an application.

An unpaged query may instead hit MaxPageSize and return an incomplete result. Confirm result codes, continuation cookies and the application’s behavior on partial failure before comparing timings. LDAP search mechanics covers those controls.

Prove the improvement at the workload level

Repeat the request and the application’s full transaction. Check that the results match, then compare elapsed time, entries visited/returned, disk activity and request frequency under normal load. A faster query can still leave the DC worse off if its index makes writes expensive or the application starts sending ten times as many requests.

← All Active Directory topics