OBKV-HBaseのクエリの元の実装は、全範囲スキャン戦略を採用しており、すべての列修飾子(Qualifier、つまり列名)のデータをスキャンしてからフィルタリングを行います。この方法では、サーバー側で膨大な冗長なスキャンと処理オーバーヘッドが発生し、特にワイド行やマルチバージョンの行に対するクエリで少数の列のみが関与する場合、遅延が顕著になります。
本記事では、OBKV-HBaseのクエリ最適化(get操作に対する最適化)機能について説明し、ワイド行やマルチバージョンの行に対するクエリシナリオにおいてクエリパフォーマンスを向上させる方法を紹介します。
機能の概要
この機能は、GET操作の実行時にクエリ最適化機能を有効にするための構成パラメータを提供します。有効になると、サーバー側でOBKV-HBaseのインテリジェントスキャン技術に基づいてクエリが最適化され、ワイドレコードや複数バージョンのレコードを迅速にスキップし、クエリの遅延を低減します。
この機能は主にワイドレコードやホットキー(バージョン数が多い)のシナリオに対応しています。HBaseのワイドレコードにおいて、異なるQualifier(すなわち列名)の数とすべてのQualifierのバージョン総数が1000を超える場合、最適化効果は非常に顕著になります。
注意
この構成パラメータを有効にすると、クライアントはサーバーに最適化の提案のみを送信します。サーバーは実際の状況に応じて最適化の実行を評価するため、構成パラメータを有効にしても、すべてのシナリオで最適化が適用されるとは限りません。
使用上の制限
この最適化機能は、以下のすべての条件を満たす場合にのみ有効になります:
制限条件 |
説明 |
|---|---|
| get操作のみ適用 | scan操作はサポートされていません |
| MaxVersions = 1 | テーブルレベルで MaxVersions=1 が設定されている場合、またはget操作で get.setMaxVersions(1) が設定されている場合 |
| 非時系列テーブル | 時系列テーブルはサポートされていません |
| Filterを指定しない場合 | クエリ時にFilterを指定できません |
| reverse scanをサポートしていない | クエリ時にreverse scanを使用できません |
| ローカル読み取り | サーバー側で実行する際にローカル読み取りが必要です(分散シナリオでは、バッチgetはリモート実行される可能性があり、この場合最適化は適用されません) |
この機能はステートメントレベルとグローバルレベルの2種類の設定方法をサポートしており、設定方法によってデータ型の制限が異なります。詳細は以下のとおりです:
- ステートメントレベルの設定:
Get.setAttribute()メソッドを使用して設定する必要があります。パラメータタイプはbyte[]型で、文字列"true"または"false"のバイト配列(例:"true".getBytes())を直接渡せばよいです。サーバー側が自動的にブール値に解釈します。 - グローバルレベルの設定:ブール型、またはブール値に解釈可能な文字列(
"true"/"false")である必要があります。
パフォーマンスへの影響:
- この最適化は主にワイドレコードや複数バージョンのシナリオに対応しており、それ以外のシナリオでは最適化効果が明確でない場合があります。
構成パラメータ
この機能はステートメントレベルとグローバルレベルの2種類の設定方法をサポートしています:
構成レベル |
定数名 |
構成値 |
型 |
デフォルト値 |
|---|---|---|---|---|
| ステートメントレベル | HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE |
hbase.htable.hotkey.get.optimize.enable |
byte[] (Get.setAttribute() による設定) |
false |
| グローバルレベル | HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE_GLOBAL |
hbase.htable.hotkey.get.optimize.enable.global |
boolean (Configuration による設定) |
false |
優先順位のルール:
- ステートメントレベルが優先:
Get.setAttribute()でステートメントレベルの設定が行われている場合、その設定値を使用します。 - ステートメントレベルで未設定の場合はグローバル設定を使用:ステートメントレベルで設定がない場合、グローバル設定を使用します。
- デフォルト値:両方のレベルで設定がない場合、デフォルト値は
falseです。
使用方法
Get.setAttribute() メソッドを使用して、個々のGET操作に対する最適化スイッチを設定します。きめ細かい制御が必要なシナリオに適しています。
個別GET操作の例:
Get get = new Get(Bytes.toBytes("rowkey"));
get.addColumn(family.getBytes(), column.getBytes());
// ホットキーGETの最適化を有効にする
get.setAttribute(HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE, "true".getBytes());
// または無効にする
// get.setAttribute(HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE, "false".getBytes());
Result result = hTable.get(get);
一括GET操作の例:
List<Get> gets = new ArrayList<>();
for (String key : keys) {
Get get = new Get(Bytes.toBytes(key));
get.addColumn(family.getBytes(), column.getBytes());
get.setAttribute(HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE, "true".getBytes());
gets.add(get);
}
Result[] results = hTable.get(gets);
Configuration オブジェクトを使用してグローバルな最適化スイッチを設定します。統一的に制御が必要なシナリオに適しています。
Configuration configuration = ObHTableTestUtil.newConfiguration();
// グローバルにGETクエリの最適化を有効にする
configuration.setBoolean(HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE_GLOBAL, true);
OHTable hTable = new OHTable(configuration, "table_name");
// この時点で、ステートメントレベルで設定されていないすべてのGET/SCAN操作はグローバル設定を使用します
Get get = new Get(Bytes.toBytes("rowkey"));
Result result = hTable.get(get); // グローバル設定のtrue値が自動的に使用されます
ステートメントレベルの設定はグローバル設定を上書きでき、ほとんどの操作で最適化が必要だが、一部の操作では最適化を無効にする必要があるシナリオに適しています。
Configuration configuration = ObHTableTestUtil.newConfiguration();
// グローバルで有効にする
configuration.setBoolean(HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE_GLOBAL, true);
OHTable hTable = new OHTable(configuration, "table_name");
// Get1:ステートメントレベルを設定せず、グローバル設定(true)を使用する
Get get1 = new Get(Bytes.toBytes("rowkey1"));
Result result1 = hTable.get(get1);
// Get2:ステートメントレベルをfalseに設定し、グローバル設定を上書きする
Get get2 = new Get(Bytes.toBytes("rowkey2"));
get2.setAttribute(HBASE_HTABLE_HOTKEY_GET_OPTIMIZE_ENABLE, "false".getBytes());
Result result2 = hTable.get(get2); // グローバルのtrueではなくfalseを使用する