発端
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つ以上あるかどうかをチェックすればよい。
というのが私の推測。