Active Directoryを照会し、表示名がフォーマット{displayName}のすべてのユーザーとグループを検索するC#でメソッドを作成しています(先頭と末尾にワイルドカード)、このメソッドはオートコンプリートフィールドに使用されます。ワイルドカードを使用したActive Directoryクエリのパフォーマンスが低い
問題は、私が書いたメソッドのパフォーマンスが非常に悪く、クエリの文字列に応じて30秒から1分の間に何かを取ります。
私の組織のADは非常に大きいですが、この時間がかかる場合、オートコンプリートフィールドは無意味です。ここで
私が今使っているコードです:
// Intialize the results list.
result.queryResult = new List<Classses.ADSearchObject>();
// Set up domain context.
PrincipalContext pc = new PrincipalContext(ContextType.Domain, Domain, Constants.adQueryUser, Constants.adQueryPassword);
// Set up a directory searcher.
DirectorySearcher dSearcher = new DirectorySearcher();
// Define a SearchCollection to store the results.
SearchResultsCollection searchCol;
// Define returned result paging for performance.
dSearcher.PageSize = 1000;
// Define the properties to retrieve
dSearcher.PropertiesToLoad.Add("sAMAccountName");
dSearcher.PropertiesToLoad.Add("displayName");
// Define the filter for users.
dSearcher.Filter = $"(|(&(displayName = {result.querystring}*)(objectCategory=person))(&(displayName=*{result.querystring})(objectCategory=person)))";
// Search based in filter and save the results.
searchCol = dSearcher.FindAll();
// Add the results to the returned object
foreach (SearchResult searchResult in searchCol)
{
DirectoryEntry de = searchResult.GetDirectoryEntry();
// Code to get data from the results...
}
// Define the filter for groups.
dSearcher.Filter = $"(|(&(displayName={result.querystring}*)(objectCategory=person))(&(displayName=*{result.querystring})(objectCategory=person)))";
// Search based in filter and save the results.
searchCol = dSearcher.FindAll();
// Add the results to the returned object
foreach (SearchResult searchResult in searchCol)
{
DirectoryEntry de = searchResult.GetDirectoryEntry();
// Code to get data from the results...
}
現在の検索はそれらを区別することが簡単にするために、ユーザーとグループに分かれていますが、それは、実質的にパフォーマンスを向上させた場合、私はそれらを統一します単一の検索。
編集:ユーザールネが示唆したように、私はFindAll
のにかかる時間を確認するためにStopwatch
を使用して、私はまた私のforeach
ループが取るどのくらい確認。
FindAll
コールは、ADによって索引付けされた先頭のワイルドカード(検索されない)で検索しても、約100ms(非常に高速)であることがわかりました。
明らかに、最も長くかかるコールは、私のforeach
ループで約40秒(40,000ms)かかります。
私はその性能を改善する方法を考え出したていないように私は私のforeach
ループ内のコードブロックで質問を更新しています:私は私の更新で私の「ストップウォッチ」を開始し、停止
// --- I started a stopwatch here
foreach (SearchResult searchResult in searchCol)
{
// --- I stopped the stopwatch here and noticed it takes about 30,000ms
result.code = 0;
DirectoryEntry de = searchResult.GetDirectoryEntry();
ADSearchObject adObj = new ADSearchObject();
adObj.code = 0;
if (de.Properties.Contains("displayName")
{
adObj.displayName = de.Properties["displayName"].Value.ToString();
}
adObj.type = "user";
result.queryResults.Add(adObj);
}
注意をコード、私はなぜループを開始するのがそんなに長いかわからない。
これはMicrosoftのADを扱うときの動作です。たぶん、ADツリーに何らかの種類のDBを同期させることで、毎回ADを照会するのではなく、ミリ秒単位でクエリを実行できるようになるかもしれません。 – r1verside
'(&(displayName = * {result.querystring} *)(objectCategory = person))'はあなたのフィルタと同じですか?そして 'FindAll'呼び出しをStopWatchできますか?それらは最も時間を取っていますか? – rene
@rene投稿に編集したものを見て、 'Stopwatch'から取り出した時間を追加しました。 –