LindormTable は、表形式モデルでセカンダリインデックスをサポートしています。セカンダリインデックスを使用すると、アプリケーションの書き込みロジックを変更することなく、プライマリキー以外の列でデータをクエリできます。Lindorm はインデックスのメンテナンスを自動的に処理し、プライマリテーブルとすべてのインデックス テーブル間の一貫性を保証します。
前提条件
開始する前に、以下が準備できていることを確認してください。
Lindorm インスタンス
LindormTable に接続済みの SQL クライアント。詳細については、「Lindorm Wide-Table SQL で LindormTable エンジンを使用する」または「Lindorm-cli で LindormTable に接続して使用する」をご参照ください。
基本概念
インデックスとプライマリテーブルの関係
各セカンダリインデックスは、プライマリテーブルとは別の独立した物理データテーブルにマッピングされます。1 つのプライマリテーブルに対して、1 つ以上の列で構築された複合インデックスを含む、複数のインデックスを作成できます。プライマリテーブルに書き込むと、Lindorm は関連するすべてのインデックス テーブルを自動的に更新します。クエリを実行する際は、プライマリテーブルに対して WHERE 句で条件を指定します。Lindorm は、インデックスが適合しない場合にプライマリテーブルにフォールバックすることを含め、最適なインデックスを自動的に選択します。
オンラインスキーマ変更
インデックスの変更 (インデックスの追加、無効化、削除) は、プライマリテーブルでの通常の読み取りまたは書き込み操作に影響を与えません。ダウンタイムなしで、いつでもインデックスを追加、削除、または更新できます。
強い整合性
プライマリテーブルとインデックス テーブル間のデータ整合性には、以下の制約があります。
スナップショット分離はサポートされていません。 プライマリテーブルに書き込まれたデータは、インデックス テーブルですぐに表示されない場合があります。サーバーが成功応答を返した後、データは両方で表示されるようになります。
クライアントのタイムアウトまたは I/O エラーの動作 クライアントのタイムアウトまたは I/O エラーにより書き込みが失敗した場合、データはプライマリテーブルにもインデックス テーブルにも表示されないことがあります。それらの間の結果整合性は引き続き保証されます。
可変性
インデックス付きテーブルへのすべての書き込みは、インデックスを維持する必要があるため、インデックスのないテーブルへの書き込みよりもコストが高くなります。実際のコストは、ワークロードが既存の行を更新または削除するかどうかによって異なります。
MUTABILITY プロパティは、ワークロードが実行する操作を Lindorm に伝え、インデックスメンテナンスのオーバーヘッドを最小限に抑えることができます。このプロパティは、テーブルを作成または変更するときに Table_Options を使用して設定します。詳細については、「CREATE TABLE 構文」をご参照ください。
書き込みパターンに基づいて可変性の設定を選択します:
追記のみ、更新や削除なし:
IMMUTABLEを使用追記と行レベルの削除、更新なし:
IMMUTABLE_ROWSを使用更新と削除、カスタムタイムスタンプなし:
MUTABLE_LATESTを使用 (推奨)カスタムタイムスタンプ付きの更新と削除:
MUTABLE_UDTを使用
ワークロードのパターン | 設定 | 操作コスト | 注意事項 |
インデックスなし | — | 1 | プライマリテーブルに直接書き込みます |
挿入のみ、更新や削除は行わない |
| 2 | 最も低コストです。非推奨:更新を防ぐ保護機能がありません。更新が発生した場合、インデックスはプライマリテーブルと警告なしに不整合になります。 |
行単位での挿入と削除、更新は行わない |
| 2–3 | 2 番目に低コストです。非推奨:同様の注意点があります。更新により警告なしに不整合が発生します。 |
更新と削除、カスタムタイムスタンプなし |
| 4 | LindormTable 2.7.9 以降のデフォルトです。安全性とパフォーマンスのバランスが最も優れています。 |
更新と削除、カスタムタイムスタンプが必要 |
| 4 |
|
更新と削除、カスタムタイムスタンプ、バージョン制限なし |
| 4 | 制限はありません。パフォーマンスを向上させるには、代わりに |
MUTABLE_LATEST が推奨される設定です。LindormTable 2.7.9 以降では、これがデフォルトです。インスタンスがそれ以前のバージョンである場合は、MUTABILITY='MUTABLE_LATEST' を明示的に設定してください。
カスタムタイムスタンプでデータを書き込むには、MUTABLE_UDT を使用します (LindormTable 2.6.7 以降が必要です)。可変性プロパティはインデックス作成時に有効になるため、インデックスを作成する前にこれを計画してください。
インデックスを作成する前に可変性を MUTABLE_UDT または MUTABLE_ALL に設定せずにカスタムタイムスタンプでデータを書き込むと、インデックス作成直後にインデックスに対するクエリが失敗します。復旧手順については、「よくある質問」をご参照ください。
IMMUTABLEとIMMUTABLE_ROWSにはサーバー側の強制力がありません。ワークロードがデータを更新するにもかかわらず、テーブルがIMMUTABLEまたはIMMUTABLE_ROWSに設定されている場合、サーバーはエラーを返しませんが、インデックスデータはプライマリテーブルと不整合になります。これらの設定は、更新が発生しないことが確実な場合にのみ使用してください。IMMUTABLEテーブルには削除が伴わないため、マルチインターネットデータセンター (IDC) のアクティブ/アクティブデプロイメントを完全にサポートします。
カバリングインデックス
カバリングインデックスがない場合、インデックスエントリに一致するクエリでも、プライマリテーブルから完全な行をフェッチする必要があります。インデックスによって返される rowkey はプライマリテーブル全体に散在している可能性があり、複数のリモートプロシージャコール (RPC) が必要となり、結果セットが大きくなるにつれてレスポンスタイム (RT) が増加します。
カバリングインデックスは、プライマリテーブルの列をインデックス テーブルに直接含めることで、それらの列に対するプライマリテーブルのルックアップを不要にします。Lindorm は 3 つのカバレッジモードをサポートしています:
[特定の列]:プライマリテーブルからレプリケートする列をリストします。
すべてのスキーマ列 (
COVERED_ALL_COLUMNS_IN_SCHEMA):プライマリテーブルスキーマで現在定義されているすべての列を含みます。プライマリテーブルに新しい列が追加されると、インデックスは再インデックス作成を必要とせずに自動的にそれを含みます。動的な列 (
DYNAMIC):プライマリテーブルのすべての動的な列に加えて、スキーマで定義されたすべての列を含みます。
カスタムタイムスタンプ (ユーザー定義タイムスタンプ、UDT)
Lindorm は、列レベルのカスタムタイムスタンプをサポートしています。カスタムタイムスタンプを使用したデータの書き込みは、Time to Live (TTL) の制御や、順序が不規則な書き込みやべき等な書き込みを処理するために、HBase ベースのシステムで一般的です。Lindorm のセカンダリインデックスは、カスタムタイムスタンプが使用された場合のインデックスデータの更新もサポートしており、これは NoSQL システムでは珍しい機能です。
これが重要となる 2 つのユースケース:
同時インポートとリアルタイム更新:リアルタイムの書き込みには現在の時刻を使用し、履歴データのインポートには過去のタイムスタンプ (たとえば、前日の 23:59:59) を使用します。リアルタイムの書き込みが優先され、履歴データのインポートはまだ更新されていないデータのみを埋めます。
メッセージのキャッチアップ:システムが蓄積されたメッセージをスキップして現在のメッセージを先に処理する場合、各メッセージは独自のタイムスタンプを持ちます。後で古いメッセージに追いつく際には、処理順序に関係なく、正しい上書き順序が適用されます。
セカンダリインデックスの作成
Lindorm のプライマリテーブルを作成した後、CREATE INDEX ステートメントを使用してその列にセカンダリインデックスを作成します。
次の例では、orders テーブルを使用します。user_id 列にインデックスを作成すると、テーブル全体をスキャンすることなく、ユーザー別に注文をクエリできます。
-- プライマリテーブルの作成
CREATE TABLE orders (
order_id VARCHAR NOT NULL,
user_id VARCHAR,
status VARCHAR,
amount DOUBLE,
created BIGINT,
PRIMARY KEY(order_id)
) WITH (CONSISTENCY = 'strong', MUTABILITY = 'MUTABLE_LATEST');
-- すべてのスキーマ列を含む、user_id に対するカバリングインデックスの作成
-- user_id でフィルタリングするクエリは、このインデックスを使用し、プライマリテーブルのルックアップを回避します
CREATE INDEX idx_user ON orders(user_id) WITH (INDEX_COVERED_TYPE = 'COVERED_ALL_COLUMNS_IN_SCHEMA');
-- このクエリは自動的に idx_user を使用します
SELECT * FROM orders WHERE user_id = 'u123';プライマリテーブルのサイズに基づいて、同期または非同期のインデックス作成を選択してください。小さなテーブルには同期作成を、大きなテーブルには非同期作成を使用します。構文の詳細については、「CREATE INDEX」をご参照ください。
既存のデータを持つテーブルにインデックスを追加する場合、CREATE INDEX はプライマリテーブルからインデックス テーブルに履歴データを同期します。これは大きなテーブルでは時間がかかることがあります。同期はサーバーサイドで実行されるため、Lindorm Shell プロセスを終了しても中断されません。ホット/コールドデータ分離が有効になっている場合は、インデックス構築中に容量ストレージの読み取りスロットリングを監視してください。コールドストレージの読み取りスロットリングは、インデックス構築の速度を低下させ、書き込み操作にバックプレッシャーを引き起こす可能性があります。
セカンダリインデックスの表示
テーブル上のインデックス (名前と現在のステータスを含む) を表示するには、SHOW INDEX を使用します。
SHOW INDEX FROM orders;インデックスステータスの変更
セカンダリインデックスをアクティブ化または無効化するには、ALTER INDEX を使用します。
-- インデックスをアクティブ化
ALTER INDEX IF EXISTS idx_user ON orders ACTIVE;
-- インデックスを無効化
ALTER INDEX idx_user ON orders DISABLED;DISABLED 状態のインデックスを直接 ACTIVE に変更しないでください。データ損失の原因となります。最初に BUILD INDEX 操作を実行してインデックスデータを再構築し、その後でアクティブ化してください。
インデックス作成後にプライマリテーブルに履歴データが含まれている場合は、インデックスをアクティブ化する前に、そのインデックスに対して再構築操作を実行してください。詳細については、「BUILD INDEX」をご参照ください。
セカンダリインデックスの削除
プライマリテーブルからセカンダリインデックスを削除するには、DROP INDEX を使用します。
DROP INDEX IF EXISTS idx_user ON orders;インデックスの削除にはごみ箱の権限が必要です。アクティブなクエリがインデックスを使用している場合は、注意して削除してください。
クエリの最適化
Lindorm は、ルールベースの最適化 (RBO) を使用してインデックスを選択します。各インデックスのプレフィックスをクエリの WHERE 句と照合し、一致度が最も高いインデックスを選択します。
次の例は、オプティマイザが複数のインデックスを持つテーブルに対してどのようにインデックスを選択するかを示しています。
CREATE TABLE dt (rowkey VARCHAR, c1 VARCHAR, c2 VARCHAR, c3 VARCHAR, c4 VARCHAR, c5 VARCHAR, PRIMARY KEY(rowkey));
CREATE INDEX idx1 ON dt(c1);
CREATE INDEX idx2 ON dt(c2, c3, c4);
CREATE INDEX idx3 ON dt(c3) INCLUDE(c1, c2, c4);
CREATE INDEX idx4 ON dt(c5 DESC) WITH (INDEX_COVERED_TYPE = 'COVERED_ALL_COLUMNS_IN_SCHEMA');クエリ | 選択されるインデックス | 理由 |
|
|
|
|
|
|
|
|
|
|
|
|
クエリは一度に最大 1 つのインデックスしか使用できません。インデックスマージはサポートされていません。
インデックスの選択に影響を与えるには、クエリヒントを使用します。詳細については、「CREATE INDEX」をご参照ください。
制限事項
インデックス名はプライマリテーブルごとに一意である必要があります。同じインデックス名を異なるプライマリテーブルで使用することは可能です。
インデックスは単一バージョンのテーブルでのみサポートされています。複数バージョンのテーブルではインデックスはサポートされていません。
セルレベルの TTL はサポートされていません。インデックス テーブルはプライマリテーブルの TTL を継承します。インデックス テーブルに個別の TTL を設定することはできません。
LindormTable 2.8.6 以降:プライマリテーブルごとに最大 10 個のインデックス、インデックスごとに最大 8 個のインデックス列。それ以前のバージョン:最大 5 個のインデックスと最大 3 個のインデックス列。
インデックス列とプライマリキーの合計長は 30 KB を超えてはなりません。100 バイトを超える列をインデックス列として使用することは避けてください。
クエリは最大で 1 つのインデックスを使用します。インデックスマージクエリはサポートされていません。
セカンダリインデックスはバッチ増加機能をサポートしていません。
セカンダリインデックスクエリからの結果のソート順は、プライマリテーブルのソート順とは異なります。
バルクロードを介してインポートされたデータに対してインデックスを構築することはできません。インデックスは、SQL または API を介して書き込まれたデータにのみ適用されます。
大きなテーブルにインデックスを作成すると、履歴データが同期される間、
CREATE INDEXの実行に時間がかかります。
よくある質問
エラー User-Defined-Timestamp(UDT) is not supported by table in MUTABLE_LATEST mode が表示されるのはなぜですか?
テーブルの可変性が MUTABLE_LATEST に設定されている間にインデックスを作成しましたが、アプリケーションがカスタムタイムスタンプでデータを書き込んでいます。MUTABLE_LATEST はカスタムタイムスタンプをサポートしていません。
これを修正するには:
プライマリテーブルのインデックスを削除します。
可変性プロパティを
MUTABLE_UDTに変更します。インデックスを再度作成します。
アクティブなクエリがインデックスを使用している場合、インデックスを削除するとそれらのクエリに影響します。続行する前に、それに応じて計画してください。
その他のインデックス関連の問題については、Lindorm DingTalk グループに参加するか、チケットを送信してください。詳細については、「テクニカルサポート」をご参照ください。