パフォーマンス要件はシステム構築時に考慮すべき最も重要なポイントの1つですが、XMLデータベースのチューニング情報はまだまだ不足している状況かと思います。本稿では、各XMLDB製品に共通するであろうパフォーマンスのポイントについて、Cyber Luxeonを使用して実際に実行・測定し、検証を試みました。
はじめに
パフォーマンス要件はシステムを構築する際に、考慮すべき最も重要なポイントの1つです。リレーショナルデータベース(以降、RDB)に関しては、そのチューニングのポイントについては、書籍、Webなどで数多くの情報が存在しますが、XMLDBに関してはまだまだこれからといったところです。そこで本稿では、Cyber Luxeonに限らず、各XMLDB製品に共通するであろうパフォーマンスのポイントについて、実際に実行・測定し検証を試みました。
なお、XMLの更新機能に関してはXQuery Update Facilityの仕様策定が進められていますが、執筆段階では草案段階であり、XMLDBごとにXML更新用の機能が提供されているのが現状です。そこで本稿ではXMLDBの検索機能に対象を絞って説明を進めます。
対象読者
XMLに触れたことがある方、RDBなどデータベースを操作したことがある方を対象とします。
検証環境
まずは、本稿の検証に使用したハードウェアスペック、ソフトウェアを以下の表に示します。
| CPU | Intel Core2 Duo E6300 1.8GHz |
| メモリ | 2G |
| OS | Windows XP |
| Java | 1.6.0 |
| DB | Cyber Luxeon ver2.0 Developer Edition |
XPath、XQueryの記法によるパフォーマンスの違い
テストデータ
XPath、XQueryの計測では、以下に示したXMLを共通で使用しました。1つのXMLファイルのように書かれていますが、実際は、item要素をルート要素とする10000個のXMLと、1つのバインダドキュメント(複数のXMLにショートカットを設定することによって、あたかも1つのXMLファイルかのように扱えるCyber Luxeonの機能)を使用しています。バインダドキュメントはMultiDoc_Container要素をルート要素とします。item要素は1万件作成されており、item要素内のprice要素にはランダムに整数値が格納されています。
<MultiDoc_Container> <item> <item_name>item1</item_name> <price>1100</price> </item> <item> <item_name>item2</item_name> <price>3000</price> </item> <item> <item_name>item3</item_name> <price>3000</price> </item> <!-- 以降10000件まで格納 --> </MultiDoc_Container>
測定方法
以下のJavaプログラムを使用して、実行時間を測定しました。検証にあたってはソースコード内のXQueryの文字列の箇所を検証ケースごとに、書き換えて使用しました。
public class ExecXQuery { public static void main(String[] args) { // XMLストアへの接続 clientSession = XlnClientSessionFactory.getSession(); XMLStore xmlStore = clientSession.getXMLStore( "test_store" ); // XQuery文字列(この部分をテストケースによって変更する) String xqueryStr = " for $item in /MultiDoc_Container/item\n" + " where $item/price > 1000\n" + " return $item"; XMLDocument xmlDoc = (XMLDocument)xmlStore.getFile( "/test_dir/dc.bnd" ); XQuery xQuery = clientSession.createXQuery( xqueryStr ); // 測定開始 long start = System.currentTimeMillis(); // XQuery実行 xQuery.execute( xmlDoc ); long end = System.currentTimeMillis(); // XQuery結果の取得 XQuerySequence results = xQuery.getResults(); XQuerySequenceIterator iter = results.getIterator(); int i = 0; while( iter.hasNext() ){ i++; XQueryItem xQueryItem = iter.nextItem(); Node node = (Node)xQueryItem.getValue(); } long allEnd = System.currentTimeMillis(); clientSession.release(); // 測定結果 clientSession.release(); System.out.println( "Query time:" + (allEnd -start) ); System.out.println( "All time:" + (allEnd -start) + "/検索ノード数:" + i ); } }
検証ケース1:XPathで「//ノード名」を使うと遅い
仮説
XPathの検索では、ノードへのパスをすべて記述しなくても、//ノード名というかたちで検索対象ノードを指定することにより、コンテキストノード配下の該当するノードすべてを指し示すことができます。しかし、これを使用するとノードの連なりを順にたどるという処理(ノードウォーキング)が実行されてしまい、パフォーマンスが悪化することが予想されます。
抽出対象データ
item要素のprice要素が「1000」である商品名要素を抽出します。
検証用XQuery
以下に測定で使用したXQuery式を示します。2つのXQuery式は同じ結果を返します。
for $item in /MultiDoc_Container/item
where $item/price = 1000
return $item/name
for $item in //item
where $item/price = 1000
return $item/name
測定結果
各XQueryで1万要素を検索した結果を以下の表に示します。
| テストケース | XQuery実行時間 | 全実行時間 | 該当ノード数 |
| パス直接指定 | 234ミリ秒 | 234ミリ秒 | 291 |
| 「//ノード名」指定 | 313ミリ秒 | 313ミリ秒 | 291 |
予想通り、パスを直接指定した方が、実行時間が少なく済んでいます。
考察・結論
XPath式で「//ノード名」は、パフォーマンスが劣化するので、必要性がない限り、なるべく使用しない方が良いでしょう。今回のケースでは「//ノード名」に該当するノードは、コンテキストノード配下では1つでしたが、コンテキストノード配下に同一名のノードが複数ある場合にも、パスを直接指定してOr条件(||)で連結するなどした方が、パフォーマンスは向上するでしょう。検索対象のXMLのノードが多くなるほど、たどるノードも多くなるので、パフォーマンスの差も顕著にあらわれます。
検証ケース2:XPATHで1度で絞り込んだ方が、WHERE文で絞り込むよりも速い
仮説
ノードを条件で絞り込んで検索する場合に、XPathに検索条件を指定して1度で対象ノードを絞り込むパターンと、上位ノードをXPathで抽出してから、WHERE句を使用して、ノードを絞り込む場合では、1度で絞り込んだほうが、無駄なノードを変数に格納しない分性能が良いことが予想されます。
抽出対象データ
item要素のprice要素が「1000」である商品名要素を抽出します。
検証用XQuery
以下に測定で使用したXQuery式を示します。2つのXQuery式は同じ結果を返します。
for $item in /MultiDoc_Container/item[price=1000]
return $item/name
for $item in /MultiDoc_Container/item
where $item/price = 1000
return $item/name
測定結果
各XQueryで1万要素を検索した結果を以下の表に示します。
| テストケース | XQuery実行時間 | 全実行時間 | 該当ノード数 |
| XPathで絞り込む | 219ミリ秒 | 219ミリ秒 | 291 |
| Where句で絞り込む | 234ミリ秒 | 234ミリ秒 | 291 |
予想通りXPathで1度で絞り込んだ方が、実行時間は少なくすんでいます。
考察・結論
XPathで抽出する時点で絞り込んだ方が性能が良いという結果になりました。それは、XPathで絞り込まないパターンの場合、一旦ノードを変数に格納し、その上で絞り込むので、ノードがメモリに展開される分、オーバーヘッドがあるためと考えられます。余計なオーバーヘッドを生まないためにも、XPath上で絞り込める場合は、そのようにした方が良いでしょう。
この記事は参考になりましたか?
- Cyber Luxeonで学ぶXMLDB入門連載記事一覧
- この記事の著者
-
山田 祥寛(ヤマダ ヨシヒロ)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
-
WINGSプロジェクト 佐藤 治夫 (株式会社ビープラウド)(サトウ ハルオ)
<WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書、記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
