Teiid Data Virtualization とは

作成日:2016.05.02

このページでは Teiid または Teiid Data Virtualization と呼ばれるミドルウェアの簡単な紹介を行う。

Teiid に関する他のページはTeiid Data Virtualization の覚え書きのインデックスからたどれる。


更新履歴
(2016.05.02) 作成。


目次

1. データ仮想統合とは

データ仮想統合(Data Virtualization) とは、複数の異なる情報を単一のフォーマットに見せる技術全般を指す。 例えば、

のような機能を提供する。 重要なのは複数のデータを一つに集約せずに、統合を果たしたのと同じ効果をリアルタイムに得ることである。

例えば社内に Oracle、SQL Server、MySQL と異なるデータベースがあるとする。 すべてを Oracle に統合しようとすると Oracle 以外を使っていた部署のシステムの書き換えが必要になりコスト的・政治的に難しい。 Oracle 以外のデータベースをそのまま残して、ETL ツールで Oracle DB に定期的に転送するというやり方では、リアルタイムのデータを見ることができなくなる。 データ仮想統合を使えば、元のデータベースはそのまま残して、その上に仮想的な統合データベースを構築することができる。

データ仮想統合の具体的な製品としては、Cisco Data Virtualization PlatformRed 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 内で一時的に保存してビュー形式で見せる。
ただし Teiid のキャッシュ機能、特に query cache、は仮想統合ゆえの弱点を抱えている。 Teiid 経由で INSERT/UPDATE/DELETE が実行された場合はキャッシュを無効化できるのだが、データソースに対して直接データ更新が行われた場合は Teiid はキャッシュをパージするタイミングを得られず誤った結果を返してしまう。 つまりあまり使えない。

これ以外の特徴としては、

3. Federated Planning

Teiid の federated query に対する最適化を紹介する。

3.1 Pushdown

Teiid はクライアントから渡された SQL クエリーを効率的に分解する。 例えば TPC-H の orders、lineitem というテーブルが DS1 にあり、customer というテーブルが DS2 にあり、Teiid 上で仮想データベースが作られたとする。

fig-1: DS1、DS2を含んだVDB
DS1、DS2を含んだVDB

そこに以下のようなクエリー(実際は 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 にも様々な種類がある。

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 することになる。

fig-2: 基本的な JOIN の処理フロー
基本的な JOIN の処理フロー

この処理方法は Teiid 側に大量のデータを読み込むので、Teiid の処理負荷が高くなる。 またデータソース側にインデックスがあっても利用することができない。

そこで Teiid は(可能であれば) Dependent Join という最適化を行う。 これは RDB1 から読み込んだデータを RDB2 に送り込んで、RDB2 側で Join をするという特殊な Join pushdown である。 fig-3 のように RDB2 のテーブル TBL2 にインデックスがあった場合に発動し易い。 その処理の流れは

  1. Teiid が RDB1 のテーブル TBL1 からスキャンする。1,000 行を取得できる。
  2. Teiid は RDB2 のテーブル TBL2 にスキャンを要求するが、この際に SELECT * FROM TBL2 WHERE key IN (row1, row2, row3, row4, ....) のように TLB1 からのスキャン結果を並べる。
  3. RDB2 は SELECT の結果を返すが、これが元の JOIN の結果に近いものになっている。

このような dependent join は、データソース間をまたがる Join 処理を、片方のデータソースに押し込めることができる。 インデックスがある場合、RDB2 の selectivility が低い場合には、Teiid でやるよりも高速となる。

fig-3: Dependent Join の処理フロー
Dependent Join の処理フロー

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 が存在する。

コメント

コメントを書き込む
[1] [名無しさん] 2016-05-03 10:41:10
「2. Teiid とは」に、「BEA 社の JBoss Enterprise Application Server (EAP) 上」とありますが、BEAではなくJBoss Inc.ですよね。
[2] [管理人] 2016-05-08 14:31:08
ご指摘ありがとうございます。確かに BEA は関係ありませんでいsた。

TOP    掲示板    戻る
Written by NAKAMURA Minoru, Email: nminoru atmark nminoru dot jp, Twitter:@nminoru_jp