Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

XMLDBのチューニングポイント

Cyber Luxeonで学ぶXMLDB入門 第7回

  • LINEで送る
  • このエントリーをはてなブックマークに追加

パフォーマンス要件はシステム構築時に考慮すべき最も重要なポイントの1つですが、XMLデータベースのチューニング情報はまだまだ不足している状況かと思います。本稿では、各XMLDB製品に共通するであろうパフォーマンスのポイントについて、Cyber Luxeonを使用して実際に実行・測定し、検証を試みました。

目次

はじめに

 パフォーマンス要件はシステムを構築する際に、考慮すべき最も重要なポイントの1つです。リレーショナルデータベース(以降、RDB)に関しては、そのチューニングのポイントについては、書籍、Webなどで数多くの情報が存在しますが、XMLDBに関してはまだまだこれからといったところです。そこで本稿では、Cyber Luxeonに限らず、各XMLDB製品に共通するであろうパフォーマンスのポイントについて、実際に実行・測定し検証を試みました。

 なお、XMLの更新機能に関してはXQuery Update Facilityの仕様策定が進められていますが、執筆段階では草案段階であり、XMLDBごとにXML更新用の機能が提供されているのが現状です。そこで本稿ではXMLDBの検索機能に対象を絞って説明を進めます。

対象読者

 XMLに触れたことがある方、RDBなどデータベースを操作したことがある方を対象とします。

検証環境

 まずは、本稿の検証に使用したハードウェアスペック、ソフトウェアを以下の表に示します。

検証環境
CPUIntel Core2 Duo E6300 1.8GHz
メモリ2G
OSWindows XP
Java1.6.0
DBCyber 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要素にはランダムに整数値が格納されています。

検索対象のXML
<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の文字列の箇所を検証ケースごとに、書き換えて使用しました。

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万要素を検索した結果を以下の表に示します。

測定結果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式は同じ結果を返します。

XPathで絞り込んで変数に格納するケース
for $item in /MultiDoc_Container/item[price=1000]
    return $item/name
XPathで1度変数にノードを格納してから、where句で絞り込むケース
for $item in /MultiDoc_Container/item
    where $item/price = 1000
    return $item/name

測定結果

 各XQueryで1万要素を検索した結果を以下の表に示します。

測定結果1
テストケースXQuery実行時間全実行時間該当ノード数
XPathで絞り込む219ミリ秒219ミリ秒291
Where句で絞り込む234ミリ秒234ミリ秒291

 予想通りXPathで1度で絞り込んだ方が、実行時間は少なくすんでいます。

考察・結論

 XPathで抽出する時点で絞り込んだ方が性能が良いという結果になりました。それは、XPathで絞り込まないパターンの場合、一旦ノードを変数に格納し、その上で絞り込むので、ノードがメモリに展開される分、オーバーヘッドがあるためと考えられます。余計なオーバーヘッドを生まないためにも、XPath上で絞り込める場合は、そのようにした方が良いでしょう。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • WINGSプロジェクト 佐藤 治夫 (株式会社ビープラウド)(サトウ ハルオ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2017年5月時点での登録メンバは52名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂き...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XMLD...

バックナンバー

連載:Cyber Luxeonで学ぶXMLDB入門
All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5