HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

XMLEXISTSを使う場合の注意点(だと思う)

発端

2年近く前に、次のようなクエリが原因でアプリケーションのレスポンスが悪いという状況に出くわした。

xquery count(
 for $doc in db2-fn:sqlquery("
   select xmlquery('for $doc in $root/hoge return $doc' passing DOCUMENT.DATA as ""root"")
    from DOCUMENT
    where (
      xmlexists('$root/hoge/hoge_nnnn/h_nnnn[. = ""aaaa""]' passing data as ""root"")
    )
 ")
 return $doc)

データ構造は次のような感じ。

<hoge>
<hoge_nnnn>
<h_nnnn id_nnnn="AAAA">aaaa</h_nnnn>
<h_nnnn id_nnnn="AAAA">bbbb</h_nnnn>
  :
  :この間に要素"h_nnnn"がたくさんある
  :
<h_nnnn id_nnnn="ZZZZ">yyyy</h_nnnn>
<h_nnnn id_nnnn="ZZZZ">zzzz</h_nnnn>
</hoge_nnnn>
</hoge>

しかし、詳しい検証をする余裕などなく、目の前にある事実だけをメモして保留。

見つけた記事

とあるきっかけで次の文書を見つけてブックマークしておいた。

しかし、心の余裕などなく(以下略)

検証

最近になって、ちょっと心の余裕が出てきたので、検証してみた。(こういうときに向けて、問題をTODOとしてとりあえず書き留めておくと役に立ちます)
心の余裕があったからなのだろうか、唐突に問題となっていることと見つけた記事のことが頭の中でひとつのネットワークを形成した。そのひらめきを信じて次の2種類のクエリのレスポンス時間を計測してみた。

xquery count(
 for $doc in db2-fn:sqlquery("
   select xmlquery('for $doc in $root/hoge return $doc' passing DOCUMENT.DATA as ""root"")
    from DOCUMENT
    where (
      xmlexists('$root/hoge/hoge_nnnn/h_nnnn[. = ""nnnn""]' passing data as ""root"")
    )
 ")
 return $doc)
;
xquery count(
 for $doc in db2-fn:sqlquery("
   select xmlquery('for $doc in $root/hoge return $doc' passing DOCUMENT.DATA as ""root"")
    from DOCUMENT
    where (
      xmlexists('$root/hoge[hoge_nnnn/h_nnnn = ""nnnn""]' passing data as ""root"")
    )
 ")
 return $doc)
;

2つのクエリの違いは、XMLEXISTSに含まれるXQuery式の条件の括弧([])の位置。ただそれだけ。
データ構造は次のとおり。

<?xml version="1.0" encoding="UTF-8" ?>
<hoge>
<hoge_0001>
<h_0001 id_0001="0001">0001</h_0001>
</hoge_0001>
<hoge_0005>
<h_0005 id_0005="0005">0005</h_0005>
<h_0005 id_0005="0004">0004</h_0005>
<h_0005 id_0005="0003">0003</h_0005>
<h_0005 id_0005="0002">0002</h_0005>
<h_0005 id_0005="0001">0001</h_0005>
</hoge_0005>
<hoge_0010>
<h_0010 id_0010="0010">0010</h_0010>
<h_0010 id_0010="0009">0009</h_0010>
<h_0010 id_0010="0008">0008</h_0010>
<h_0010 id_0010="0007">0007</h_0010>
<h_0010 id_0010="0006">0006</h_0010>
  <!-- 中略 -->
<h_1000 id_1000="0003">0003</h_1000>
<h_1000 id_1000="0002">0002</h_1000>
<h_1000 id_1000="0001">0001</h_1000>
</hoge_1000>
</hoge>

このデータを含む行を999行、値だけをちょっと変えた行を1行含むテーブルを作成。(値が異なる1行は、条件が誤っていないことを確認するためのデータ。)
で、クエリは、"nnnn"の部分を"0001", "0005", "0010", "0050", "0100", "0500", "1000"に置き換えたクエリをそれぞれ実行する。
実行は、db2batchを使用し、すべてのクエリを順に実行する処理を5回繰り返した。

結果

環境が貧弱なので、実行時間の比だけを見てほしい。
DB2 Express-C v9.1.2

タイプ         番号        反復回数    合計回数       最小回数       最大回数       算術平均       幾何平均       行が取り出されました 行が出力されました
-------------- ----------- ----------- -------------- -------------- -------------- -------------- -------------- -------------------- ------------------
ステートメント           1           5       2.461687       0.470665       0.542902       0.492337       0.491606                    1                  1
ステートメント           2           5       4.102681       0.800050       0.862917       0.820536       0.820204                    1                  1
ステートメント           3           5       6.823924       1.322306       1.426819       1.364785       1.364247                    1                  1
ステートメント           4           5      28.351132       5.559839       5.910827       5.670226       5.668830                    1                  1
ステートメント           5           5      54.546583      10.769796      10.980610      10.909317      10.909038                    1                  1
ステートメント           6           5     272.912879      53.956566      55.365782      54.582576      54.580478                    1                  1
ステートメント           7           5     540.429797     107.153093     109.536826     108.085959     108.082841                    1                  1
ステートメント           8           5       2.414396       0.463788       0.500210       0.482879       0.482698                    1                  1
ステートメント           9           5       2.026499       0.398040       0.428553       0.405300       0.405137                    1                  1
ステートメント          10           5       2.291560       0.451183       0.466711       0.458312       0.458268                    1                  1
ステートメント          11           5       6.011150       1.166758       1.244315       1.202230       1.201855                    1                  1
ステートメント          12           5       9.036140       1.753796       1.884823       1.807228       1.806698                    1                  1
ステートメント          13           5      38.281789       7.400996       7.899849       7.656358       7.654624                    1                  1
ステートメント          14           5      67.502275      13.290434      13.690482      13.500455      13.499526                    1                  1

DB2 Express-C v9.5.2

タイプ         番号        反復回数    合計回数       最小回数       最大回数       算術平均       幾何平均       行が取り出されました 行が出力されました
-------------- ----------- ----------- -------------- -------------- -------------- -------------- -------------- -------------------- ------------------
ステートメント           1           5       0.692870       0.135252       0.146686       0.138574       0.138507                    1                  1
ステートメント           2           5       1.506496       0.291530       0.309559       0.301299       0.301239                    1                  1
ステートメント           3           5       2.439446       0.478985       0.492050       0.487889       0.487867                    1                  1
ステートメント           4           5      10.251198       2.026803       2.074359       2.050240       2.050171                    1                  1
ステートメント           5           5      20.270543       3.958890       4.171573       4.054109       4.053396                    1                  1
ステートメント           6           5     105.304990      19.546978      26.364079      21.060998      20.911640                    1                  1
ステートメント           7           5     195.571134      39.048495      39.165155      39.114227      39.114200                    1                  1
ステートメント           8           5       0.690684       0.132877       0.141559       0.138137       0.138091                    1                  1
ステートメント           9           5       0.761964       0.149399       0.153738       0.152393       0.152384                    1                  1
ステートメント          10           5       0.875548       0.170642       0.181054       0.175110       0.175056                    1                  1
ステートメント          11           5       2.342203       0.421944       0.606114       0.468441       0.463933                    1                  1
ステートメント          12           5       3.441882       0.662257       0.714159       0.688376       0.688152                    1                  1
ステートメント          13           5      13.450489       2.603676       2.809561       2.690098       2.688945                    1                  1
ステートメント          14           5      25.237932       5.014145       5.071185       5.047586       5.047544                    1                  1

DB2 Express-C v9.7.0

タイプ         番号        反復回数    合計回数       最小回数       最大回数       算術平均       幾何平均       行が取り出されました 行が出力されました
-------------- ----------- ----------- -------------- -------------- -------------- -------------- -------------- -------------------- ------------------
ステートメント           1           5       0.510405       0.100010       0.106235       0.102081       0.102051                    1                  1
ステートメント           2           5       0.805768       0.156104       0.168043       0.161154       0.161081                    1                  1
ステートメント           3           5       1.147170       0.225266       0.238035       0.229434       0.229386                    1                  1
ステートメント           4           5       4.018960       0.789354       0.817881       0.803792       0.803702                    1                  1
ステートメント           5           5       7.652550       1.510006       1.556505       1.530510       1.530418                    1                  1
ステートメント           6           5      40.178374       7.242845      11.093872       8.035675       7.912179                    1                  1
ステートメント           7           5      72.440617      14.412380      14.569646      14.488123      14.488007                    1                  1
ステートメント           8           5       0.500120       0.097809       0.104628       0.100024       0.099988                    1                  1
ステートメント           9           5       0.571181       0.109513       0.118653       0.114236       0.114189                    1                  1
ステートメント          10           5       0.646335       0.126758       0.136715       0.129267       0.129213                    1                  1
ステートメント          11           5       1.310628       0.257969       0.266457       0.262126       0.262107                    1                  1
ステートメント          12           5       2.068233       0.409064       0.419965       0.413647       0.413628                    1                  1
ステートメント          13           5       8.935340       1.745314       1.826181       1.787068       1.786793                    1                  1
ステートメント          14           5      16.899590       3.323222       3.426773       3.379918       3.379700                    1                  1

いずれも、ステートメント1〜7がもともとのクエリ、ステートメント8〜14が書き換えた後のクエリ。
見てのとおり、2種類のクエリの実行時間には明らかな差がある。
上記の記事の内容から推測すると、XMLEXISTSは、条件にマッチするXML要素のシーケンスを実際に生成するのではないだろうか。そのシーケンスが空であればXMLEXISTSは偽となるし、空でなければ真となる。
もともと問題となっていたクエリでは、返される要素は"h_nnnn"であるため、すべての要素に関して条件にマッチするかどうかを調べなければならない。
一方、書き換えたほうのクエリでは、返される要素は"hoge"であるため、条件にマッチする要素"h_nnnn"が1つ以上あるかどうかをチェックすればよい。
というのが私の推測。