このトピックでは、Hologres の主要なインデックスである分散キー、イベント時間列 (セグメントキー)、クラスタリングキーを紹介し、Hologres の開発中にインデックスを使い始めてクエリパフォーマンスを向上させるのに役立ちます。
Hologres の仕組み
Hologres は、並列コンピューティングとベクトルコンピューティングを使用して、数秒でクエリ応答を配信する分散データウェアハウスです。このアーキテクチャのため、データ分散はパフォーマンスにとって非常に重要です。これには、分散キーによって管理される分散ノード間でのデータのバランス方法と、イベント時間列 (セグメントキーとも呼ばれる) によって管理される単一ノード上のファイル内でのデータの順序付け方法が含まれます。Hologres は、オンライン分析処理 (OLAP) シナリオ向けにデフォルトで列指向ストレージ形式を使用しており、クラスタリングキーによって管理されるファイル内のデータの順序も不可欠です。これら 3 つの概念を習得することが、パフォーマンスを最適化する鍵となります。これらのデータレイアウトプロパティはデータ書き込み時に設定され、変更にはコストがかかるため、最初からこれら 3 つの属性を考慮してテーブルを設計することを推奨します。ビットマップインデックスや辞書エンコーディングなど、データレイアウトに直接影響しない属性は、後で必要に応じて調整できます。
Hologres は、データベース > スキーマ > テーブルの 3 階層のメタデータ構造を使用します。データベース間のクエリを避けるため、論理的に関連するテーブルを同じスキーマの下にグループ化することを推奨します。データベースはメタデータ分離の基本単位であり、リソース分離の単位ではありません。
SQL 最適化の基本
適切なデータ分散戦略でテーブルを設計することで、SQL クエリはデータを迅速に特定できます。これにより、I/O が削減され、消費するコンピューティングリソースが少なくなり、より高いクエリパフォーマンスが実現します。バランスの取れたデータ分散は、同時実行リソースが効率的に使用されることを保証し、単一障害点を回避します。次の図は、SQL クエリがデータを取得する方法と I/O がどのように削減されるかを示しています。
-
パーティションプルーニング:SQL クエリがパーティションテーブルを対象とする場合、クエリオプティマイザはパーティションプルーニングを使用して関連するパーティションを特定します。クエリのフィルター条件にパーティションキーが含まれていない場合、クエリはすべてのパーティションをスキャンする必要があり、過剰な I/O が発生します。一般的なルールとして、日単位でのパーティション分割は良い実践です。非パーティションテーブルの場合、パーティションプルーニングはスキップされます。
-
シャードプルーニング:分散キーを使用して、必要なデータを含むデータシャードを迅速に特定します。これにより、単一クエリのリソース消費が削減され、同時実行クエリのより高いスループットがサポートされます。特定のシャードを特定できない場合、分散フレームワークはすべてのシャードが計算に参加するようにスケジュールします。これにより、単一クエリの並列処理は向上しますが、より多くのリソースを使用し、全体的な同時実行性が低下します。集中実行を必要とする一部のオペレーターは、追加のシャッフルオーバーヘッドを発生させる可能性もあります。ベストプラクティスとして、注文 ID、ユーザー ID、イベント ID など、データ分散が均等な列を分散キーとして選択します。結合する必要がある複数のテーブルが同じ分散キーを共有している場合、関連データは同じシャードに共存します。これにより、効率的なローカル結合操作が可能になります。
-
セグメントキープルーニング:セグメントキー (イベント時間列) を使用して、ノード内の特定のデータファイルを迅速に特定し、不要なファイルへのアクセスを回避します。このレベルでデータをフィルタリングできない場合、すべてのファイルをスキャンする必要があります。
-
クラスタリングキープルーニング:クラスタリングキーを使用して、単一ファイル内のデータセグメントを迅速に特定します。これにより、範囲クエリと列のソートの効率が向上します。
SQL 最適化の実践
このセクションでは、TPC-H クエリを使用して、クエリパフォーマンスを向上させるために Hologres インデックスを設定する方法を実証します。TPC-H の詳細については、「テスト計画の概要」をご参照ください。
TPC-H SQL リファレンス
TPC-H Q1 クエリ
TPC-H Q1 クエリは、lineitem テーブルの特定の列に対して集約とフィルタリングを実行します。次の条件が含まれます:
l_shipdate <=:これはフィルター条件です。効率的な範囲フィルタリングをサポートし、必要なデータを迅速に取得するには、適切なインデックスを定義する必要があります。
--TPC-H Q1
SELECT
l_returnflag,
l_linestatus,
SUM(l_quantity) AS sum_qty,
SUM(l_extendedprice) AS sum_base_price,
SUM(l_extendedprice * (1 - l_discount)) AS sum_disc_price,
SUM(l_extendedprice * (1 - l_discount) * (1 + l_tax)) AS sum_charge,
AVG(l_quantity) AS avg_qty,
AVG(l_extendedprice) AS avg_price,
AVG(l_discount) AS avg_disc,
COUNT(*) AS count_order
FROM
lineitem
WHERE
l_shipdate <= DATE '1998-12-01' - INTERVAL '120' DAY
GROUP BY
l_returnflag,
l_linestatus
ORDER BY
l_returnflag,
l_linestatus;
TPC-H Q4 クエリ
TPC-H Q4 クエリは、主に lineitem テーブルと orders テーブルを結合します。次の条件が含まれます:
-
o_orderdate >= DATE '1996-07-01':これはフィルター条件です。効率的な範囲フィルタリングをサポートし、必要なデータを迅速に取得するには、適切なインデックスを定義する必要があります。 -
l_orderkey = o_orderkey:これは 2 つのテーブル間の結合条件です。最高のパフォーマンスを得るには、両方のテーブルで同じインデックスを使用してローカル結合を有効にし、操作中のデータシャッフルを削減します。--TPC-H Q4 Query SELECT o_orderpriority, COUNT(*) AS order_count FROM orders WHERE o_orderdate >= DATE '1996-07-01' AND o_orderdate < DATE '1996-07-01' + INTERVAL '3' MONTH AND EXISTS ( SELECT * FROM lineitem WHERE l_orderkey = o_orderkey AND l_commitdate < l_receiptdate ) GROUP BY o_orderpriority ORDER BY o_orderpriority;
テーブル作成の推奨事項
Q1 と Q4 のクエリには、lineitem テーブルと orders テーブルが関与します。
hologres_dataset_tpch_100g.lineitem
Q1 と Q4 の両方のクエリに lineitem テーブルが関与しますが、使用する列と条件は異なります。
-
Q1 クエリの場合:クエリは主に
l_shipdateを範囲フィルタリングに使用します。クラスタリングキーは、ファイル内のデータのソート順を利用して範囲スキャンを高速化します。したがって、l_shipdateをクラスタリングキーとして設定します。セグメントキー (イベント時間列) は、ファイル間の順序を維持します。単調増加または単調減少する日付列の場合、それをセグメントキーとして設定すると、効果的なセグメントキープルーニングが可能になります。したがって、l_shipdateをセグメントキーとして設定することもできます。 -
Q4 クエリの場合:クエリは
lineitemテーブルをordersテーブルとl_orderkeyおよびo_orderkey列で結合します。分散キーはデータ分散戦略を指定します。システムは、同じキー値を持つデータを同じシャードに配置します。2 つのテーブルが同じテーブルグループにあり、それらの分散キー列で結合される場合、システムはデータ書き込み時に一致するレコードを自動的に同じシャードに分散します。これらのテーブルが結合されると、システムはネットワーク経由でデータをシャッフルすることなく、各ノードでローカル結合を実行します。これにより、ランタイムのデータシャッフルと再配布が回避され、実行効率が大幅に向上します。したがって、l_orderkeyを分散キーとして設定します。 -
lineitemの最終的なテーブル構造は次のとおりです:BEGIN; CREATE TABLE hologres_dataset_tpch_100g.lineitem ( l_ORDERKEY BIGINT NOT NULL, L_PARTKEY INT NOT NULL, L_SUPPKEY INT NOT NULL, L_LINENUMBER INT NOT NULL, L_QUANTITY DECIMAL(15,2) NOT NULL, L_EXTENDEDPRICE DECIMAL(15,2) NOT NULL, L_DISCOUNT DECIMAL(15,2) NOT NULL, L_TAX DECIMAL(15,2) NOT NULL, L_RETURNFLAG TEXT NOT NULL, L_LINESTATUS TEXT NOT NULL, L_SHIPDATE TIMESTAMPTZ NOT NULL, L_COMMITDATE TIMESTAMPTZ NOT NULL, L_RECEIPTDATE TIMESTAMPTZ NOT NULL, L_SHIPINSTRUCT TEXT NOT NULL, L_SHIPMODE TEXT NOT NULL, L_COMMENT TEXT NOT NULL, PRIMARY KEY (L_ORDERKEY,L_LINENUMBER) ) WITH ( distribution_key = 'L_ORDERKEY',--ローカル結合を有効にします。 clustering_key = 'L_SHIPDATE',--範囲フィルタリングを高速化します。 event_time_column = 'L_SHIPDATE'--セグメントキープルーニングを高速化します。 ); COMMIT;
hologres_dataset_tpch_100g.orders
この例では、orders テーブルは Q4 クエリで使用されます。
-
ordersテーブルのo_orderkey列を分散キーとして設定し、ローカル結合機能を活用して結合クエリの効率を向上させます。 -
o_orderdate列は主に日付フィルタリングに使用されます。セグメントキープルーニングを高速化するために、これをセグメントキーとして設定します。 -
ordersの最終的なテーブル構造は次のとおりです:BEGIN; CREATE TABLE hologres_dataset_tpch_100g.orders ( O_ORDERKEY BIGINT NOT NULL PRIMARY KEY, O_CUSTKEY INT NOT NULL, O_ORDERSTATUS TEXT NOT NULL, O_TOTALPRICE DECIMAL(15,2) NOT NULL, O_ORDERDATE timestamptz NOT NULL, O_ORDERPRIORITY TEXT NOT NULL, O_CLERK TEXT NOT NULL, O_SHIPPRIORITY INT NOT NULL, O_COMMENT TEXT NOT NULL ) WITH ( distribution_key = 'O_ORDERKEY',--ローカル結合を有効にします。 event_time_column = 'O_ORDERDATE'--セグメントキープルーニングを高速化します。 ); COMMIT;
サンプルデータのインポート
HoloWeb の数回のクリックでパブリックデータセットをインポート機能を使用して、100 GB の TPC-H データを Hologres インスタンスに迅速にインポートできます。HoloWeb で、上部のナビゲーションバーから [データソリューション] を選択し、左側のナビゲーションウィンドウで [数回のクリックでパブリックデータセットをインポート] をクリックします。設定ページで、[インスタンス名] (例:holo_test) と [データベース] を選択します。次に、[パブリックデータセット名] リストから tpch_100g を選択します。システムは、ページの下部に編集不可能な SQL スクリプトを自動的に生成します。このスクリプトには、hologres_foreign_dataset_tpch_100g および hologres_dataset_tpch_100g スキーマを作成し、customer、lineitem、nation、orders、part、partsupp、region、supplier などの外部テーブルにデータを順次インポートするステートメントが含まれています。
パフォーマンステストの結果
このセクションでは、推奨されるテーブルプロパティ (インデックス) を設定する前と後でクエリパフォーマンスを比較します。
-
テスト環境
-
インスタンス仕様:32 コア
-
ネットワークタイプ:VPC
-
PSQL クライアントを使用して各クエリを 2 回実行し、2 回目の実行のレイテンシーを記録します。
-
-
結論
-
単一テーブルでのフィルタリングクエリの場合、フィルター列をクラスタリングキーとして設定すると、クエリが効果的に高速化されます。
-
複数テーブル結合クエリの場合、結合列を分散キーとして設定すると、結合効率が大幅に向上します。
クエリ
インデックスありのレイテンシー
インデックスなしのレイテンシー
Q1
48.293 ms
59.483 ms
Q4
822.389 ms
3027.957 ms
-
参考資料
詳細情報
技術原理
Hologres のコア技術原理 (アーキテクチャ、ストレージエンジン、コンピュートエンジン) の詳細:Alibaba Cloud のクラウドネイティブリアルタイムデータウェアハウスのコア技術。
サービスの有効化
-
仕様の選択:インスタンス管理。
-
RAM ユーザーの権限付与:RAM ユーザー権限付与のクイックスタート。
データインポート
-
Flink を使用したリアルタイム書き込みとディメンションテーブルクエリ:Realtime Compute for Apache Flink。
-
MySQL、Oracle、PolarDB などのデータベースからのリアルタイム完全同期:MySQL データソースの設定。
-
OSS からのデータインポート:DLF を使用した OSS データレイクへのアクセスの高速化。
-
Fixed Plan を使用して、データの書き込みと更新の効率を 10 倍に向上させます。詳細については、「Fixed Plan を使用した SQL 実行の高速化」をご参照ください。
データクエリ
-
さまざまなユースケースに対応するテーブル作成の推奨事項:シナリオベースのテーブルチューニングガイド。
-
テーブルを作成する前に、
distribution_key、clustering_key、event_time_column、bitmap_indexなどの主要なパラメーターを理解してください。適切な構文とインデックスを使用して最適なテーブル構造を定義すると、パフォーマンスが大幅に向上します。詳細については、「CREATE TABLE」をご参照ください。 -
内部テーブルのパフォーマンスチューニング:クエリパフォーマンスの最適化。
-
MaxCompute の高速化:外部テーブルを使用した MaxCompute データクエリの高速化。
O&M とモニタリング
-
アクティブなクエリ (実行中のクエリのトラブルシューティング、および既存または潜在的なロックの確認):クエリの管理。
-
スロークエリ (失敗したクエリまたは長時間実行されるクエリのトラブルシューティング):スロークエリログの取得と分析。
-
読み書き分離と負荷分離:プライマリインスタンスとセカンダリインスタンスの読み書き分離のデプロイ (共有ストレージ)。
ユースケースとベストプラクティス
実践とユースケース:典型的な業界シナリオ向けのベストプラクティスと代表的な顧客ユースケース。