クラスター化された列ストアインデックス (CCI) は、列ストア読み取り専用インスタンスにデータを列指向形式で保存し、大規模なデータセットに対する高速な分析処理 (AP) クエリを可能にします。このドキュメントでは、CCI を使用するタイミング、および最適なパフォーマンスを得るためにパーティション、ソートキー、辞書エンコーディングを構成する方法について説明します。
CCI は、一貫性のあるクエリ結果を維持するために、Change Data Capture (CDC) ノードを使用して非同期で構築されます。プライマリインスタンスから列ストア読み取り専用インスタンスへのデータ同期により、秒レベルのレイテンシーが発生します。リアルタイムデータアクセスを必要とするシナリオでは、CCI の使用を避けてください。
ユースケース
以下のシナリオで CCI を使用します。
混合ワークロードまたは複雑なクエリの高速化: ご利用のアプリケーションが、大規模なテーブルに対する集計や結合などの複雑な AP クエリを実行し、行ベースのストレージではパフォーマンス要件を満たせなくなった場合。CCI は、このような状況でクエリパフォーマンスを大幅に向上させます。
コールドデータのアーカイブ: データは時間とともに増加し、ストレージコストが懸念される場合。列ストア読み取り専用ノードは、Object Storage Service (OSS) に保存されている CCI メタデータを介してデータにアクセスし、コールドデータのストレージコストを削減します。詳細については、「TTL」をご参照ください。
履歴スナップショット: 有効期限なしで履歴データを長期的に保持し、クエリを実行する必要がある場合。CCI は履歴データの有効期限のないレプリカとして機能するため、監査およびバックアップワークフローに適しています。
ETL パイプライン: 本番環境に影響を与えることなく、抽出、変換、ロード (ETL) ジョブを実行するために、プライマリインスタンスのデータレプリカが必要な場合。列ストア読み取り専用インスタンスに接続して ETL を実行し、データをダウンストリームシステムに転送します。
パーティションテーブル
パーティショニング方法
パーティショニングは、大規模なテーブルをより小さく、独立して管理されるセグメントに分割し、大規模なデータセットのクエリパフォーマンスとデータ管理を向上させます。CCI のパーティショニングでサポートされている構文は次のとおりです。
PARTITION BY
HASH({column_name | partition_func(column_name)})
| KEY(column_list)
| RANGE({column_name | partition_func(column_name)})
| RANGE COLUMNS(column_list)
| LIST({column_name | partition_func(column_name)})
| LIST COLUMNS(column_list)利用可能なパーティショニングタイプは次のとおりです。
範囲: 列の値の範囲に基づいてデータを分割します。たとえば、販売履歴テーブルを年ごとにパーティション分割して、同じ年のすべてのレコードが 1 つのパーティションを共有するようにします。
リスト: 列の値が事前定義されたセット内にあるかどうかに基づいてデータを分割します。これは SaaS シナリオで一般的です。たとえば、ユーザーテーブルを国ごとにパーティション分割します。
HASH / KEY: 列のハッシュ値に基づいてデータを分割し、行をパーティション全体に均等に分散します。データ分散が予測不能な場合や、均等な分散が必要な場合に使用します。
完全なリファレンスについては、「パーティショニングタイプ」をご参照ください。
パーティショニング方法の選択
CCI は、主に集計と結合を含む AP クエリを高速化するように設計されています。カラム型並列スキャンを最大限に活用するには、ほとんどの場合、ハッシュパーティショニングを使用します。
特定のシナリオについては、以下のガイドラインに従ってください。
| シナリオ | 推奨される方法 |
|---|---|
| AP クエリ (集計、結合) | ハッシュパーティショニング |
| 時間ベースのコールドデータアーカイブ | 時間列での範囲パーティショニング |
| 時間関連のクエリフィルター | サブパーティションキーとして時間列を追加 |
| 事前定義された値セットでクエリ可能なデータ | リストパーティショニング (まず行ベースのストレージで十分かどうかを確認します) |
範囲パーティションテーブルまたはリストパーティションテーブルの場合: 行ベースのストレージがクエリ要件を満たしている場合は、カラム型パーティショニングよりも優先します。
時間ベースのサブパーティションについては、「サブパーティショニング」をご参照ください。クエリが時間範囲条件に大きく依存しない限り、サブパーティションの作成は避けてください。
パーティション数の構成
次の数式を使用してパーティション数を計算します。
Number of computing nodes × Number of cores per compute nodeデフォルトは 16 パーティションです。本番ワークロードにはこのデフォルトを使用しないでください。将来のデータ増加に対応するために、数式の結果よりも高いパーティション数を設定できます。
複数のテーブルを結合するクエリの場合、同じインスタンス内のすべての関連テーブルでパーティション数を一貫して維持してください。
パーティションキーの選択
パーティションキーは、パーティション全体にデータがどのように分散されるかを決定します。不適切なパーティションキーはデータスキューにつながり、単一のパーティションに負荷が集中し、パフォーマンスを低下させます。
次のような、均等に分散された値を持つ列を選択してください。
トランザクション ID
デバイス ID
ユーザー ID
自動増分列
パーティションキーとして時間ベースの列 (日付、タイムスタンプ) は避けてください。ほとんどの書き込みは同じ期間に集中する傾向があり、データスキューを引き起こします。時間範囲クエリも、ノード間で負荷を分散するのではなく、単一のパーティションにヒットすることになります。クエリにとって時間フィルタリングが重要な場合は、代わりに時間列をサブパーティションキーとして使用してください。
データ再分散のオーバーヘッドを最小限に抑えるために、`JOIN` または `GROUP BY` で頻繁に使用される列を選択してください。たとえば、顧客別に履歴注文を分析する場合は、顧客 ID 列を使用します。
パーティションプルーニングを有効にするために、等価条件または非範囲条件で頻繁に使用される列を選択してください。
各テーブルには 1 つのパーティションキーがあり、複数のフィールドで構成できます。パーティションキーのフィールド数が少ないほど、複雑なクエリシナリオでの適応性が一般的に向上します。
テーブル作成時にパーティションキーが指定されていない場合、システムはプライマリキーを使用します。明示的なプライマリキーが存在しない場合、システムは暗黙の主キーを使用します。
CCI 作成後、
check columnar partition db_name.tbl_nameを実行して、パーティション間のデータ分散を検査してください。出力を確認して、パーティションキーが適切であること、および潜在的なデータスキューを特定してください。
ソートキー
仕組み
ソートキーは、CCI ファイル内でデータがどのように順序付けられるかを制御します。各列データブロックには、含まれるデータの最小値と最大値が保存されます。クエリが実行されると、Pruner コンポーネントはこれらの最小値/最大値をクエリ条件と照合して評価し、各ブロックを次のように分類します。
関連性あり: スキャンされる必要があります
関連性がある可能性あり: 候補としてスキャンされます
関連性なし: 完全にスキップされます
適切に選択されたソートキーは、Pruner がスキップできるブロックの割合を増やし、スキャン量を直接削減してクエリ速度を向上させます。
Pruner の詳細については、「IMCI ベースのクエリのフィルターアルゴリズムの構成」をご参照ください。
ソートキーの選択
| クエリパターン | ソートキーの推奨事項 |
|---|---|
| 特定の列の値の範囲でフィルターするクエリ | その列をソートキーとして使用します |
ORDER BY を使用したページネーション付きクエリ ORDER BY | ORDER BY 列をソートキーとして使用します |
| その他すべての場合 | パーティションキーをソートキーとして使用します |
辞書エンコーディング
仕組み
辞書エンコーディングは、文字列の値を整数に変換することで、GROUP BY および FILTER 操作の高速化、圧縮率の向上、およびストレージコストの削減を実現します。
CCI 作成時に辞書エンコーディングする列を指定します。
-- Specify columns for dictionary encoding.
DICTIONARY_COLUMNS='col1,col2';
-- Create a CCI with dictionary encoding.
CREATE CLUSTERED COLUMNAR INDEX `cc_i_seller` ON t_order (`seller_id`)
PARTITION BY HASH(`order_id`) PARTITIONS 16
DICTIONARY_COLUMNS='order_id,seller_id';分散データベースでは、辞書ベースのクエリはノード間で辞書を解析およびマージする必要があり、オーバーヘッドが増加します。辞書ベースのフィルタリングは、クエリ実行中にデフォルトで無効になっています。これを有効にするには、ENABLE_COLUMNAR_SLICE_DICT を TRUE に設定してください。
辞書エンコーディングする列の選択
カーディナリティが低い列 (性別やリージョンなど、総行数に対して異なる値の数が少ない列) をエンコードします。
すべての文字型列をエンコードすることは避けてください。カーディナリティが高い列は、圧縮効果が最小限であり、エンコーディングとデコーディングのオーバーヘッドが増加します。
よくある質問
クラスター仕様を変更すると、パーティション数に影響しますか?
いいえ。パーティション数は CCI 作成時に設定され、クラスター仕様の変更による影響は受けません。
CCI 作成後に、パーティションキー、ソートキー、パーティション数、または辞書エンコーディングされた列を変更できますか?
いいえ。CCI を削除し、新しい構成で再作成してください。
CCI を作成するために列ストア読み取り専用インスタンスが必要ですか?
いいえ。CCI はプライマリインスタンスで作成できます。CCI データをクエリするには、列ストア読み取り専用インスタンスの購入を推奨します。