このページでは Teiid または Teiid Data Virtualization と呼ばれるミドルウェアの簡単な紹介を行う。
Teiid に関する他のページはTeiid Data Virtualization の覚え書きのインデックスからたどれる。
更新履歴
(2016.05.02) 作成。
目次
1. データ仮想統合とは
データ仮想統合(Data Virtualization) とは、複数の異なる情報を単一のフォーマットに見せる技術全般を指す。 例えば、
- Oracle、MySQL、PostgreSQL のような様々なデータベースが運用されているが相互アクセスしたい。
- Active Directory と NIS+ で別々に管理しているユーザーアカウントを統合して LDAP として公開したい。
- NFS、CIFS、FTP で公開されているファイルを一つにまとめて WebDAV で公開したい。
のような機能を提供する。 重要なのは複数のデータを一つに集約せずに、統合を果たしたのと同じ効果をリアルタイムに得ることである。
例えば社内に Oracle、SQL Server、MySQL と異なるデータベースがあるとする。 すべてを Oracle に統合しようとすると Oracle 以外を使っていた部署のシステムの書き換えが必要になりコスト的・政治的に難しい。 Oracle 以外のデータベースをそのまま残して、ETL ツールで Oracle DB に定期的に転送するというやり方では、リアルタイムのデータを見ることができなくなる。 データ仮想統合を使えば、元のデータベースはそのまま残して、その上に仮想的な統合データベースを構築することができる。
データ仮想統合の具体的な製品としては、Cisco Data Virtualization Platform、Red Hat Jboss Data Virtualization(JDV) がある。 JDV は、その OSS 版として Teiid が公開されている。 このページでは Teiid の解説を行う。
2. Teiid とは
Teiid は最初 MetaMatrix 社によって開発されたが、Red Hat に会社ごと買収された。
その後、Red Hat 社が別途買収した BEA 社の JBoss Enterprise Application Server (EAP) 上で動くサービスとして組み込まれて現在に至る。
Teiid 8.13 からは、その動作基盤が JBoss EAP ではなく、JBoss EAP の OSS 版の WildFly に変更された。
Teiid はデータ仮想統合の中でもデータベースの仮想統合(のみ)を実現する。 統合の対象にできるデータベースは Oracle のようなリレーショナル・データベース、Cassandra や MongoDB のような NoSQL、Web Service、CSV/XML/Excel のようなファイルなど多岐に渡る。 純粋なデータベース以外のデータも統合の対象にすることができるので、データベースではなくデータソース(Data Source)を統合すると呼ぶことにする。
Teiid は様々なデータソースを統合して仮想データベースを作り、データソースのテーブルを仮想テーブルとしてまとめあげる。 クライアントは Teiid にコネクションを張り、単一のデータベースに対するように SQL クエリーを実行する。 Teiid は SQL クエリーを受けて自動的に各データソースにクエリーを投げて結果を統合して返してくれる。
そのため Teiid は Oracle の dblink や PostgreSQL の Foreign Data Wrapper(FDW) に近い。 ただし以下のような点で有利である。
- サポートしているデータソースの種類が多い
- データ仮想統合の専業だけあり、対応しているデータソースの種類が多い。
Teiid はデータソース毎に トランスレータ(Translator) と呼ぶ変換ライブラリを持ち、トランスレータは 50 種類近く存在する。
ユーザーは新しいデータベース製品に対するトランスレータを書くことができる。
Teiid のトランスレータを書くのは、少なくとも PostgreSQL の FDW を書くよりは簡単である。 - Virtual Database の定義
- Teiid は仮想データベースを XML 形式の Virtual Database(VDB) ファイルにまとめる。 このファイル中にデータソースの種類・定義のみならず、データベース内に存在するインデックス、PRIMERY KEY や FOREIGN KEY などの制約も記述することができる。 1 台の Teiid インスタンスは複数の仮想データベースを走行することができるし、動的に追加(デプロイ)・削除(アンデプロイ)・バージョンアップすることも可能である。
- 専用 GUI ツールによる操作
- Eclipse をベースとした Teiid Designer が存在し、データソース内を閲覧しながらどのテーブルを VDB に加えるのかを操作することができる。 FOREIGN KEY などを認識して ER 図を表示することもできる。 非常に強力である。
- 優れた Federated Planning
- 統合した仮想データベースに投げられた SQL クエリーは、配下の物理データベースに分解されたクエリーとして投入される。 この時、SQL クエリーをどのように分解するかは様々な最適化があるのだが、Teiid はこの点が非常に優れている。 この点は 3. でさらに詳しく解説する。
- OLAP 機能のサポート
- 集約関数、Window 関数、ROLLUP に対応している(WITHIN GROUP や ROLLUP 以外の CUBE や GROUPING は未対応)。 テーブル結合機能を持たない NoSQL をデータソースにしてテーブル(相当機能)を JOIN したり、Window 関数機能を持たない MySQL をデータソースにして Window 関数を事項することができる。
- User Defined Function
- Java で User-Defined Function 関数を書くこともできる。 これは Teiid 層で実行されるが、データベース種類を越えて実行が可能。
- XML のサポート
- Teiid はデータ型として XML 型と XQuery による問い合わせをサポートしている。 データソース側が XML 型をサポートしている場合、Federated Planning が効くようだ。
- JSON のサポート
- Teiid は JSON に対する操作関数を多少備えている。 専用の JSON 型はなく、あまり積極的なものではない。
- 分散トランザクションの自動実行
- Teiid は複数のデータソースに単に問い合わせ(SELECT)をするだけではなく、INSERT/UPDATE/DELETE も実行可能だ。
また BEGIN 〜 COMMIT で囲ったトランザクションを受け付けている。
この時、トランザクションが複数のデータソースへのアクセスしていれば、各データソースの処理を 2相コミットで処理する。
つまりユーザーは仮想データベースに対する普通のトランザクションを書けば、自動的に分散トランザクションへ変換してくれる。
ただしこの機能を使うにはデータソースが JDBC/XA をサポートしている必要がある。 - 仮想的なセキュリティ機能の付加
- データソース側に存在するセキュリティ機能とは別に、Teiid が仮想的なセキュリティ機能を提供する。
これはデータソースが持っていない機能を統一的に実施できる点が優れている。
- クエリー実行権限の設定
- Teiid は JBoss のアカウント管理機能を利用して一般的なロールベースの権限定義を行うことができる。 仮想テーブル単位あるいは仮想テーブルのカラム単位に CREATE、READ、UPDATE、DELETE(CRUID) を許可・禁止できる。
- Row-Based Security
- Oracle の Label Security や PostgreSQL の 行セキュリティポリシー(Row Security Policies) のような機能を提供する。
このセキュリティ機構を簡単に言うと、
SELECT * FROM TBL WHERE condition
のようなクエリーを投げる時に、自動的にSELECT * FROM TBL WHERE row-based-security-conditions AND condition
を追加してくれる機能である。 Row-base security の条件は複数付ける事が可能だが、その場合(全ての条件を満たさないとアクセスできないのではなく)どれか1つでも条件が成立すればアクセス可能となる。 - Column Masking
- 特定のカラムを条件によってマスクする機能である。
例えばパスワードフィールドは一般ユーザーからアクセスする場合は生の値を返すのではなく '***' のようにマスクした値を返したいという使い方ができる。
要は通常の SQL の中に
CASE WHEN condition1 THEN mask1 WHEN condition0 THEN mask0 ELSE column
を挿し込んだ形になる。
- キャッシュ機能
- おまけ的な機能だがキャッシュがある。
- Query Cache
- SQL クエリーの結果を保存して、次回の呼び出しを高速化する。
- Materialized View
- 問い合わせを Teiid 内で一時的に保存してビュー形式で見せる。
これ以外の特徴としては、
- JBoss 連携が可能なので、仮想データベースを使った Web サービスを公開するのが簡単。
- Sharding による分割テーブルを定義できる。同一定義のテーブルを公開している複数のデータソースを束ねることが可能。
- Conformed Tables を使い同一内容のテーブルを定義できる。Federated Planning は最適化されたアクセスをすることができる。
3. Federated Planning
Teiid の federated query に対する最適化を紹介する。
3.1 Pushdown
Teiid はクライアントから渡された SQL クエリーを効率的に分解する。 例えば TPC-H の orders、lineitem というテーブルが DS1 にあり、customer というテーブルが DS2 にあり、Teiid 上で仮想データベースが作られたとする。

そこに以下のようなクエリー(実際は TPC-H の Query 3)が投入されたとする。
SELECT l_orderkey, sum(l_extendedprice * (1 - l_discount)) AS revenue, o_oderdate, o_shippriority FROM customer, orders, lineitem WHERE c_mktsegment = 'MACHINERY' AND c_custkey = o_custkey AND l_orderkey = o_orderkey AND o_orderdate < date '1995-03-09' AND l_shipdate > date '1995-03-09' GROUP BY l_orderkey, o_orderdate, o_shiporiority ORDER BY revenue DESC, o_orderdate LIMIT 10;
Teiid は TPC-H Query3 を分解し、以下のように DS1 と DS2 に投げ、その結果を Teiid 自身によって統合する。
Teiid 自身の処理 |
SELECT l_orderkey, revenue, o_oderdate, o_shippriority FROM DS1, DS2 WHERE c_custkey = o_custkey ORDER BY revenue DESC, o_orderdate LIMIT 10; |
---|---|
DS1 |
SELECT o_custkey, l_orderkey, o_oderdate, o_shippriority, sum(l_extendedprice * (1 - l_discount)) AS revenue FROM orders, lineitem WHERE l_orderkey = o_orderkey AND o_orderdate < date '1995-03-09' AND l_shipdate > date '1995-03-09' GROUP BY l_orderkey, o_orderdate, o_shiporiority; |
DS2 |
SELECT c_custkey FROM customer WHERE c_mktsegment = 'MACHINERY'; |
このようにデータソース側で実行可能な処理は極力データソース側で実行するという最適化を行う。 このような最適化を Pushdown と呼ぶ。
Pushdown にも様々な種類がある。
- WHERE 句などに指定されたフィルター条件をデータソース側で実行する Predicate Pushdown
- テーブル間の JOIN をデータソース側で実行する Join Pushdown
- 集約関数をデータソース側で実行する Aggregation Pushdown
Teiid は上記の全ての pushdown を完備しており、可能な限りデータソース側に pushdown する。 前述のトランスレータはデータベース製品の機能のリストを持っているので、Teiid はどの操作が pushdown 可能でどの操作ができないかを正確に判断できる。 もちろんデータソース側に pushdown できない操作は Teiid で実行することで、データベース製品の機能差を吸収することができる(その場合、性能は犠牲になる)。
Teiid はデータソース側の統計情報を持たないため、コストベースのプラニングができない。 データソース側で実行するよりも Teiid 側で実行してしまった方が高速なパターンもあるのだが無条件 pushdown する。 Teiid には pushdown を止める一時的に止めるオプションが存在しない。
3.2 Depedent Joins
リレーショナル・データベースにおいてテーブルの結合(Join)は性能を左右する最重要項目である。 Teiid にとっても Join が重要なのは論を待たない。
Join に対して Teiid の federated planning は各データソースにクエリーを投げて、その結果を Teiid 内の nested loop または sort merge join で処理する(2016年5月現在、Teiid に hash join アルゴリズムは実装されていない)。
fig-2 では RDB1 にある 1,000 行のテーブル TBL1 と RDB2 にある 2,000 行のテーブル TBL2 を equi-join するイメージだが、TBL1 と TBL2 を全て Teiid に読み込んで Join することになる。

この処理方法は Teiid 側に大量のデータを読み込むので、Teiid の処理負荷が高くなる。 またデータソース側にインデックスがあっても利用することができない。
そこで Teiid は(可能であれば) Dependent Join という最適化を行う。 これは RDB1 から読み込んだデータを RDB2 に送り込んで、RDB2 側で Join をするという特殊な Join pushdown である。 fig-3 のように RDB2 のテーブル TBL2 にインデックスがあった場合に発動し易い。 その処理の流れは
- Teiid が RDB1 のテーブル TBL1 からスキャンする。1,000 行を取得できる。
- Teiid は RDB2 のテーブル TBL2 にスキャンを要求するが、この際に
SELECT * FROM TBL2 WHERE key IN (row1, row2, row3, row4, ....)
のように TLB1 からのスキャン結果を並べる。 - RDB2 は SELECT の結果を返すが、これが元の JOIN の結果に近いものになっている。
このような dependent join は、データソース間をまたがる Join 処理を、片方のデータソースに押し込めることができる。 インデックスがある場合、RDB2 の selectivility が低い場合には、Teiid でやるよりも高速となる。

Step 2 の SELECT の IN 句は TBL1 からの入力結果を並べるので、SQL クエリーの文字列は長大になる。 そのため TBL1 のスキャンの結果行をある程度分割して、複数回 Step 2 の SQL を発行することもある。
また JDBC ドライバーが対応している場合、IN 句の後は結果行の値を文字列化して並べるのではなく、オブジェクトストリームで転送することがある。 またデータベース側が許すなら一時テーブルを作って処理することもできる。
この手法を Dependent Join と呼ぶのが一般的なのかどうか不明。 PostgreSQL の内部では Parameterized Join と呼ばれている。
4. Embedded Teiid
Teiid は JBoss EAP 上で動作するのだが、独立した Java プログラム中で Teiid の機能だけを使う Embedded Teiid が存在する。