Post ten dotyczy tematu efektywnego pobierania danych z Active Directory. Załóżmy, że chcemy pobrać listę użytkowników przy czym interesują nas tylko niektóre właściwości, które ich opisują. Pokażę trzy niewiele różniące się z pozoru sposoby odczytania potrzebnych nam danych. Pozornie ponieważ te trzy podejścia znacząco różnią się wydajnością. W celu zademonstrowania różnic napisałem prostą klasę ADTester. Zawiera ona tylko jedną metodę Run w parametrach, której określamy tryb działania oraz liczbę obiektów do pobrania. Różnica pomiędzy trybami jest następująca:
W najlepszym przypadku tryb prosty jest 2.7 szybszy niż tryb normalny i prawie 60 razy szybszy niż tryb wolny. Różnica jest wręcz powalająca, a wnioski nasuwają się same.
- W trybie szybkim (Mode.Fast) dla każdego obiektu z bazy danych Active Directory pobrane zostają tylko wybrane 4 właściwości, a to dzięki zastosowaniu właściwości DirectorySearcher.PropertiesToLoad
- W trybie normalnym (Mode.Normal) dla każdego obiektu z bazy danych Active Directory pobrane zostają wszystkie dostępne dla danego obiektu właściwości.
- W trybie wolnym (Mode.Slow) zamiast użyć danych zawartych w obiektach SearchResult korzystam z metody SearchResult.GetDirectoryEntry.
maxNumberOfObjects | Mode.Fast | Mode.Normal | Mode.Slow |
100 | 363 | 463 | 7507 |
200 | 407 | 661 | 1600 |
500 | 797 | 2212 | 39323 |
1000 | 1353 | 3060 | 75935 |
W najlepszym przypadku tryb prosty jest 2.7 szybszy niż tryb normalny i prawie 60 razy szybszy niż tryb wolny. Różnica jest wręcz powalająca, a wnioski nasuwają się same.
- Jeśli z góry wiemy jakie właściwości nas interesują to używajmy właściwości DirectorySearcher.PropertiesToLoad.
- Korzystajmy z danych zwróconych przez klasę DirectorySearcher w postaci obiektów SearchResult.
- Tylko jeśli to absolutnie konieczne korzystajmy z metody SearchResult.GetDirectoryEntry. Taka potrzeba zachodzi na przykład wtedy jeśli chcemy zmodyfikować dane w AD.
public class ADTester { public enum Mode { Fast, Normal, Slow } public void Run(Mode mode, int maxNumberOfObjects) { var ldapPath = "YOUR_LDAP_PATH"; using (var root = new DirectoryEntry(ldapPath)) { using (var searcher = new DirectorySearcher(root) { Filter = "(&(objectClass=user))", SearchScope = SearchScope.Subtree, SizeLimit = maxNumberOfObjects }) { if (mode == Mode.Fast) searcher.PropertiesToLoad.AddRange(new[]{ "displayName","name", "pwdLastSet","userAccountControl" }); using (SearchResultCollection searchResult = searcher.FindAll()) { foreach (SearchResult user in searchResult) { if (mode != Mode.Slow) { var displayName = user.Properties["displayName"]; ... } else { var entry = user.GetDirectoryEntry(); var displayName = entry.Properties["displayName"]; ... } } } } } } }