このトピックでは、分散キー、イベントタイム列(セグメントキー)、クラスタリングキーなど、Hologresでサポートされているインデックスについて説明します。Hologres開発でインデックスをすばやく使用してクエリのパフォーマンスを向上させるのに役立ちます。
Hologresのしくみ
Hologresは、並列コンピューティングとベクトルコンピューティング技術を使用してクエリに数秒で応答する分散データウェアハウスです。分散キーとイベントタイム列はデータ分散を決定し、クエリのパフォーマンスに重大な影響を与えます。データは分散キーに基づいてノードに分散され、ファイルはイベントタイム列に基づいてノード内でソートされます。オンライン分析処理(OLAP)シナリオでは、Hologresでは列指向ストレージがデフォルトで使用されます。クラスタリングキーの設定も重要です。これは、ファイル内でのデータのソート方法を決定するためです。適切なインデックス設定により、クエリのパフォーマンスを大幅に向上させることができます。テーブルを作成するときは、分散キー、イベントタイム列、およびクラスタリングキーを設定してデータ分散を決定することをお勧めします。既存のテーブルに対してこれらのインデックスを設定する場合、調整コストは高くなります。既存のテーブルの場合、ビジネス要件に基づいて、ビットマップインデックスや辞書エンコードプロパティなど、データ分散に直接影響しない他のインデックスを設定できます。
Hologresのメタデータは、データベース層、スキーマ層、テーブル層の3層モデルを使用します。論理的に関連するテーブルは同じスキーマに格納して、データベース間のクエリを防ぐことをお勧めします。メタデータはデータベースによって分離されますが、リソースはデータベースによって分離されません。
SQL最適化の基本原則:I/Oリソース消費の削減と並行性の最適化
テーブルを作成するときにデータ分散に適切なインデックスを設定すると、SQLステートメントが実行された後にクエリするデータがすぐに見つかります。これにより、I/Oおよびコンピューティングリソースの消費が削減され、クエリが高速化されます。バランスの取れたデータ分散は、同時リソースの利用率を高め、単一ノードのボトルネックを防ぐのにも役立ちます。次の図は、SQLステートメントの実行からデータの取得までの実行プロセスを示しています。これにより、I/Oリソース消費がどのように削減されるかを理解できます。
パーティションプルーニング:パーティションテーブルでSQLクエリを実行すると、システムはパーティションプルーニング機能を使用して、必要なデータが配置されているパーティションを見つけます。クエリ条件に基づいて一致するパーティションがない場合、システムはすべてのパーティションをトラバースする必要があり、過剰なI/Oリソースが消費されます。ほとんどの場合、日ごとのパーティション分割がより適切です。パーティション化されていないテーブルの場合、パーティションプルーニングは関係ありません。
シャードプルーニング:分散キーを使用して、目的のデータが配置されているシャードをすばやく見つけることができます。これにより、単一のSQLステートメントに必要なリソースが削減され、複数のSQLステートメントが同時に実行される場合の高いスループットがサポートされます。特定のシャードが見つからない場合、システムは分散フレームワークに基づいてすべてのシャードを計算用にスケジュールします。この場合、単一のSQLステートメントが複数のシャードで実行されるため、大量のリソースが消費され、システム全体の並行性が低下します。特定の演算子が集中方式で実行されると、追加のシャッフルオーバーヘッドが発生します。ほとんどの場合、注文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つのテーブルを結合します。可能であれば、2つのテーブルに同じインデックスを設定して、ローカル結合を許可します。これにより、2つのテーブル間のデータシャッフリングが削減されます。--TPC-H Q4 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;
テーブル作成の推奨事項
このセクションでは、TPC-H Q1およびQ4で使用されるlineitemテーブルとordersテーブルを作成するための推奨事項を示します。
hologres_dataset_tpch_100g.lineitem
lineitemテーブルのインデックス設定とクエリ条件は、TPC-H Q1とTPC-H Q4で異なります。
TPC-H Q1:l_shipdate列は、ファイル内のデータの時間シーケンスを指定し、範囲フィルタリングに使用されます。範囲フィルタリングを高速化するために、l_shipdate列をクラスタリングキー列として設定できます。イベントタイム列は、ファイルをソートするために使用されます。ファイルのフィルタリングを容易にするために、日付が単調に増加または減少する日付列をイベントタイム列として設定することをお勧めします。 TPC-H Q1では、l_shipdate列をイベントタイム列として設定できます。
TPC-H Q4:結合クエリは、lineitemテーブルのl_orderkey列とordersテーブルの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
この例では、TPC-H Q4 で orders テーブルが使用されます。
ローカル結合を許可するために、orders テーブルの o_orderkey 列を分散キーとして構成します。これにより、結合クエリの効率が向上します。
ファイルのプルーニングを高速化するために、orders テーブルの o_orderdate 列をイベント時間列として構成します。 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 を使用すると、数回クリックするだけで TPC-H パブリック データセットから 100 GB のデータを Hologres インスタンスにインポートできます。詳細については、「数回クリックするだけでパブリック データセットをインポートする」をご参照ください。
パフォーマンス テスト結果の比較
このセクションでは、テーブルにインデックスが構成される前後のパフォーマンス テストの結果について説明します。
テスト環境
インスタンス仕様: 32 CPU コア
ネットワークタイプ: virtual private cloud (VPC)
PostgreSQL クライアントで各クエリを 2 回実行し、2 回目のクエリのレイテンシを使用します。
テストの結論
フィルタリングを含む単一テーブルに対するクエリの場合、データがフィルタリングされる基準となる列をクラスタリングキー列として構成することで、クエリを大幅に高速化できます。
複数テーブル結合クエリの場合、結合列を分散キー列として構成することで、結合操作を大幅に高速化できます。
クエリ
Hologres でインデックスが構成されている場合のレイテンシ
Hologres でインデックスが構成されていない場合のレイテンシ
Q1
48.293 ms
59.483 ms
Q4
822.389 ms
3027.957 ms
参照資料
さらに読む
サービスのアクティベーション
インスタンス仕様の選択方法の詳細については、「インスタンス管理」をご参照ください。
RAMユーザーの詳細については、「RAMユーザーに権限を付与する」をご参照ください。
データのインポート
Flinkを使用してリアルタイムでデータを書き込む方法、およびクエリでディメンションテーブルを使用する方法の詳細については、「フルマネージド Flink の使用」をご参照ください。
MySQL、Oracle、PolarDBなどのデータベースからリアルタイムでデータを同期する方法の詳細については、「MySQL からのデータ同期用のデータソースを構成する」をご参照ください。
オブジェクトストレージサービス (OSS) からデータをインポートする方法の詳細については、「DLF を使用して OSS からデータを読み書きする」をご参照ください。
データを書き込む場合は、固定プランを使用して効率を 10 倍向上させることができます。詳細については、「固定プランを使用して SQL ステートメントの実行を高速化する」をご参照ください。
データクエリ
さまざまなシナリオでテーブルを作成する方法の詳細については、「シナリオ固有のテーブル作成とチューニングのガイド」をご参照ください。
テーブルを作成する前に、分散キー、クラスタリングキー、イベントタイム列、およびビットマップインデックスの構文と使用方法を理解する必要があります。これらのインデックスは、クエリのパフォーマンスを何倍も向上させるのに役立ちます。詳細については、「CREATE TABLE」をご参照ください。
Hologres 内部テーブルに対するクエリのパフォーマンスを最適化する方法の詳細については、「クエリのパフォーマンスを最適化する」をご参照ください。
MaxCompute データに対するクエリを高速化する方法の詳細については、「Hologres に外部テーブルを作成して MaxCompute データに対するクエリを高速化する」をご参照ください。
O&M とモニタリング
実行中のクエリを特定し、クエリがロックを取得しているか、ロックが解放されるのを待機しているかを確認する方法の詳細については、「クエリの管理」をご参照ください。
失敗したクエリと低速なクエリを特定する方法の詳細については、「低速クエリログのクエリと分析」をご参照ください。
読み取り/書き込み分割と負荷分離の詳細については、「プライマリインスタンスとセカンダリインスタンス (共有ストレージ) の読み取り/書き込み分割を構成する」をご参照ください。