DB2 9 での pureXML: XML データのクエリーに使う手段を使い分ける

DB2 9 では、pureXML® サポートが導入されています。これはつまり、XML データは固有の階層フォーマットで保管され、クエリーを実行されるということです。DB2 では、XML データに対してクエリーを実行するために SQL/XML と XQuery という 2 つの言語を提供しています。XQuery と SQL は別々に使用できますが、SQL に XQuery を組み込んで使用することも、またその逆も可能です。これにより、とても柔軟に、そしてさまざまな方法で XML データに対してクエリーを実行できるようになっていますが、それぞれの方法にはそれが有効に機能する特定の状況があります。この記事ではこれらの方法 1 つひとつの利点と欠点を検討し、特定のニーズに最適な方法を選択するためのガイドラインを提供します。この記事は、DB2 9.5 に合わせて更新されています。

Matthias Nicola, DB2/XML Performance, IBM Silicon Valley Laboratory

Author photo: Matthias NicolaNicola 博士は、IBM Silicon Valley Lab の XML データベース・パフォーマンスの技術リーダーです。彼の業務は、XQuery、SQL/XML、また DB2 ネイティブの XML 機能を含め、DB2 での XML パフォーマンスのあらゆる側面を対象としています。Nicola 博士は DB2 XML 開発チームや XML を使用する顧客やビジネス・パートナーと緊密に業務を進めながら、XML ソリューションの設計や実装、最適化に協力しています。IBM に入社する前には、Informix Software でデータ・ウェアハウスのパフォーマンスに関する業務を行っていました。また、分散データベースや複製データベースに関する研究と業界プロジェクトにも 4 年間携わっていました。彼は、1999年にドイツの Technical University of Aachen でコンピューター・サイエンスの博士号を取得しています。


developerWorks 貢献著者レベル

Fatma Ozcan (fozcan@almaden.ibm.com), Research Staff Member, IBM Almaden Research Center

Author photo: Fatma OzcanOzcan 博士は、2001年から IBM Almaden Research Center に研究スタッフとして勤務しています。アメリカ・カレッジパークにある University of Maryland で2001年、コンピューター・サイエンスの博士号を取得しました。XML 照会言語および照会の最適化、異種情報システムの統合、そしてソフトウェア・エージェントなどを研究対象としています。彼女は ACM SIGMOD のメンバーです。



2007年 8月 28日 (初版 2006年 6月 08日)

はじめに

DB2 での純粋な XML のサポートは、XML データの管理に効率的かつ多様な機能をもたらします。DB2 では XML をその本来の階層フォーマットで保管、処理するため、XML を CLOB にテキストとして保管したり、リレーショナル・テーブルにマッピングするときに生じるパフォーマンス上の制約や柔軟性に関する制約がありません。さらに DB2 V9 は XML 専用のデータベースとは異なり、1 つのデータベース内、さらにはテーブルの 1 つの行内においてでさえリレーショナル・データと XML データをシームレスに統合します。この柔軟性は、リレーショナル・データ、XML データ、あるいはその両方への同時アクセスを可能にする言語サポートに反映されています。XML に対してクエリーを実行する方法には、以下の 4 つがあります。

  • プレーンな SQL (XQuery が一切関係しない SQL)
  • SQL/XML (SQL に組み込まれた XQuery)
  • スタンドアロン言語としての XQuery (SQL が一切関係しない XQuery)
  • SQL を組み込んだ XQuery

XQuery および SQL/XML を使用して、XML データに対してクエリーを実行する方法についての概要は、developerWorksに 掲載された記事、「SQL を使った DB2 XML Data データの照会」および「Query DB2 XML data with XQuery」を参照してください。この記事では、読者がこの 2 つの記事で紹介されている概念を十分に理解していることを前提とします。注意する点として、XPath は XQuery のサブ言語なので、XQuery について言及する際は常に言外に XPath も含まれることを覚えておいてください。XPath については、DB2 XML Extender で XSLT スタイル・シートまたはロケーション・パスを使用した経験があればすでにご存知だと思います。たいていの場合、XML 値を抽出したり、XML 述部を表現するには XPath で十分事足りるので、XQuery のすべての追加機能をまだよく知らないとしても、XPath から使い始めることができます。

DB2 では、最大限の生産性を引き出し、クエリーをアプリケーションのニーズに適応させるために上記のすべての方法を利用することができます。そこで、この記事では以下の疑問を取り上げます。

  • 4 つの方法それぞれの主要な特性、そして利点と欠点は何か。
  • どの方法をどんな場合に使用するべきなのか。

この記事ではまず全体的な概要を説明し、それからそれぞれの方法ごとにより詳細で具体的な事例を掘り下げて解説します。

概要およびガイドライン

たいていのクエリーはプレーンな XQuery、SQL/XML、または SQL を組み込んだ XQuery のいずれかで表現できますが、場合によっては、特定の方法が他の方法よりも直観的にクエリー・ロジックを表現できることに気付くかもしれません。一般に、XML データに対してクエリーを実行するのに「最適」な方法は、アプリケーションの要件と特性を考慮に入れた上で臨機応変に選択する必要があります。ただし、ガイドラインとしては以下のように要約することができます。

  • XQuery または XPath を使用しないプレーンな SQL が実際に役立つのは、全文書検索、そして文書全体の挿入、削除、更新などの操作だけです。文書を選択するには、同じテーブルに含まれる XML ではない列が基準になるためです。
  • SQL 文に XQuery または XPath が組み込まれた SQL/XML は、最も広範な機能を提供し、課せられる制約も最小限となります。SQL/XML では、XML 列での述部の表現、文書のフラグメント抽出、XQuery 式へのパラメーター・マーカーの受け渡し、全文検索の使用、SQL レベルでの集約とグループ化が可能であるだけでなく、XML とリレーショナル・データを柔軟に組み合わせ、結合することもできます。ほとんどのアプリケーションは SQL/XML で十分対処できるため、現時点ではこれらの利点すべてが必要なわけではないとしても、SQL/XML は今後の拡張に備えて選択肢として残しておいてください。
  • XQuery は XML データに対するクエリー専用に設計された強力な問い合わせ言語です。そのため、XML データのみにクエリーを実行して操作を行う必要があるが、リレーショナル・データは関係しないアプリケーションに適しており、ときには他の方法より簡単かつ直観的な方法となります。さらに、XML 専用のデータベースを DB2 9 にマイグレーションする場合、既存の XQuery があるのであれば、プレーンな XQuery をそのまま使ったほうがいい場合があります。
  • SQL を組み込んだ XQuery が有力候補となるのは、リレーショナル述部および索引を利用するだけでなく、全文検索も利用して XQuery に入力する文書をあらかじめ XML 列からフィルタリングしたいという場合です。XQuery に組み込まれた SQL でも XML 列で外部関数を実行できますが、グループ化と集約によるデータ分析クエリーを実行しなければならない場合には、SQL/XML のほうが適しています。

1 つの文でどのように SQL と XQuery を組み合わせようが、DB2 は単一のハイブリッド・コンパイラーを使用してクエリー全体に対する実行計画を生成し、最適化します。このため、クエリー実行のパフォーマンスに不利な条件が招かれることはありません。

以下の表に、XML データに対してクエリーを実行する 4 つの方法それぞれの利点を要約します。

表 1. 要約
プレーンな SQLSQL/XMLプレーンな XQuerySQL/XML を組み込んだ XQuery
XML 述部-++++++
リレーショナル述部++++-+
XML およびリレーショナル述部-++-++
XML とリレーショナルの結合-++-++
XML と XML の結合-+++++
XML データの変換-o++++
挿入、更新、削除++++--
パラメーター・マーカー+++--
全文検索+++-++
XML 集約およびグループ化-++oo
関数コール++++-++

上記の表では、「-」は該当する言語がその機能をサポートしないこと、「+」はその機能はサポートされるけれども他に効率的または便利な方法が存在するかもしれないこと、「++」は該当する言語がその機能を表現するのに最適であること、そして「o」はその機能を表現するのは可能なものの、該当する言語では表現しにくかったり、あるいは非効率的であることを意味します。

次に、具体的なクエリー例を検討するためにデータとテーブルのサンプルを定義します。


サンプル・テーブルおよびデータ

XML に対してクエリーを実行する方法の説明で使用する 3 つのテーブルを以下に記載します。dept テーブルを構成するのは、unitID と deptdoc という 2 つの列と、架空の会社の 1 つの部門を記述する行です。unitID 列はその部門が含まれる組織単位を識別し (組織単位には複数の部門がある場合があります)、deptdoc 列にはその部門に所属する従業員をリストする XML 文書が含まれます。一方、project テーブルにあるのは XML 型の projectDoc という列だけです。この project テーブルの各行には特定のプロジェクトについて記述する XML 文書が含まれます。プロジェクトには複数の部門が関与する場合もあります。3 つ目のテーブルは、リレーショナルと XML のハイブリッド・クエリーおよび結合を表すための、各組織単位の名前、マネージャーなどをリストした純粋なリレーショナル・テーブルです。組織単位には複数の部門が含まれる場合もあります。

create table dept( unitID char(8), deptdoc xml)
unitIDdeptdoc
WWPR
<dept deptID="PR27">
   <employee id="901">
      <name>Jim Qu</name>
      <phone>408 555 1212</phone>
  </employee>
  <employee id="902">
      <name>Peter Pan</name>
      <office>216</office>
  </employee>
</dept>
WWPR
<dept deptID="V15">
   <employee id="673">
      <name>Matt Foreman</name>
      <phone>416 891 7301</phone>
      <poffice>216</office>
  </employee>
  <description>This dept supports sales world wide</description>
</dept>
S-USE...
......
create table project(projectDoc xml)
projectDOC
<project ID="P0001">
    <name>Hello World</name>
    <deptID>PR27</deptID>
    <manager>Peter Pan</manager>
</project>
<project ID="P0009">
    <name>New Horizon</name>
   <deptID>PR27</deptID>
   <deptID>V15</deptID>
   <manager>Matt Foreman</manager>
   <description>This project is brand new</description> 
 </project>
create table unit( unitID char(8) primary key not null, name char(20), manager varchar(20),...)
unitIDnamemanager...
WWPRWorldwide MarketingJim Qu...
S-USESales US East CoastTom Jones...
............

プレーンな SQL

XPath や XQuery のないプレーンな SQL では、XML 述部を使用せずに完全な文書を読み取ることができます。全文書検索の対象となる XML 文書を、同じテーブルにあるリレーショナル述部に基づいて識別することができるアプリケーションでは、プレーンな SQL が手軽で簡単です。例えば、クエリー 1 は組織単位「WWPR」のすべての部門文書を取得します。

クエリー 1
select deptdoc
from dept
where unitID = 'WWPR';

クエリー 2 は同様に、Jim Qu によって管理されているすべての部門の XML データを返します。

クエリー 2
select deptdoc
from dept d, unit u
where d.unitID = u.unitID and u.manager= 'Jim Qu';

プレーンな SQL に明らかな欠点は、XML データ自体で述部を表現することも、XML 文書のフラグメントだけを取得することもできないという点です。この例で PR27 部門のみを選択して従業員名だけを返すとなると、プレーンな SQL では対応しきれません。

XML 列の述部が不要で、常に完全な XML 文書を返すクエリーには、プレーンな SQL で十分だと考えられます。この場合、VARCHAR 列または CLOB 列に XML も保管すれば、全文書の挿入、検索操作のパフォーマンスが向上する可能性があります。

DB2 V9 で SQL/XML または XQuery のサポートをいずれも使わないとしても、プレーンな SQL ではクエリーで全文検索条件を使用できます。DB2 Net Search Extender で XML 列の全文索引を作成すれば、基本的なキーワード検索から、ステミングによる高度な検索や 37 の言語でのシソーラス検索およびあいまい検索に至るまでのテキスト検索に対応することができます。さらに、パス式で識別された特定の文書セクションにテキスト検索を絞りこむこともできます。クエリー 3 は、テキスト索引による検索に基づいて、/dept/description の下にある文書のいずれかの場所にストリング「sales」が含まれるすべての部門の文書を返す例です。

クエリー 3
select deptdoc
from dept
where CONTAINS(deptdoc,'SECTION("/dept/description") "sales" ')=1;

SQL/XML (SQL に組み込まれた XQuery/XPath)

SQL/XML は SQL 言語標準の一部で、新しい XML データ型を定義するとともに XML データに対してクエリーを実行する関数や、構成、検証、変換を行う関数を定義しています。DB2 V8 ではすでに多数の SQL/XML パブリッシング機能を備えており、ユーザーが XMLELEMENT、XMLATTRIBUTE、XMLFOREST、XMLAGG などの関数を使ってリレーショナル・データから XML を構成できるようになっています。

DB2 9 にはさらに、XMLQUERY、XMLTABLE などの新しい SQL/XML クエリー関数と XMLEXISTS 述部が追加されています。これらの関数を使えば、SQL 文に XQuery や単純な XPath 式を組み込むことができます。

クエリー 4 に示すように、一般的に XMLQUERY 関数は select 節で XML 列から XML フラグメントを抽出するために使用し、XMLEXISTS は where 節で XML データの述部を表現するために使用します。

クエリー 4
select unitID, XMLQUERY('for $e in $d/dept/employee return $e/name/text()' 
			       passing  d.deptdoc as "d")
from dept d
where  unitID LIKE 'WW%' and 
       XMLEXISTS('$d/dept[@deptID = "V15"]' passing d.deptdoc as "d");

上記のクエリー例では、XMLEXISTS を使用して「WW」の部門 V15 を選択し、XMLQUERY を適用してその部門文書に含まれるすべての従業員の名前を返します。その結果は以下のとおりです。

DepartmentEmployee
WWPRMatt Foreman

このクエリーでは、SQL/XML を使用して XML データとリレーショナル・データのクエリーを統合する方法も示しています。select 節はリレーショナル列と XML 列の両方からデータを取得し、where 節にはリレーショナル述部と XML 述部の両方が含まれています。

DB2 9.5 では、XMLEXISTS とXMLQUERY 関数の「passing」節を省略して、上記のクエリーをさらに簡潔にすることができます。「passing」節を使わずに XML 列「deptdoc」を XQuery に渡すだけにすれば、XQuery 式ではこの列を $DEPTDOC として参照することができるからです。このように作成したのが、クエリー 5 です。

クエリー 5
select unitID, XMLQUERY('for $e in $DEPTDOC/dept/employee return $e/name/text()')
from dept d
where  unitID LIKE 'WW%' and 
       XMLEXISTS('$DEPTDOC/dept[@deptID = "V15"]');

これと同じクエリーは、XMLTABLE 関数でも表現することができます (クエリー 6 を参照)。このフォーマットでは、入力データを制限するための条件と、対象とする出力値を抽出するための条件を指定します。クエリー 6 では XMLTABLE 関数に含まれる XQuery 式が部門 V15 に勤務する従業員を特定し、COLUMNS 節に含まれるパス式 (「name/text()」) が該当する従業員の名前を返します。この出力は、クエリー 4 および 5 と同じです。

クエリー 6
select d.unitID, T.name
from dept d, XMLTABLE('$d/dept[@deptID="V15"]/employee' passing d.deptdoc as "d"
                       COLUMNS
                          name varchar(50) path 'name/text()'  ) as T
where unitID LIKE 'WW%';

SQL/XML の利点

SQL/XML の方法には、以下に挙げる利点があります。

  • 既存の SQL アプリケーションに多少の XML 機能をさまざまな箇所に段階的に追加する場合には、SQL/XML を使用するのが適切です。
  • SQL の愛好者が、自分とそのチームが SQL を最もよく理解しているという理由で SQL を主要言語のままにしておきたい場合には、SQL/XML を使用するのが適切です。
  • SQL/XML は、リレーショナル列と XML 列から同時にデータを返さなければならないクエリーに適しています。
  • 上記のクエリー 3 のように、全検索条件が必要なクエリーにも SQL/XML は適しています。
  • 結果をセットとして返し、欠落した XML 要素をヌルで表したい場合には SQL/XML が役立ちます。
  • DB2 V9 の XQuery は外部パラメーターをサポートしていないので、パラメーター・マーカーを使用するには SQL/XML を使用するのが適切です。XMLQUERY、XMLTABLE および XMLEXISTS で passing メカニズムを使うことで、SQL パラメーター・マーカーを変数 ($x) として組み込み XQuery 式に渡すことができます。
    クエリー 7
    select deptdoc
    from dept
    where XMLEXISTS('$d/dept[@deptID =  $x]' 
    		      passing deptdoc as "d", cast(? as varchar(8)) as "x");
  • リレーショナル・データと XML データの統合が必要なアプリケーションには SQL/XML が適しています。SQL/XML は XML データとリレーショナル・データを結合するのに最も簡単な手段だからです。以下の例は、unit テーブルにマネージャー (manager) としてリストされている従業員が所属するすべての部門の組織単位 ID を選択する例で、このクエリーはリレーショナル値 (unit.manager) と XML 値 (//employee/name) とを結合します。
    クエリー 8
    select u.unitID
    from dept d, unit u
    where XMLEXISTS('$d//employee[name = $m]' 
    			passing d.deptdoc as "d", u.manager as "m");

    上記では、この結合を実現するために組織単位のマネージャーを XMLEXISTS 述部に渡し、実際の結合条件が XQuery 述部となるようにしていますが、逆に XML 文書の従業員の名前を SQL コンテキストに抽出して結合条件を SQL 述部にすることもできます。
    クエリー 9
    select u.unitID 
    from dept d, unit u
    where u.manager = XMLCAST(XMLQUERY('$d//employee/name ' 
    			        passing d.deptdoc as "d") as char(20));

    XMLCAST 関数は単一の入力値を期待するため、通常はクエリー 9 よりクエリー 8 のほうが好ましい方法です。サンプル・テーブルの場合、クエリー 9 は複数の従業員がいる部門に対しては失敗します。しかし XMLCAST を使ったクエリー 9 の方法は unit.manager でリレーショナル索引を使用できるため、文書ごとに 1 回しか現れない XML 値を結合する場合には便利です。結合条件はリレーショナル述部ではなく XQuery 述部なので、クエリー 8 ではリレーショナル索引を使用することはできません。
  • SQL/XML は XML のグループ化と集約にも適しています。XQuery 言語には明示的な group by 構文がありません。自己結合を使えば XQuery でもグループ化と集約を表現することは可能ですが、この方法はかなり厄介です。一例として、オフィスごとにグループ化した従業員の数、つまり各オフィスの従業員数をカウントするとします。これをプレーンな XQuery で行うとすると、クエリー 10 のようになります。クエリー 10 では、まず db2-fn:xmlcolumn 関数が DB2 の XML データへのアクセスを指定します。そして XML 列の名前を引数として取り、該当する列に保管された XML 値のシーケンスを返します。しかしこの方法よりも、XMLTABLE または XMLQUERY などの SQL/XML 関数を使って XML 列からデータ項目を抽出し、それからお馴染みの SQL の概念を使ってグループ化と集約を表現するほうが簡単です。クエリー 11 が返す論理結果はクエリー 10 と同じですが、ここでは XMLTABLE、そして SQL の group by 節が使用されています。
    クエリー 10
    XQUERY
    for $o in distinct-values(db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept/employee/office)
    let $emps := db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept/employee[office/text()=$o]
    return
    	<result><office>{$o}</office><cnt>{count($emps)}</cnt></result>;
    
    Result:
    <result><office>216</office><cnt>2</cnt></result>
    クエリー 11
    select X.office, count(X.emp)
    from dept, XMLTABLE ('$d/dept/employee' passing deptdoc as "d"
       COLUMNS 
         emp         VARCHAR(30)      PATH  'name',
         office      INTEGER          PATH  'office ') as X
    GROUP BY X.office;
    
    Result:
    216   2 
    -     1

    クエリー 11 では、XMLTABLE 関数がすべての文書の /dept/employee/name および /dept/employee/office を「emp」と「office」という2 つの列からなるテーブルの形式で抽出します。このテーブルで SQL の group by および集約関数を使用すれば、通常はプレーンな XQuery で同じ結果を生成するよりも効率的な方法となります。

    SQL の group by は NULL 値に対してもグループを生成するため、クエリー 11 の結果は 1 行追加されていることに注意してください。この行は、サンプル表に含まれるオフィス情報のない従業員に該当します。クエリー 10 ではこの従業員に対する行は生成されません。for ループで繰り返される個々のオフィス値には欠落したオフィス情報が含まれないためです。

SQL/XML の欠点

  • SQL/XML が常に XML 文書を別の XML 文書に変換するのに最適な方法になるとは限りません。XML 文書間での変換には XQuery を単独で使用するほうが適しています。また多くの場合、そのほうが XML データだけを操作する場合にはより直観的な方法となります。ただし、DB2 9.5 には XSLTRANSFORM という関数もあり、この関数を SQL 文内で使用すると XSLT スタイル・シートを使って XML 文書を変換することができます。具体的に言うと、XMLQUERY 関数を XSLTRANSFORM 関数の引数にすることができます。
  • 2 つの XML 列間の結合、あるいはもっと一般的に 2 つの XML 値の結合は、SQL/XML よりもプレーンな XQuery を使用したほうが、より直観的に表現することができます。クエリー 12 は、dept テーブルと project テーブルの XML 列を結合して、いずれかのプロジェクトに取り組んでいる従業員を返すという例です。
    クエリー 12
    select XMLQUERY('$d/dept/employee' passing d.deptdoc as "d")
    from dept d, project p
    where XMLEXISTS('$d/dept[@deptID=$p/project/deptID]'
                     passing d.deptdoc as "d", p.projectDoc as "p");

    クエリー 12 では、XMLEXISTS 内で すべての dept および project の文書を XQuery に渡し、結合条件を表現しています。このような結合を作成するには、プレーンな XQuery でのほうが簡単です (クエリー 14)。

スタンドアロン言語としての XQuery

ここで一歩離れて、XQuery とは何か、そしてなぜこれが必要なのかを考えてみましょう。SQL がリレーショナル・データ・モデルを対象に設計された問い合わせ言語であるのと同じく、XQuery は XML データに対してクエリーを実行するためだけに設計された言語です。XML データはリレーショナル・データとは大幅に異なるため、XML データを効率的に処理するには専用の言語が必要となります。リレーショナル・データはフラットで、高度に構造化され、強い型付けをされていて、順序付けられていません。その一方、XML データは順序付けられており、ネストされていて、階層を持ち、オプションで型が定義され、そしてたいていは不規則な形で半構造化されています。SQL ではこのようなデータを処理できないため、XQuery が設計されたというわけです。具体的に言うと、XQuery は XML 文書ツリーをナビゲートして XML フラグメントを抽出するように設計されているだけでなく、一連の XML 項目の作成、操作、繰り返し処理を行い、さらに新しい XML データの構成までを行うための式を組み込んでいます。

IBM は DB2 の主要なアプリケーション・プログラミング・インターフェース (API) のすべてを拡張し、SQL と同様に、XQuery を主要言語としてサポートするようにしました。これには CLI/ODBC、埋め込み SQL、JDBC、そして .NET が含まれます。その結果、DB2 コマンドライン・プロセッサーは XQuery もサポートするようになっています。XQuery はそのままの状態で送信できますが、先頭に XQUERY キーワードを付けて、DB2 に XQuery パーサーを使用するように指示しなければなりません。以下はその一例です。

クエリー 13
XQUERY 
for $dept in db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept
where $dept/@deptID="PR27"
return $dept/employee/name;

クエリー 13 は部門文書ごとに各「dept」要素を繰り返し処理し、部門 PR27 に所属する従業員の名前を返します。

XQuery の利点

  • XQuery は、SQL やリレーショナル構造を使用する必要がない (あるいは使用するのが望ましくない) XML 専用アプリケーションに適しています。
  • XQuery は XML 専用データベースを DB2 V9 にマイグレーションする際に役立ちます。たいていの場合、既存のXQuery は多少の変更を加えるだけで DB2 で実行できるからです。例えば、DB 2 で XQuery の入力データを取得する db2-fn:xmlcolumn() 関数が、他のデータベースで collection() と呼ばれている場合、単純に名前を変更するだけで済みます。
  • クエリーの結果を、データベース内の XML 文書とは別の新しく構成した XML 文書に組み込む (そして返す) 必要がある場合には、XQuery が便利です。
  • XQuery は、2 つの XML 文書間での結合を表現するのにも、XML 値を結合するのにも非常に優れています。クエリー 12 の結合を例に取ると、XQuery を使用した場合には、クエリー 14 のように一層単純明快かつ効率的に結合を表現することができます。
    クエリー 14
    XQUERY
    for $dept in db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept
       for $proj in db2-fn:xmlcolumn("PROJECT.PROJECTDOC")/project
    where $dept/@deptID = $proj/deptID
    return $dept/employee;

XQuery の欠点

  • プレーンな XQuery では、DB2 NSE (Net Search Extender) が提供する全文検索機能を活用することができません。全文検索を行うには SQL が必要になります。
  • プレーンな XQuery では、SQL ユーザー定義関数 (UDF) を呼び出すことも、C あるいは Java で作成された外部 UDF を呼び出すこともできません。
  • 現在、DB2 にはパラメーター・マーカーを使用して単独の XQuery を呼び出す方法がなく、パラメーターを XQuery に渡すには、SQL/XML でパラメーター・マーカー ("?") を名前付き変数に変換しなければなりません。例えば、クエリー 13 ではリテラル値「PR27」の代わりに疑問符 (?) を SQL スタイルのパラメーター・マーカーとして使いたいと思うかもしれせんが、そうすると無効なクエリーになってしまいます。

    クエリー 7 で、SQL/XML を使えば SQL パラメーター・マーカーを変数として組み込み XQuery 式に渡せることを説明しました。SQL/XML クエリーには、select 節内に XML 文書を部分的に抽出するための XMLQUERY 関数を含め、where 節内に適格な文書を選び出すための XMLEXISTS 述部が含まれることがよくあります。クエリー・ロジック全体を 2 つの別個の XQuery 呼び出し (XMLQUERY と XMLEXISTS それぞれでの呼び出し) ではなく単一の FLWOR 式で表現し、パラメーター・マーカーも引き続き使用できるようにするには、クエリー 13 をクエリー 15 のように書きなおしてください。
    クエリー 15
    values( XMLQUERY(
    	       ' for $dept in db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept
                         where $dept/@deptID = $z
                         return $dept/employee/name'
                  passing cast(? as varchar(8)) as "z" ) );

    クエリー 15 は SQL の全選択 (fullselect) に含まれる values 節でしかないので、SQL/XML 文ということになります。values 節は結果テーブルの列ごとに式を指定するという方法で値のテーブルを返します。クエリー 15 では、結果テーブルを構成するのは 1 つの行と XML 型の 1 つの列で、XMLQUERY 関数が出力列の値を生成します。したがって、すべての従業員の名前は単一の XML 値でクライアントに返されることになります。クエリー 15 の FLOWR 式はクエリー 13 の式とほとんど同じですが、クエリー 15 には外部変数 ($z) が含まれています。この変数がパラメーターとして XMLQUERY 関数に渡されます。

SQL を組み込んだ XQuery

単独のXQuery を使用してアクセスできるのは唯一、XML データのみです。扱っているのが XML データだけの場合はこれでまったく問題ありませんが、XML データへのアクセスとリレーショナル・データへのアクセスを組み合わせて、両方の言語とデータ・モデルを最大限に活用しなければならないアプリケーションの場合には対応しきれません。前述した SQL/XML では SQL に XQuery を組み込みましたが、逆に XQuery に SQL を組み込めば可能性はさらに広がります。この場合、前のセクションで説明した利点と欠点の他、重要となる側面には以下があります。

SQL を組み込んだ XQuery の利点

  • SQL を組み込んだ XQuery は、リレーショナル列の条件を基準に XML 文書のサブセットだけを処理したい場合に役立ちます。この場合、XML 列に含まれる XML 文書のサブセットにのみ XQuery を適用できれば理想的です。具体的には、リレーショナル述部を使って入力を特定の XQuery に制限するということです。この制限を可能にするため、DB 2 では db2-fn:sqlquery という別の入力関数を用意して、XQuery 内から SQL クエリーを呼び出せるようにしています。この関数は SQL の SELECT 文を取り込み、XML 列を出力として返します。例えば、クエリー 16 は XML 列 deptdoc に含まれるすべての文書を検討せずに、組み込み SQL 文を使用して述部が適用される unit テーブルを結合することによって XML 文書を事前にフィルタリングします。
    クエリー 16
    XQUERY 
    for $emp in db2-fn:sqlquery("select deptdoc 
     		          from dept d, unit u
    		          where d.unitID=u.unitID and
    		          u.manager = 'Jim Qu'")/dept/employee
    where $emp/office = 216
    return $emp/name;

    両方のテーブルの unitID 列、そして unit テーブルの manager 列に設定された正規リレーショナル索引によって、組み込み SQL クエリーが迅速に処理されるはずです。
  • SQL を組み込んだ XQuery では、全文検索を利用できます。これは、組み込み SQL 文の where 節で全文検索関数「contains」を使用できるためです。クエリー 17 では、XQuery 内の SQL 文が dept テーブルから、「sales」という語が含まれる /dept/description 内の文書を選択します。全文索引によって XML 文書が素早く検出されると、これらの XML 文書が FLWOR 式に入力され、この FLWOR 式によって文書のすべての従業員の名前が抽出されます。クエリー 18 はこの記事のサンプル・テーブルに対して同じ結果を返しますが、SQL/XML 表記で表現されたものです。
    クエリー 17
    XQUERY 
    for $emp in db2-fn:sqlquery(" 
    	       select deptdoc from dept
    	       where CONTAINS(deptdoc, 'SECTION(""/dept/description"") ""sales"" ')=1
    	       				          ")//employee
    return $emp/name;
    クエリー 18
    select XMLQUERY('$d//employee/name' passing deptdoc as "d")
    from dept
    where CONTAINS(deptdoc,'SECTION("/dept/description") "sales" ')=1;
  • SQL を組み込んだ XQuery は、リレーショナル・データと XML データを統合する必要のあるアプリケーションに役立ちます。この方法では、XML データとリレーショナル・データを組み合わせてクエリーを実行できるからです。これは SQL/XML にも当てはまりますが、XMLEXISTS 関数を使った SQL/XML でのほうがXML 値とリレーショナル値は結合しやすいはずです。クエリー 19 とクエリー 20 を比較してみてください。クエリー 19 は、従業員のなかに組織単位のマネージャーが含まれる部門の deptID を返します。unit テーブルのマネージャー名は組み込み SQL 文によって XML 型 (この場合は、XML ストリング) にキャストされてから XQuery に渡されます。XQuery の where 節には結合条件が含まれ、マネージャー名を従業員の名前を表す要素と比較します。クエリー 20 は、この結合を SQL/XML 表記で表現したものです。
    クエリー 19
    XQUERY 
    for $m in db2-fn:sqlquery('select XMLCAST(u.manager as XML) from unit u')
    for $d in db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept
    where $d/employee/name = $m
    return $d/data(@deptID);
    クエリー 20
    select XMLQUERY('$d/dept/data(@deptID)' passing  d.deptdoc as "d")
    from dept d, unit u
    where XMLEXISTS('$d/dept/employee[name = $m]' 
    			passing d.deptdoc as "d", u.manager as "m");

    余談ですが、deptID の変わりに一致する従業員の名前を返すとしたら、クエリー 19 とクエリー 20 をどのように変更したらよいか考えてみてください。クエリー 19 ではとても簡単です。return 節を return $m に変更すればいいだけだからです。クエリー 20 ですぐに思い付く方法は XMLQUERY 関数に含まれるパスを XMLQUERY('$d/dept/employee/name' passing d.deptdoc as "d") に変更することですが、このように変更すると、マネージャーの名前だけでなく、該当する部門のすべての従業員の名前が返されることになってしまいます。一致する部門文書からマネージャーの名前だけを抽出するには、クエリー 20 での XMLEXISTS と同様に、名前に関する述部を XMLQUERY 関数に組み込む必要があります。つまり、XMLQUERY('$d/dept/employee/name[. = $m]' passing d.deptdoc as "d", u.manager as "m" ) とします。XMLEXISTS と XMLQUERY との違いは、XMLEXISTS は述部を適用して文書全体を限定しますが、XMLQUERY 関数での述部は、XMLEXISTS が限定した特定の文書の中で特定の名前を検出するために適用されるという点です。
  • DB2 9.5 では、XQuery から db2-fn:sqlquery 関数に組み込まれた SQL 文にパラメーターを渡すことができます。これは、さまざまな状況で役に立ちます。その一例がクエリー 21 で、クエリー 19 および 20 と同じ結合を表現したものです。「for」節が従業員の名前に対して繰り返され、「where」節では同じ名前のマネージャーが unit テーブルに存在するかどうかをチェックします。db2-fn:sqlquery 関数は $n を追加の引数として取り、select 文を評価するときに、関数「parameter(1)」はこの $n の値を前提とします。db2-fn:sqlquery 関数はこのようなパラメーターを複数使用することができます。XQuery の「where」節の結果は、db2-fn:sqlquery 関数が空の結果を返す場合は false となり、空でない一連の結果を返すと true となります。これは、XQuery が持つ、存在に関するセマンティクスによるものです。したがって、ここでは値自体ではなく値の有無だけが問題となるので、select 節は select XMLCAST( ''yes'' as XML ) となります。
    クエリー 21
    XQUERY 
    for $n in db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept/employee/name
    where db2-fn:sqlquery('select XMLCAST(manager as XML) from unit
                           where manager = parameter(1)', $n)
    return $n/../../data(@deptID);

    すでにクエリー 19 と 20 の方法があるのに、なぜこのような方法で結合を表現しようとするのでしょう。その理由は、クエリー 21 では、結合述部は SQL のレベルにあるため DB2 は unit.manager に対してリレーショナル索引を使用することができるからです。一方、クエリー 19 と 20 は結合条件を XML のレベルで表現するため、/dept/employee/name のXML 索引を使用できるようになっています。これはクエリー 8 と 9 の場合と同様です。
  • クエリー 19 で示したように、SQL を組み込んだ XQuery では XML データとリレーショナル・データをひとつに組み合わせることが可能なので、リレーショナル・データを XQuery で扱おうとする際に役立ちます。クエリー 22 が構成するのは、組織単位と部門情報が含まれる結果文書です。部門情報は XML 列である deptdoc から取得される XML 文書で、組織単位情報はリレーショナル・テーブルの unit から取得されます。組み込み SQL 文は SQL/XML パブリッシング機能を使用して、「Unit」という XML 要素を構成します。この要素が持つ 3 つの子要素の値は、unit テーブルのリレーショナル列、つまり unitID、name、manager から取得されます。
    クエリー 22
    XQUERY 
       let $d := db2-fn:sqlquery("select deptdoc from dept where unitID = 'WWPR' ")
       let $u := db2-fn:sqlquery("select XMLELEMENT(NAME ""Unit"",
     			          XMLFOREST(unitID, name, manager))
    			  from unit where unitID = 'WWPR' " ) 
       return <result>
     		<units>{$u}</units>
    		<department>{$d}</department>
       	 </result>;

    クエリー22 の出力は、以下のようになります。

        <result>
             <units><unit> 
                       <UNITID>WWPR</UNITID> 
                       <NAME>World Wide Markeing</NAME> 
                       <MANAGER>Jim Qu</MANAGER>
                    </unit>
                    <unit> 
                       <UNITID>WWPR</UNITID> 
                       <NAME> ... </NAME>
                       <MANAGER> ... </MANAGER>
                   </unit>
    			....
    	   </units>
             <department> 
                 <dept deptID="PR27">
                      <employee id="901">
                      <name>Jim Qu</name>
                      <phone>408 555 1212</phone>
                    </employee>
                    <employee id="902">
                      <name>Peter Pan</name>
                      <office>216</office>
                    </employee>
                 </dept>
             </department>
        </result>
  • SQL を組み込んだ XQuery の利点としては、組み込み SQL 文にユーザー定義関数 (UDF) の呼び出しを含められることも挙げられます。UDF は、重要なビジネス・ロジックをカプセル化してアプリケーション開発要件を簡略化する手段として、多くの IT 組織で広く使用されています。プレーンな XQuery では UDF を呼び出せないため、これは大きな利点となります。

SQL を組み込んだ XQuery の欠点

  • db2-fn:sqlquery では XQuery のなかに SQL 文を組み込むことは可能ですが、組み込み SQL 文に正規 SQL スタイルのパラメーター・マーカーを含めることはできないのが現状です。
  • DB2 9では、db2-fn:sqlquery で XQuery から SQL に値を渡すことはできません。ただしクエリー 21 からわかるように、この制約は DB2 9.5 では取り除かれています。

XML クエリーの結果

認識しておかなければならないのは、クエリーをどのように作成するかによって、DB2 が生成するクエリー結果のフォーマットは異なるという点です。例えばプレーンな XQuery は、データベース内の同じ文書 (行) から複数の項目 (要素や文書フラグメントなど) が取得されたとしても、結果セットに 1 行につき 1 項目という形で返します。一方、SQL/XML で XMLQUERY 関数が使用されている場合、複数の項目はそれぞれの行に分割されるのではなく、1 行にまとめて返されます。これは、そのアプリケーションによって望ましいこともあれば、そうでない場合もあります。例を挙げてみましょう。

クエリー 23 とクエリー 24 はどちらも dept 文書に含まれる従業員名を要求するクエリーです。クエリー 23 は SQL/XML で表現されている一方、クエリー 24 は XQuery で作成されています。

クエリー 23
select XMLQUERY('$d/dept/employee/name' passing deptdoc as "d")
from dept;
クエリー 24
XQUERY db2-fn:xmlcolumn("DEPT.DEPTDOC")/dept/employee/name;

クエリー 23 は dept 文書ごとに行を返し、それぞれの行には該当する部門に所属する従業員の名前が含まれます。

<name>Jim Qu</name> <name>Peter Pan </name>
<name>Matt Foreman</name>

クエリー 24 はそれとは異なり、各従業員の名前を行ごとに返します。

<name>Jim Qu</name>
<name>Peter Pan</name>
<name>Matt Foreman</name>

アプリケーションで一般的に使いやすいのは、クエリー 24 のように XML 値ごとに分かれている結果ですが、この例ではどの name 要素が同じ部門文書から取得されているのかわからなくなってしまいます。クエリー 23 の結果はこの情報を維持しますが、アプリケーションにとっては使いにくいものとなります。それは、名前に個別にアクセスするには結果の行を分割しなければならない場合があるからです。アプリケーションが XML パーサーを使って DB2 からそれぞれの XML 結果行を取り込んだ場合、クエリー 21 の最初の結果行は整形式文書にはならないため (ルート要素が単一でないことが理由)、パーサーによって拒否されることになります。この問題は、クエリー 23 にXMLELEMENT コンストラクターを加えて単一のルート要素を追加すれば解決できます (クエリー 25 を参照)。

クエリー 25
Select XMLELEMENT(name "employees",
    XMLQUERY('$d/dept/employee/name'   passing d.deptdoc as "d"))
from dept d;

こうすると、クエリー結果は以下のように変更され、それぞれの結果行が整形式 XML 文書となります。

<employees><name>Jim Qu </name><name>Peter Pan</name></employees>
<employees><name>Matt Foreman</name></employees>
....

クエリー 15 では SQL のvalues 節と XMLQUERY 関数を使ってパラメーターを XQuery に渡せるようにしたことを思い出してください。しかしクエリー 15 の出力は単一の行で、この行に、すべての従業員名が含まれます。行ごとに従業員名を分け、さらにパラメーター・マーカーも使用しなければならない場合は、クエリー 26 のように XMLTABLE 関数を使用するという手段でその目的を果たせます。

クエリー 26
select X.*
from dept d, XMLTABLE('for $dept in $d/dept
                       where $dept/@deptID = $z
                       return $dept/employee/name'
                       passing d.deptdoc as "d", cast(? as varchar(10)) as "z"
            COLUMNS
                       "name"   XML  PATH '.') as X ;

まとめ

DB2 pureXML では、さまざまな方法で XML データにクエリーを実行することができます。どの方法がふさわしいかは、アプリケーションの要件と特性に応じて選択します。ほとんどの場合、リレーショナル・データを XML データと組み合わせる必要がある場合に最適なのはSQL/XML です。SQL/XML にはとりわけ、XML データに対してパラメーター・マーカーを使用できるという利点があります。一方、XML 専用アプリケーションであれば、単独の XQuery が有力な候補となります。さらに XQuery を組み込み SQL で補えば、全文検索や UDF の呼び出しにも対応することができます。この記事で説明した例は、どれを選択するか決定する上で有益な情報となります。記載したクエリー・パターンを出発点として、XML データに対する独自のクエリーを作成してください。

一般的なガイドラインは、どうしても必要な場合を除き、クエリーを極力複雑にしないことです。例えば、XQuery に組み込む SQL 文に、さらにXQuery を組み込むことは確かに可能ですが、私たちの経験では、目的のクエリー・ロジックを表現するのに 2 つの言語を複数の階層にネストさせる必要はないのが通常です。SQL に XQuery を組み込む場合、あるいは XQuery に SQL を組み込む場合は、1 階層だけにとどめるようにすることをお勧めします。


謝辞

この記事をレビューしてくれた Don Chamberlin 氏、Bert van der Linden 氏、Cindy Saracco 氏、Jan-Eike Michels 氏、そして Hardeep Singh 氏に感謝します。


ダウンロード

内容ファイル名サイズ
Script for queries in this articleDDLandQueries.txt9KB

参考文献

学ぶために

  • 記事「What's new in DB2 Viper: XML to the core」(Cynthia M. Saracco 著、developerWorks、2006年2月) では、DB2 9 での XML サポートについて説明しています。
  • 記事「SQL を使った DB2 XML Data データの照会」(Cynthia M. Saracco 著、developerWorks、2006年3月) では、SQL および SQL/XML を使って XML 列に保管されたデータに対してクエリーを実行する方法を説明しています。
  • 記事「Query DB2 XML data with XQuery」(Don Chamberlin、Cynthia M. Saracco 共著、developerWorks、2006年4月) では、XQuery を使って XML 列に保管されたデータに対してクエリーを実行する方法を説明しています。
  • 記事「XMLTABLE の例証、第 1 回: XML データをリレーショナル・フォーマットで取得する」(Vitor Rodrigues、Matthias Nicola 共著、developerWorks、2007年8月) では、XMLTABLE 関数のさまざまな使用方法を紹介しています。
  • Net Search Extender に、DB2 V8 の全文検索機能が記載されています。
  • Matthias Nicola と Bert van der Linden による記事「Native XML Support in DB2 Universal Database」を読んでください。
  • Integration of SQL and XQuery in IBM DB2」(F. Ozcan 他による共著、IBM Systems Journal、2006年4月) を読んで SQL と XQuery の統合についての詳細を学んでください。
  • developerWorks technical events and Webcasts で最新情報を入手してください。
  • コミュニティー向け DB2 Express Edition の無料バージョン、DB2 Express-C について調べてみてください。
  • 製品や技術を入手するために
  • DB2 9 のテスト・ドライブをダウンロードして、この記事で説明したクエリー手法を試してみてください。
  • DB2 を無料で使用するには、コミュニティー向け DB2 Express Edition の無料バージョン、DB2 Express-C をダウンロードしてください。DB2 Express Edtion と同じコア・データ機能を備えた DB2 Express-C は、アプリケーションをビルドしてデプロイするための安定した基盤になります。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Information Management, XML
ArticleID=259635
ArticleTitle=DB2 9 での pureXML: XML データのクエリーに使う手段を使い分ける
publish-date=08282007