You want to use the STATS LDAP control to test the efficiency of a query.
22.214.171.124 Using a graphical user interface
The STATS control is a useful way to obtain statistics about the performance of an LDAP query. With the STATS control, you can find out information, such as the amount of time it took the server to process the query, how many entries were visited versus returned, what the search filter expanded to, and if any indexes were used. Here is an example of what the STATS control returns for a search for all group objects in the cn=Users container:
***Searching . . . ldap_search_ext_s(ld, "cn=users,DC=rallencorp,DC=com", 2, "(objectcategory=group)", attrList, 0, svrCtrls, ClntCtrls, 20, 1000 ,&msg) Result <0>: Matched DNs: Stats: Call Time: 10 (ms) Entries Returned: 17 Entries Visited: 17 Used Filter: (objectCategory=CN=Group,CN=Schema,CN=Configuration,DC=rallencorp,DC=com) [RETURN] Used Indexes: INTERSECT_INDEX:17:I;
A couple things are worth noting here. First, the search visited only 17 entries and ended up returning all 17. In terms of the definitions defined in Recipe 15.8, this query is both inexpensive and efficient. You can also see that the filter that I used, (objectcategory=group), was expanded to (objectCategory=CN=Group,CN=Schema, CN=Configuration,DC=rallencorp,DC=com). The syntax of the objectCategory attribute is a distinguished name, but Active Directory provides a shortcut so that you need to use only the LDAP display name of the class instead. Internally, Active Directory converts the display name to the distinguished name, as shown here. Finally, we can see that our search used an index INTERSECT_INDEX:17:I.
Let's look at another example, except this time I'll perform an ANR search for "Jim Smith":
***Searching . . . ldap_search_ext_s(ld, "ou=Sales,DC=rallencorp,DC=com", 2, "(anr=Jim Smith)", attrList, 0, svrCtrls, ClntCtrls, 20, 1000 ,&msg) Result <0>: Matched DNs: Stats: Call Time: 20 (ms) Entries Returned: 1 Entries Visited: 2 Used Filter: ( | (displayName=Jim Smith*) (givenName=Jim Smith*) (legacyExchangeDN=Jim Smith) (msDS-AdditionalSamAccountName=Jim Smith*) (physicalDeliveryOfficeName=Jim Smith*) (proxyAddresses=Jim Smith*) (name=Jim Smith*) (sAMAccountName=Jim Smith*) (sn=Jim Smith*) ( & (givenName=Jim*) (sn=Smith*) ) ( & (givenName=Smith*) (sn=Jim*) ) ) Used Indexes: idx_givenName:10:N;idx_givenName:10:N;idx_sn:9:N;idx_ sAMAccountName:8:N;idx_name:7:N;idx_proxyAddresses:6:N;idx_ physicalDeliveryOfficeName:5:N;idx_msDS-AdditionalSamAccountName:4:N;idx_ legacyExchangeDN:3:N;idx_givenName:2:N;idx_displayName:1:N;
You can see from the second line that I used a very simple filter (anr=Jim Smith). If you look down a little farther at "Used Filter:" you can see a better example of search filter expansion. Like the objectCategory example earlier, ANR is a shorthand way to do something complex. A simple one-term search filter expands into a multiterm filter that searches across numerous attributes. For more on the behavior of ANR, see Recipe 10.13. The point of showing this is that the STATS control is very powerful and can be an invaluable tool when trying to troubleshoot or optimize LDAP queries.
15.9.4 See Also
Recipe 4.3 for using a LDAP controls, Recipe 4.5 for searching for objects, Recipe 10.13 for more on ANR, and Recipe 15.8 for more on expensive and inefficient searches