Technical Articles
SAP HANA Cloud, Data Lake 追加インデックスについて
はじめに
これまで2つのブログ(HANA Cloud, Data Lake First step と SAP HANA Cloud, Data Lake に AWS S3 bucketからインポートする)でインメモリアーキテクチャを持つSAP HANA Cloudにデータのスケーラビリティを提供するSAP HANA, Data Lake (以下Data Lake) についてとりあげました。そしてその中でData Lakeは最も古いカラムストアアーキテクチャを持つRDBMS製品であるSAP IQがベースになっている事をお知らせしました。すでにオンプレミスでSAP IQをご利用いただいている方はご存知の事でも、Data Lakeで初めてSAP IQのアーキテクチャに触れるというユーザの方もいると思いますので、このブログではData Lakeの高速化に重要なインデックスについてとりあげてみようと思います。
HANA Cloud, Data Lakeの基本的なデータ格納方式(デフォルトインデックス)
Data Lake(とその基盤技術を共通にするSAP IQ)が採用しているカラムストアアーキテクチャは、こちらの図で示した様に従来のRDBMSとは大きく異なるデータの格納方法を採用しています。下の図では、シンプルな売り上げ明細のテーブルを、Data Lakeに格納した時のモデルを示しています。
この格納方式は、テーブルに存在するすべてのカラムにインデックスが付与されるのに近い効果があります。なぜなら全てカラムごとにデータが集約されている事、そしてData Lakeの内部で自動生成される辞書圧縮アルゴリズムは (図の灰色の符号化構造) 、カラムに含まれるデータの行を特定するのに有効だからです。例えば店舗名のカラムを例にしてみましょう。この明細テーブルから「永田町店」の売り上げだけを集計することを考えてみましょう。この場合、いつ、どんな商品が、いくつ売れたかは関係ありません。従って金額のカラムと、店舗名のカラムだけを参照すればよく、全体のデータのうちの2つのカラムだけを処理すればよくなりますので、処理コストが半減します。さらに、店舗名の辞書テーブル (Lookup Table) から「永田町店」は内部的に3bitの「001」と符号化されているのが判ります。つまり店舗名カラムに格納されている 3bit という非常に小さなサイズのデータを比較評価して適合する行を抽出できるのです。そして抽出された行の金額を集計することになります。もとのデータは「永田町店」というvarchar型の 20Byte だったデータ(実際には可変文字型のサイズなので12Byte)が、3Bit(Byteではなく、Bitであることにご留意ください)で表現されているということは、このカラムを評価する場合のデータのサイズが大幅に小さくなって (12Byte × 8Bit = 96Bit に対し3Bit) いる事がお分かりいただけるでしょうか。
このようなアルゴリズムでData Lake内部のデータは格納されるため、テーブルに対する検索処理(select文)の処理が非常に高速になるのがこのアーキテクチャの特徴となっています。なお、このFPインデックス化のために何か特別な処理(手順や操作)が必要なわけではありません。通常のSQL文のINSERT / UPDATEや、インポート処理(バッチ処理 / バルクインサート)を行えば、Data Lakeがこのデータ構造に自動的に変換するので、ユーザが意識する事はありません。この格納方式がデフォルトのデータ格納方式(デフォルトインデックス)であり、このインデックス方式を Fast Projection (FP) インデックスと呼びます。
FPインデックスについてもう少し説明します。上記の店舗名カラムはここでは5つの店舗しかない例を示していました。この場合5種類のデータを表現できればいいので、IDを付与する場合に必要なのは3Bitでした。しかし、3Bitで表現できるデータの種類は8種類です(二進法で000から111まで)。では店舗数が増えて9店舗を持つ場合はどうなるでしょうか。Data Lakeはこの場合は自動的にIDに必要なBit数を増やして4Bitに、さらに4Bitで表現できるデータの種類(二進法で0000から1111まで)の16を超えるとさらに5Bitと自動的にIDに必要なデータサイズに拡大します(下の表参照)。そしてこの動作は完全に内部的な処理であり、Data Lakeを利用するお客様、及び管理者からは意識させることはありません(このような動きになっていることを知る必要もないくらいです)。
カージナリティの数に応じたBit数
データ格納に 必要なBit数 | カラムの値の カージナリティ | データ格納に必要なBit数 | カラムの値の カージナリティ | |||
1 | 2 | 17 | 131972 | |||
2 | 4 | 18 | 262144 | |||
3 | 8 | 19 | 524288 | |||
4 | 16 | 20 | 1048576 | |||
5 | 32 | 21 | 2097152 | |||
6 | 64 | 22 | 4194304 | |||
7 | 128 | 23 | 8388608 | |||
8 | 256 | 1Byte | 24 | 16777216 | 3Byte | |
9 | 512 | 25 | 33554432 | |||
10 | 1024 | 26 | 67108864 | |||
11 | 2048 | 27 | 134217728 | |||
12 | 4096 | 28 | 268435456 | |||
13 | 8192 | 29 | 536870912 | |||
14 | 16384 | 30 | 1073741824 | 2 ^ 30 | ||
15 | 32768 | 31 | 2147483647 | 2 ^ 31-1 | ||
16 | 655536 | 2Byte | 実データサイズ | > 2147483647 |
さて、そうなるとデータの種類が増えると無尽蔵にID用のデータのサイズが大きくなってしまうのでは、という疑問がわくと思います。このID用のデータサイズは31bitが上限になっており、それ以上のID用のデータサイズが必要になった場合は、この辞書圧縮が適用されずに実データそのものが格納されるようになります。31Bitとは4Byteに1Bit欠けるサイズですので、このIDのサイズはいくら大きなサイズになっても4Byte以上のサイズになることはありません。ところで31BitのID用のデータサイズが使い切るにはどれくらいのデータの種類(先ほどの店舗名の例であれば何店舗か)になるでしょうか。答えは2,147,483,647(約21億)です。つまり約21億件のユニーク(重複のない)なデータを含むテーブルの場合は、この辞書圧縮が有効でなくなることになりますが、この規模のユニークな値を持つテーブルはそう多くはないでしょう。ご注意いただきたいのはテーブルの件数が約21億というわけではなく、ユニークな値が約21億を超える場合という事です。また、仮に約21億を超えるデータがある場合でもデフォルトのインデックスが持つ辞書圧縮アルゴリズムが適用されなくなるだけで、実際のデータが格納されますので、データベースとしては何の不備もありません。辞書圧縮を用いた非常に効率的な検索が適用できなくなるだけ(該当するカラムだけです!)です。そしてこのような場合にも、この後にご説明する追加のインデックスをご利用いただければ検索の高速化が可能になりますのでご心配はいりません。
追加インデックス
ここまででデフォルトのデータの格納方式(FPインデックス)に関して説明してきましたが、Data Lakeではさらに高速化を図るために追加のインデックスが用意されています(先ほどの約21億を超えるのユニークな値を持つカラムにも有効です)。追加できるインデックスの種類は以下のようになっています。
High Group (HG) | カージナリティの高いデータの結合と、グループ化操作に有効な拡張bツリーインデックス。 |
Word (WD) | VARCHARおよびLONG VARCHARデータ型のカラムの内容を区切り、単語ごとにインデックス化します。このインデックスは現在の所、わかち書きが可能な言語で有効であり、英文などのテキストや、URL、メールアドレスに有効です。 |
Date (DATE) | DATE データ型のカラムに使用します |
Time (TIME) | TIME データ型のカラムに使用します |
Datetime (DTTM) | DATETIME / TIMESTAMP データ型のカラムに使用します |
Compare (CMP) | 同一のデータ型、精度、スケールを持つ2つの異なる列に比較インデックス(2つの列のバイナリ比較(<、>、または=))を格納します。 |
この中で特に重要な追加インデックスはHGです。カージナリティとは、カラムに含まれるデータの種類がどれくらいあるかを意味する言葉ですが、例えば性別や都道府県は非常にカージナリティは低く、金額や、IDはカージナリティが高いと言えます。HGインデックスはカージナリティが概ね1,000を超えるデータを持つカラムに対して追加すると効果的なインデックスと指針が示されています。主キーや外部キーとなるカラムや、where句の検索条件に使われるカラムで、かつカージナリティが1,000を超えるカラムには、このHGを付与すると効果的です。
また、DATE、TIME、DATETIME、TIMESTAMPといった日付データ型も検索条件に使われる場合が多いので、これらのインデックスを付けてください。なお、日付をchar型に格納する場合もあると思いますが、その場合はHGインデックスを選択してください。
WDインデックスは、上記の概略にあるように、英語のようなわかち書きで記述される言語の場合に単語ごとにインデックス構造を作ることができますが、日本語は単語ごとに区切る仕組みが今のところサポートされていないので、有効に使う事はできません。
CMPインデックスは、同じテーブルに含まれる同じデータ型を持つ列と列を比較する場合に有効なインデックスで、単独のカラムに付与する事はできません。2つのカラムの大小比較を高速に処理します。指定したカラムの比較結果をあらかじめ保存し、多数のローにわたり、売値カラムと買値カラムの大小関係の判定結果を高速に得たい、というような場合に適用します。
SAP IQを以前よりお使いのお客様の中には、従来のSAP IQが持つ追加インデックスのLow Fast (LF) とHigh Non Group (HNG) タイプのインデックスをご存知のことと思いますが、現在はHGインデックスを利用する事が推奨されており、SAP IQでの互換のために残された機能となっています。Data Lakeではこれらのインデックスは使えませんのでご注意ください。
上記のような指針に基づき、追加のインデックスを付与する事で、より高い検索性能を得ることができるようになります。
追加インデックスに伴うコスト
追加インデックスは、文字通りデフォルトインデックスに追加するデータインデックス構造ですので、追加インデックスに伴いストレージ領域の追加が必要になることと、データの追加 / 更新の際の処理コストが増加する事を認識しておく事は重要です。しかしながら、Data Lakeの追加のインデックスを処理するリソース(主にストレージ)と、インデックスの追加に伴う処理時間の増加は、インデックスを追加したことによる検索処理性能の向上の効果と比較して大きな負担にはならないはずです。とはいえ、レコード件数の大きなテーブルの場合はそれなりのコストも発生しますので、最終的には検索のパフォーマンスと、前述のコスト(特に更新に伴う時間)を比較して判断すべきですが、積極的にこれらの追加のインデックスを利用する事をお勧めします。
追加インデックスの作成方法
最初に説明した通り、Data Lakeにデータを格納(Insertでもインポートでも)すればFPインデックスが作成されますので、追加インデックスを新たに付与する場合にのみ、以下の手順でカラムごとにインデックスを追加することになります。
追加のインデックスを作成するには、SAP IQのcreate index構文を、HANA Cloudで実行するためのREMOTE_EXECUTEプロシージャにラップして使用します。この手順についての詳細は、こちらのブログでご確認下さい。
CALL SYSRDL#CG.REMOTE_EXECUTE('
CREATE インデックス種別 INDEX インデックス名 ON テーブル名(カラム名);
');
例えば、HGインデックスを SALES_ORD_ITEMSテーブルの SHIP_TGT カラムに、さらにDATEインデックスをSHIP_DATEカラムに追加する場合は以下の様になります。ここでは、複数のData Lake用のクエリを並列で実行するためのオプション、「begin parallel iq」も使用しています。
CALL SYSRDL#CG .REMOTE_EXECUTE('
begin parallel iq
CREATE HG INDEX SHIP_IDX ON SALES_ORD_ITEMS(SHIP_TGT);
CREATE DATE INDEX SHIP_IDX ON SALES_ORD_ITEMS(SHIP_DATE);
end parallel iq;
');
HANA Cloudと同じとはいかないまでも、これらの追加のインデックスの効果を生かすことで、件数の大きなデータの検索処理に高い効果を発揮する事ができますので、Data Lakeを積極的に利用してみて下さい。