Unsere Anwendung verfügt über einen Prozess, der alle Benutzer aus Active Directory abruft und die relevanten SQL-Tabellen mit ihren Informationen aktualisiert. Der Prozess in der Nacht und es wurde vor ein paar Jahren geschrieben - so ist es Legacy-Code, der funktioniert und "wenn es nicht kaputt ist, repariere es nicht". Wir führen jedoch eine neue Funktion in unsere Anwendung ein, die Änderungen an diesem Code erfordert, und da sie seit Jahren nicht mehr berührt wurde, dachte ich, ich könnte sie genauso gut aufräumen.Warum ist DirectorySearcher im Vergleich zu PrincipalSearcher so langsam?
Dieser Prozess läuft NUR während der Nacht mit Ausnahme von seltenen Serverfehlern, in diesem Fall müssen wir es manuell während des Tages ausführen. Der Prozess verwendet die gute alte System.DirectoryServices
-Bibliothek, um seine Arbeit zu erledigen, und obwohl es funktioniert, läuft es ziemlich langsam.
Ich dachte über die neuere System.DirectoryServices.AccountManagement
Bibliothek statt verwenden, so begann ich den gesamten Prozess Umschreiben (ein paar hundert Zeilen Code) und ich war erstaunt zu sehen, dass PrincipalSearcher
dramatischDirectorySearcher
trifft.
Ich habe versucht, aus dem Grund zu suchen und kam auf the following SO answer, die einen Vergleich zwischen den beiden gibt, die besagt, dass DirectorySearcher
als PrincipalSearcher
schneller sein sollte.
ich ein Testprojekt gefeuert zu vergewissern, dass ich nicht halluziniert wurde:
class Program
{
static void Main(string[] args)
{
// New stuff
var context = new PrincipalContext(ContextType.Domain, "mydomain.com");
var properties = new[] { "cn", "name", "distinguishedname", "surname", "title", "displayname" };
var i = 0;
var now = DateTime.Now;
new Thread(delegate()
{
while (true)
{
Console.Write("\r{0} ms, {1} results", (DateTime.Now - now).TotalMilliseconds, i);
Thread.Sleep(1000);
}
}).Start();
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
var underlying = searcher.GetUnderlyingSearcher() as DirectorySearcher;
underlying.PageSize = 1000;
underlying.PropertiesToLoad.Clear();
underlying.PropertiesToLoad.AddRange(properties);
underlying.CacheResults = false;
using (var results = searcher.FindAll())
{
foreach (var result in results)
{
i++;
}
}
}
Console.WriteLine("It took {0}", (DateTime.Now - now).TotalMilliseconds);
now = DateTime.Now;
i = 0;
// Old stuff
var root = new DirectoryEntry("LDAP://DC=mydomain,DC.com");
var filter = "(&(objectCategory=user)(objectClass=user))";
using (var searcher = new DirectorySearcher(root, filter, properties))
{
searcher.PageSize = 1000;
searcher.CacheResults = false;
using (var results = searcher.FindAll())
{
foreach (var result in results)
{
i++;
}
}
}
Console.WriteLine("It took {0}", (DateTime.Now - now).TotalMilliseconds);
}
}
einige tausend Benutzer abfragen, waren die Ergebnisse um 0.9ms pro Benutzer mit PrincipalSearcher
(ca. 30 Sekunden für ~ 34k-Benutzer) und ungefähr 5,2 ms pro Benutzer mit DirectorySearcher
(ungefähr 2 Minuten und 30 Sekunden für ~ 34k Benutzer) - PrincipalSearcher
ist fast sechsmal schneller.
Ich versuchte Debugging und Vergleich der PrincipalSearcher
zugrunde liegenden DirectorySearcher
mit dem einen, den ich erstellt und sie schienen ziemlich ähnlich.
Ich versuchte weiter nach vorne zu prüfen und es scheint, dass, wenn ich die Suche Wurzel aus der PrincipalSearcher
‚s zugrunde liegenden Sucher verwenden, dann ist die DirectorySearcher
schaffe ich tatsächlich die PrincipalSearcher
trifft:
// ...
DirectoryEntry psRoot;
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
var underlying = searcher.GetUnderlyingSearcher() as DirectorySearcher;
psRoot = underlying.SearchRoot;
// ...
}
// ...
using (var searcher = new DirectorySearcher(psRoot, filter, properties))
{
// ...
}
während des Debuggens fand ich heraus, dass Die Suchwurzeln sind weitgehend gleich - dh sie repräsentieren die gleiche Domäne.
Was könnte die Suchgeschwindigkeit so verlangsamen?