私がXMLデータベースに期待するものは、スキーマのない巨大XML文書に対する高速なクエリです。その理由に関して語り出すと2~3日語る必要が生じかねないので、それは割愛します。
しかし、それを得意とするNeoCore XMSやTX1はべらぼうに高価であり、とても買えません。
そこで目に付いたのが、SQL Server 2005です。RDBではありますが、XML型やXQueryをサポートしており、Express Editionなら自作プログラムに無料で付けることもできます。多少の問題は目を閉じるとして、これが使えればコスト的に大変に嬉しいことになります。
というわけで、軽く評価してみました。
ただし、私自身はSQL Server 2005について素人同然の存在なので、正しい評価を下しているかどうかは分かりません。ですから、以下の内容は眉に唾を付けて読むように!
環境 §
- 対象: SQL Server 2005 CTP September
- マシン: Pentium III/733 Memory 384MB
- OS: Windows 2000 WS SP4
- インストール状況: OSからクリーンインストール。SQL Server 2005に必要なソフト以外は何も入れていません
マシンが貧弱すぎるねぇ~。でもテストマシンはこれになってしまうのよ。貧乏人は悲しいねぇ~。お金儲けてパソコンを買いたいというと、マニアだと誤解する人が多いけれど、そうではないのよ。
ちなみに、計測後に比較対象としてXprioriをインストールしていますが、もちろん同じ貧弱なハードで動いているので、特に大きなハンデではないはずです。
参考文書 §
Microsoft SQL Server 2005 での XML サポート
SQL Server 2005 CTP Septemberのインストール §
忘れずにIISを入れておくこと。
先にMDAC 2.7を入れておくこと。
以上2点に注意するだけで、インストールは完了しました。
ただし、クリーンインストールではないWindows 2000 WS上でインストールを試みた際には、セットアップが途中で失敗するという問題が生じました。(とはいえ、他のソフトのベータ版など、怪しいものは多数入った環境だったので、何が問題であったのかは不明。失敗したのは、どうも.NET Framework 2.0 Betaのインストールに関してらしい)
手動での管理方法 §
SQL Server Management Studioというものを使います。
昔のEnterprise Managerの後継ソフトという感じでしょうか?
通常のWindowsアプリケーションで、最近流行りのWebアプリケーション形式の管理ソフトよりも、ずっと使いやすい印象です。
ツールバーのDatabase Engine Queryのボタンをクリックすると、手動でクエリを実行するウィンドウ(という表現で良いのか?)が開きます。クエリをキーボードからタイプして、ツールバーのExcecuteボタンをクリックするとクエリが実行され、結果がウィンドウ下部に表示されます。
また下部のステータスバーに、クエリの所要時間が秒単位で表示されます。
(以下の所要時間はこの数値を転記)
DBの作成 §
とりあえず、GUIベースで、以下の3つのフィールドを持つテーブルを作成。
- ID int型整数 PrimaryKey
- Name nchar型 (これは入れてみただけでほとんど意味はない)
- Xml XML型
データを入れてみる §
Management Studioからレコードをいくつか追加してみました。
IDとNameはGUIベースで簡単に書き込めるものの、Xmlには書き込めないことが判明。クエリで書き込むしかないようです。
簡単なクエリから §
まずは、こんな感じで「全て見せてちょうだいな」というクエリを実行。
SELECT * FROM Test001.dbo.Table001
まだXMLデータを入れていないので、結果は面白くも何ともありません。
XML文書を含むレコードを追加 §
参考文書のクエリを手直しして実行。
INSERT INTO Test001.dbo.Table001 VALUES (4, N'NameValue',
'<Xml genre="security" publicationdate="2002" ISBN="0-7356-1588-2">
<title>Writing Secure Code</title>
<author>
<first-name>Michael</first-name>
<last-name>Howard</last-name>
</author>
<author>
<first-name>David</first-name>
<last-name>LeBlanc</last-name>
</author>
<price>39.99</price>
</Xml>')
これで、Xmlフィールドにも値を設定できました。
XPathを含むクエリを試す §
まず、こんなクエリを実行。
SELECT ID, Xml.query('//first-name')
FROM Test001.dbo.Table001
結果は以下のようになりました。ちなみに、ID1~3は、手動で作ってみたレコードで、Xmlに値は入っていません。
1 NULL
2 NULL
3 NULL
4 <first-name>Michael</first-name><first-name>David</first-name>
このクエリの場合、単にfirst-name要素抜き出しているだけで、first-name要素を含むレコードだけに制限する機能は含んでいません。よって、first-name要素を含む含まないに関係なく、全てのレコードが出てきます。
ここまで、思ったより順調に動いています。
ファイルからのインポート §
さて、そろそろ本番です。
スキーマのない巨大XML文書へのクエリ性能を体験するためには、それをデータベースに入れねばなりません。
テストに使用するXML文書は、XprioriのサイトにあるXprioriチューニングTips ~XML構造編~にある「XML文書のサイズが及ぼす影響」のファイルを使うことにします。
ちなみにこれは、10万個の要素を持つダミーのXML文書です。それでも、せいぜい2MBでしかなく、本当なら巨大とは言い難いものですが。
とはいえ、2MBでもクエリの一部に記述して書き込むのはおそらく無理でしょう。
このXML文書のファイルを、ファイルから取り込んで新しいレコードを作成します。
INSERT INTO Test001.dbo.Table001
SELECT 5, N'NameValue5', Xml
FROM (SELECT * FROM OPENROWSET
(BULK 's:\delme5.xml',SINGLE_BLOB) AS Xml) AS R(Xml)
所要時間27sec
インデックス設定無しでクエリを試す §
さて、きっちりとテストデータが収まったので、クエリを行ってみます。
上記記事の2つのクエリ(XPath式)とちょっと違うものを使ってみます。
以下の2つです。
- //list/e50000
- //list/*[.='50000']
では、さっそく実行。
SELECT ID, Xml.query('//list/e50000')
FROM Test001.dbo.Table001
所要時間1sec
SELECT ID, Xml.query('//list/*[.="50000"]')
FROM Test001.dbo.Table001
所要時間5sec
最初の方は、すぐに結果が戻ってきて悪くない感じです。
しかし、後者は5秒もかかり、もたつきます。
現時点ではインデックスを設定していないので、まだ楽観しています。
XML プライマリ インデックスを作る §
まず、XML プライマリ インデックスを作成してみます。
CREATE PRIMARY XML INDEX idx_Xml on Test001.dbo.Table001 (Xml)
所要時間5:03
かなり時間が掛かっています。
さて、クエリを実行してみます。
SELECT ID, Xml.query('//list/e50000')
FROM Test001.dbo.Table001
所要時間5sec
あれ!? 5秒って性能ダウン!?
もう一度実行すると速くなりました。
所要時間0sec
0秒というのは、実行時間をまるめると0になってしまうということなのでしょう。
もう1つのクエリも実行。
SELECT ID, Xml.query('//list/*[.="50000"]')
FROM Test001.dbo.Table001
所要時間8sec
所要時間8sec
あれれ?
これは5秒から8秒に性能低下?
しかも、2回やっても結果は同じ?
VALUE インデックスを作る §
遅くなったりするのは、インデックスの問題だろうか。
というわけで、次は、3種類あるXML セカンダリ インデックスを1つずつ作ってみます。
まずVALUE インデックスを作成してみます。
CREATE XML INDEX idx_Xml_Value on Test001.dbo.Table001 (Xml)
USING XML INDEX idx_Xml FOR VALUE
所要時間11sec
クエリその1。
SELECT ID, Xml.query('//list/e50000')
FROM Test001.dbo.Table001
所要時間0sec
所要時間0sec
クエリその2。
SELECT ID, Xml.query('//list/*[.="50000"]')
FROM Test001.dbo.Table001
所要時間8sec
所要時間8sec
いずれも変化無し。
PATH インデックスを作る §
次は、3種類あるXML セカンダリ インデックスのうち、PATH インデックスです。
まずは作成。
CREATE XML INDEX idx_Xml_Path on Test001.dbo.Table001 (Xml)
USING XML INDEX idx_Xml FOR PATH
所要時間7sec
クエリその1。
SELECT ID, Xml.query('//list/e50000')
FROM Test001.dbo.Table001
所要時間0sec
所要時間0sec
クエリその2。
SELECT ID, Xml.query('//list/*[.="50000"]')
FROM Test001.dbo.Table001
所要時間8sec
所要時間8sec
やはり変化なし。
PROPERTY インデックスを作る §
次は、3種類あるXML セカンダリ インデックスのうち、PROPERTY インデックスです。
まずは作成。
CREATE XML INDEX idx_Xml_Property on Test001.dbo.Table001(Xml)
USING XML INDEX idx_Xml FOR PROPERTY
所要時間6sec
クエリその1。
SELECT ID, Xml.query('//list/e50000')
FROM Test001.dbo.Table001
所要時間0sec
所要時間0sec
クエリその2。
SELECT ID, Xml.query('//list/*[.="50000"]')
FROM Test001.dbo.Table001
所要時間8sec
所要時間8sec
やはり変化なし。
Xpriori §
以上が完了した後、比較対象としてXprioriをインストールしてみました。
念のために付記するとXprioriはNeoCore XMSの機能制限された無償バージョンです。NeoCore XMSは、おそらく日本国内のXMLデータベースの世界でユーザー支持度ナンバーワンの製品です。
これに対して、同じXML文書をインポートした後で、以下の2つのクエリを実行。
- //list/e50000
- //list/*[.='50000']
いずれも一瞬で戻ってきました。僅かな引っかかりも感じられません。極めて速いです。
結論 §
というわけで、スキーマのない巨大XML文書へのクエリという意味では、現時点でのSQL Server 2005はほとんど話にならない水準の性能しか発揮できないことが確認できました。とてもXMLデータベースとしてNeoCore XMSやTX1と戦える余地はないでしょう。
とはいえ、これはSQL Server 2005にとってフェアな評価ではありません。SQL Server 2005はあくまでRDBであり、RDBの不十分な点を補うためにXML型を導入しているに過ぎません。XML文書は、RDBのフィールドの1つとして扱われるものであり、必然的に小さなデータを多数格納することが想定されます。しかも、速度を上げたければスキーマを使えであるとか、データをXML型ではなく通常のRDBの型のフィールドに入れるべきだとしています。このようなソフトが、スキーマのない巨大XML文書へのクエリ性能をカリカリにチューニングしていると期待する方が間違いでしょう。
しかし、私個人の立場で言えば、様々な理由からスキーマのない巨大XML文書を扱うデータベースを必要としています。特にデータベースのリファクタリングを想定すると、全データが単一のツリーであってくれないと困るのではないか、という気持ちがあるのです。つまり、ツリーを分割して格納したくはないのです。これまで分割されていたデータも1つにまとめたいと思っているぐらいなので、分割は好ましい選択ではありません。
最後に付記しておくと、この結論は確定したものでも、確実なものでもありません。使用しているソフトも最終形ではありませんし、使っている私も、このソフトの使い方を正しく理解していない可能性があります。
というわけで、以上の内容は眉に唾を付けて読むように!
2005年9月28日追記 §
xml-usersメーリングリストのこの話題に関するスレッド