[AD/ADAM] 10000件以上のデータが登録された環境でサーバソートすると 0x8007202C (3)/4 – DirectorySearcher.VirtualListView

みなさんごきげんよう、ういこです。
これまでは、大量データ保持の AD / ADAM に対してソートを行う際の問題についてお伝えしてまいりました。今回は、回避策として、Virtual List View が使えるか?という内容です。

【問題】 10000 件以上、大量に ADAM および AD にオブジェクトが登録されている環境に対し、ソートを実行すると

" サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)"

というエラーが返され、ソートができない。しかし、Name など一部の属性では問題なく動作する。 ただし、降順ソートの場合、すべての属性に対してソートができず、上記エラーが発生する。

【解説】Active Directory の大容量データに対するサーバソートについて
(1) 昇順ソート ~ インデックスつき属性と、インデックスなし属性での挙動の違い
(2) 降順ソート ~ 既知の問題
(3) Virtual List View は対処方法となりえるか?← このコンテンツです!
(4) まとめ (4 回目予定)

- これまでの経緯
サーバ ソート(データをサーバ側で「整える(取得したデータの並べ替えを行う))の昇順ソートの場合は、インデックス化されていない属性をソートキーに指定した場合は、データの並べ替えのためサーバ側で一時的にデータを格納するテーブルが作成され、このテーブル内で指定されたキーによる整列を行います。この一時的なソートに用いられるテーブルのサイズは、"MaxTempTableSize" という LDAP ポリシーで決められており、既定は 10000 です。
ソートする対象のレコード数が MaxTempTableSize を超えた場合、ソート処理は行われません。
一方、インデックス化された属性のソートの場合にはこの一時データ格納テーブルを使わないためこの制限に抵触しません。このため、インデックス化された属性の場合はうまくいき、インデックス化されてない属性をソートキーに指定して昇順ソートを行った場合は上記問題が発生してしまうことになるのでした。
そして、降順ソート時は MaxTempTableSize のサイズ制限抵触以外の問題が存在するため、インデックス化属性であっても降順ソート時大量件数が存在する場合、非インデックス属性の昇順ソート時の動作と同様のエラーが発生する問題があります。この問題は製品の障害となります。そのため、降順ソートを実装する必要があるシステムの場合は、属性のインデックス化は回避手段とはなりません。

- VLV は回避策にならない
MSDN を見ると、VLV は大きなサイズの ResultSet に向いてます、みたいなことが書いてあるのですが、実際は、VLV も Temp tableを使って中間結果を保持することで動作する設計です。しかし、この Temp Table はすなわち MaxTempTableSize が制限値になるため、VLV の計算に必要な中間結果がこの値を超えた場合、昇順ソートのインデックスなし属性がソートキーに指定された場合と同様処理が中断することになります。よって、回避策として有効な手段には残念ながらならないという結論になります。なお、問題発生時のエラーは、非インデックス属性の大量データの昇順ソート実行時と同じく「"サーバーは要求された重大な拡張子をサポートしていません。(0x8007202C)」となります。なお、MaxTempTableSize のサイズをオブジェクト数をカバーする値に変更しますと、正常に Resultset が返されるようになります。

- VLV サンプル コード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.DirectoryServices;

namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

        private void button1_Click(object sender, EventArgs e)
{
SearchResultCollection results;
using (DirectorySearcher searcher = new DirectorySearcher())
{
DirectoryEntry de = new DirectoryEntry("LDAP://CN=Users,DC=corp,DC=contoso,DC=com");
searcher.SearchRoot = de;
searcher.Filter = "(objectclass=*)";
searcher.PropertiesToLoad.Add("samaccountname");
searcher.PropertiesToLoad.Add("name");
searcher.PropertiesToLoad.Add("displayName");
searcher.PropertiesToLoad.Add("mail");
searcher.SearchScope = SearchScope.Subtree;
DirectoryVirtualListView virtualList = new DirectoryVirtualListView(0, 50, 10);
string searchAttributeName = null;
searchAttributeName = "name";
SortOption sort = new SortOption(searchAttributeName, SortDirection.Descending);
searcher.Sort = sort;
searcher.VirtualListView = virtualList;
results = searcher.FindAll();
if (results.Count >= 0)
{
Console.WriteLine(searcher.VirtualListView.ApproximateTotal);
MessageBox.Show(searcher.VirtualListView.ApproximateTotal.ToString());
}
}
}
}
}

~ ういこう ~