すべてのプロダクト
Search
ドキュメントセンター

MaxCompute:Rangeクラスタリング

最終更新日:Sep 16, 2025

Rangeクラスタリングは、グローバルにソートされた順序でデータを分散する新しいデータクラスタリング方法です。 Rangeクラスタリングは、ハッシュクラスタリングによって引き起こされる可能性のあるデータスキューの問題を防ぐことができます。 Rangeクラスタリングでは、2レベルのインデックスを作成することもできます。Rangeクラスタリングは、クラスターキーに基づくRangeクエリやマルチキークエリなどのシナリオに適しています。 このトピックでは、MaxComputeでRangeクラスタリングを使用する方法について説明します。

背景情報

ハッシュクラスタ化テーブルには、次の利点があります。

  • 特定の列値に基づいてデータをクエリする場合は、ハッシュアルゴリズムを使用してハッシュバケットを直接見つけることができます。 このプロセスはバケットプルーニングと呼ばれます。 バケット内のデータがソートされた方法で保存されている場合は、さらにインデックスを使用してデータを見つけることができます。 これにより、スキャンデータの量が減り、クエリ効率が向上します。

  • 各テーブルの特定の列で2つのテーブルを結合し、いずれかのテーブルの列がハッシュされている場合、シャッフルステップを削除できます。 これにより、コンピューティングリソースを節約できます。

ハッシュクラスタリング機能の詳細については、「ハッシュクラスタリング」をご参照ください。

ハッシュクラスタリングには次の制限があります。

  • ハッシュアルゴリズムを使用してバケットを作成すると、データスキューの問題が発生する可能性があります。 ジョインスキューの問題と同様に、データスキューの問題はハッシュアルゴリズムに固有のものです。 入力データがバケット間で不均一に分散されると、データスキューの問題が発生する可能性があります。 その結果、バケット内のデータ量が大きく異なります。 ハッシュクラスタリングを使用する場合、ほとんどの場合、各バケットは同時処理の単位になります。 バケット内のデータ量が異なる場合、ロングテールが発生する可能性があります。

  • バケットプルーニングは、等価クエリのみをサポートします。 列の値が0より大きいという条件など、等しくない条件に基づいてデータをクエリする場合、クエリされたデータが格納されているバケットを見つけることができません。 この場合、すべてのバケットのデータを照会する必要があります。

  • 複数のクラスターキーに基づくクエリの場合、すべてのクラスターキーが使用可能で、すべてのクエリ条件が等しい条件である場合にのみ、クエリのパフォーマンスを向上させることができます。

    たとえば、次のステートメントを使用して作成されたテーブルのデータを照会します。 クエリ条件としてC1=x AND C2=yを使用する場合にのみ、クエリのパフォーマンスを向上させることができます。 C1=xまたはC2=yをクエリ条件として使用する場合、ハッシュクラスタリングに基づいてクエリを高速化することはできません。 これは、キーがクエリに使用されるときに、キーのハッシュ値がペアに結合されるためです。 キーのハッシュ値が結合されていない場合、クエリされたデータが格納されているバケットを見つけることができないか、バケットのプルーニングを実装できません。

    CREATE TABLE T2 (C1 int, C2 int, C3 string)
       CLUSTERED BY (C1, C2)
          SORTED by (C1, C2)
           INTO 1024 BUCKETS;

制限に対処するために、MaxComputeは、Rangeクラスタリングと呼ばれる新しいデータクラスタリング方法を提供します。

説明

Rangeクラスタリングは、クラスターキーの完全なソートに基づいて、データを複数のばらばらの範囲に分割します。 各範囲はバケットと見なされ、次の両方の条件を満たす必要があります。

  • 重複した値は同じバケットに格納されます。

  • 各バケットの値の数は概算です。

次のサンプルステートメントは、Tという名前のテーブルを作成します。

CREATE TABLE T (C1 int) 
    RANGE CLUSTERED BY (C1) 
    SORTED BY (c1) 
    INTO 3 BUCKETS;

C1列の値は、{ 1、8、-3、2、4、1、1、3、8、20、-8、9 } です。

Rangeクラスタリングを有効にすると、次のバケットが取得されます。

  • バケット0 : { -8, -3, 1, 1}

  • バケット1 : { 2、3、4}

  • バケット2 : { 8、8、9、20}

説明
  • バケットによって表される範囲は、ばらばらであってもよい。 たとえば、バケット1の範囲は [2, 4] で、バケット2の範囲は [8, 20] です。 (4,8) の範囲内の値はない。

  • 範囲クラスタリングは、範囲サイズを近似するのではなく、バケットサイズを近似することを目的としています。 データを計算する場合、各バケットは同時処理の単位になります。 同じバケットサイズでロングテールの問題を防ぎます。 しかしながら、各範囲内のデータ分布は同じでなくてもよい。 したがって、一貫したバケットサイズは、一貫した範囲サイズを表しません。

Rangeクラスタリングプロセスは、MaxComputeによって自動的に実装されます。 各範囲を手動で指定する必要はありません。 ビッグデータシナリオでは、範囲の手動構成は効率的または実現可能ではありません。 MaxComputeは、データを自動的にソートおよびサンプリングし、各範囲のデータ分布に基づいてヒストグラムを作成し、各範囲のヒストグラムを組み合わせて計算します。 これにより、MaxComputeは範囲クラスタリングの最適なパフォーマンスを実現します。

テーブルを作成するときに、RANGE CLUSTERED BYSORTED BYの両方を指定して、データがグローバルにソートされるようにすることができます。 次に、MaxComputeは、グローバルインデックスとファイルインデックスの2つのレベルのインデックスを自動的に作成します。 次の図に示すように、インデックスを使用してキー値をすばやく検索します。range clustering

Rangeクラスタリングには、ハッシュクラスタリングに対して次の利点があります。

  • Rangeクエリがサポートされています。

    たとえば、クエリ条件がc < 3の場合、システムはグローバルインデックスに基づいてバケット2とバケット3を除外し、バケット0とバケット1からデータをクエリできます。 ハッシュクラスタリングの場合、バケットのプルーニングは等価クエリに対してのみ実行できます。

  • マルチキークエリがサポートされています。

    たとえば、テーブル作成時にRANGE CLUSTERED BY (c1, c2, c3) SORTED BY (c1, c2, c3) を指定した場合、範囲クラスタリングとデータストレージはc1、c2、c3の順に実装されます。 このようにして、c1 = 100 AND c2 > 0c1 = 100 AND c2 = 50 AND c3 < 5などの複雑な条件に基づいてテーブルデータを照会できます。 このタイプのクエリは、ハッシュクラスタリングに基づいて実装することはできません。

    重要

    複数のキーに基づくクエリの場合、クエリ条件のキーは順番に並べ替える必要があり、最後のキーのみを使用して値の範囲を指定できます。

  • 範囲クラスタリングは、グローバルソートの効率的な実装を提供します。

    範囲クラスタリングを使用する前は、MaxComputeでは1つのインスタンスのみを使用してデータをグローバルにソートできます。 範囲クラスタリングを使用した後、各範囲のデータを同時にソートしてから組み合わせることができ、効率が大幅に向上します。

使用上の注意

範囲クラスタリングの構文は、ハッシュクラスタリングの構文と同様です。 違いは、範囲キーワードとバケット数が範囲クラスタリングのオプションであることです。

Rangeクラスタ化テーブルの作成

CREATE TABLEステートメントを使用して、範囲クラスタ化テーブルを作成できます。 このステートメントでは、RANGE CLUSTERED BYパラメーターを指定する必要があります。 INTO number_of_buckets BUCKETSおよびSORTED BYパラメーターはオプションです。 ほとんどの場合、SORTED BYとRANGE CLUSTERED BYで同じ値を指定することを推奨します。 このように、最適な最適化効果を達成することができる。

  • 構文

    CREATE TABLE [IF NOT EXISTS] <table_name>
                 [(<col_name> data_type [comment <col_comment>], ...)]
                 [comment table_comment]
                 [PARTITIONED BY (<col_name> data_type [comment <col_comment>], ...)]
                 [RANGE CLUSTERED BY (<col_name> [, <col_name>, ...])
                 [SORTED BY (<col_name> [ASC | DESC]
                 [, <col_name> [ASC | DESC] ...])]
                 [INTO <number_of_buckets> BUCKETS]]
                 [AS select_statement]
    • パーティション分割されていないテーブル

      CREATE TABLE T1 (a string, b string, c int)
                   RANGE CLUSTERED BY (c)
                   SORTED by (c)
                   INTO 1024 BUCKETS;
    • パーティションテーブル

      CREATE TABLE T1 (a string, b string, c int)
                   PARTITIONED BY (dt int)
                   RANGE CLUSTERED BY (c)
                   SORTED by (c)
                   INTO 1024 BUCKETS;
  • パラメーター

    • によって集められた範囲

      範囲クラスタリングのキーを指定します。 パラメーターを指定すると、MaxComputeは指定したバケット数に基づいて、1つ以上のデータ列を適切な範囲に並べ替えてサンプリングします。 データスキューの問題やホットスポットを防ぎ、同時クエリのパフォーマンスを向上させるために、RANGE CLUSTERED BYで、値の範囲が大きく、重複するキー値がほとんどない列を指定することをお勧めします。 クエリのパフォーマンスを最適化するには、RANGE CLUSTERED BYで一般的に使用される集計キーまたはフィルターキーを指定することを推奨します。

    • によって歌われた

      バケット内のフィールドをソートする方法を指定します。 最適なクエリパフォーマンスを実現するには、SORTED BYとRANGE CLUSTERED BYで同じ値を指定することを推奨します。 SORTED BYを指定すると、MaxComputeはグローバルインデックスとファイルインデックスを自動的に生成し、インデックスを使用してクエリを高速化します。

    • 番号_of_bucketsバケットへ

      ハッシュクラスタリングとは異なり、INTO number_of_buckets BUCKETSは範囲クラスタリングのオプションです。 このパラメーターを指定しない場合、MaxComputeはデータ量に基づいてバケット数を自動的に決定します。 ほとんどの場合、実際の状況に基づいてバケットの数を指定することをお勧めします。

      ハッシュクラスタリングと同様に、範囲クラスタリングのバケットサイズ (512 MB〜1 GB) に基づいてバケット数を設定することを推奨します。 テーブルが大きすぎる場合、多数のバケットが必要になります。 ただし、テーブル内のバケット数は4,000を超えないようにすることを推奨します。

テーブルのハッシュクラスタリングプロパティの変更

パーティション分割テーブルの場合、ALTER TABLEステートメントを実行して、範囲クラスタリングプロパティを追加または削除できます。

  • 構文

    -- Change a table to a range-clustered table.
    ALTER TABLE <table_name> [RANGE CLUSTERED BY (<col_name> [, <col_name>, ...])
                             [SORTED BY (<col_name> [ASC | DESC] [, <col_name> [ASC | DESC] ...])]
                             [INTO <number_of_buckets> BUCKETS];
    -- Change a range-clustered table to a non-range-clustered table.
    ALTER TABLE <table_name> NOT CLUSTERED;
  • 使用上の注意

    • ALTER TABLEステートメントは、パーティション分割テーブルのクラスタリングプロパティのみを変更できます。 パーティション分割されていないテーブルの場合、クラスタリングプロパティをテーブルに追加した後にクラスタリングプロパティを変更することはできません。

    • ALTER TABLEステートメントは、INSERT OVERWRITEステートメントを使用して生成された新しいパーティションを含む、テーブルの新しいパーティションに対してのみ有効です。 新しいパーティションは、クラスタリングプロパティに基づいて格納されます。 既存のパーティションのストレージ形式は変更されません。

    • ALTER TABLE文は、テーブルの新しいパーティションに対してのみ有効です。 したがって、このステートメントでパーティションを指定することはできません。

ALTER TABLEステートメントは、既存のテーブルに適しています。 範囲クラスタリングプロパティが追加されると、範囲クラスタリングプロパティに基づいて新しいパーティションが格納されます。

テーブルのプロパティを明示的に検証する

範囲クラスタ化テーブルを作成した後、次のステートメントを実行してテーブルのプロパティを表示できます。 範囲クラスタリングプロパティは、返された結果のExtended Infoに表示されます。

DESC EXTENDED <table_name>;

次の図は、返される結果の例を示しています。 表属性验证パーティションテーブルの場合、次のステートメントを実行して、パーティションのクラスタリングプロパティを表示することもできます。

DESC EXTENDED <table_name> partition(<pt_spec>);

次の図は、返される結果の例を示しています。分区表range属性验证

シナリオ

フィルタリングによるクエリの最適化

テーブルに対して範囲クラスタリングが有効になっている場合、テーブル内のデータはグローバルにソートされます。 MaxComputeは、ソートされたデータに基づいてグローバルインデックスとファイルインデックスを自動的に作成します。 これは、データ記憶特性に基づくデータフィルタリングの効率を改善する。 範囲クラスタリングを使用して、等価クエリと範囲クエリを最適化できます。

たとえば、単純なクエリ条件id < 3の場合、システムはオプティマイザから条件を抽出し、条件を値の範囲 (-∞, 3) に変換します。 この場合、バケットプルーニングにグローバルインデックスを使用して、データが前の値の範囲内にないバケット2とバケット3の両方を除外できます。 次に、システムはバケット0とバケット1の各ファイルのインデックスを使用して、データをすばやく見つけることができます。 このプロセスは、次の図に示すように、述語プッシュダウンと呼ばれます。过滤查询优化次のサンプルステートメントは、データセットに対して範囲クラスタリングが実行された後に、100 GBのデータセットからデータをクエリするために使用されるTPC-H Query 6ステートメントです。 TPC-Hクエリ6ステートメントでは、範囲フィルタリングに基づいて集計操作が実行されます。 範囲クラスタリングでは、2レベルのインデックスを使用してデータをすばやく検索できます。 このようにして、クエリの実行時間と消費されるCPUおよびメモリリソースが大幅に削減されます。

select sum(l_extendedprice * l_discount) as revenue
  from tpch_lineitem l
 where l_shipdate >= '1994-01-01'
   and l_shipdate < '1995-01-01'
   and l_discount >= 0.05
   and l_discount <= 0.07
   and l_quantity < 24;

マルチキー照会

この例では、次のステートメントを使用して、mf_tabテーブルを範囲クラスタ化テーブルに変更します。 これは、マルチキークエリをよりよく理解するのに役立ちます。

ALTER TABLE mf_project.mf_tab 
            RANGE CLUSTERED BY (project_name, name)
            SORTED BY (project_name, name)
            INTO 1024 BUCKETS;

テーブルが範囲クラスタ化テーブルに変更された後、プロジェクトレベルで集計クエリを実行できます。 例:

SELECT COUNT(*)
  from mf_project.mf_tab
 WHERE project_name="xxxdw"
   AND ds="20180115"
   AND type="TABLE";

複数のキーを使用して、テーブルを正確に見つけることもできます。 例:

SELECT count(*)
  from mf_project.mf_tab
 WHERE project_name="xxxdw"
   AND name="adm_ctu_cle_kba_midun_trade_dd"
   AND type="TABLE";

範囲クエリに複数のキーを使用することもできます。 次のステートメントは、名前がadmで始まるテーブルを照会します。

SELECT count(*)
  from mf_project.mf_tab
 WHERE project_name="xxxdw"
   AND name>="adm"
   AND name < "adn"
   AND type="TABLE";

前述のクエリはすべて、rangeクラスタリングのグローバルソート機能を完全に利用し、述語プッシュダウンを実行して、テーブルスキャンのI/O操作の数を減らし、データフィルタリングとコンピューティングに消費されるCPUとメモリリソースを節約できます。

rangeクラスタリングに複数のキーを使用する場合は、特定の要件を満たす必要があります。 テーブル作成ステートメントのRANGE CLUSTERED BY k0, k1, ..., knの場合、データクエリにkmを使用する場合、k0, k1, ..., km-1をすべて条件で指定し、すべての条件が等しい条件である必要があります。 このようにして、インデックスベースのクエリ高速化の最適なパフォーマンスを実現できます。

たとえば、k1、k2は、Tという名前のテーブル内のクラスタキーです。

  • クエリ条件がk1 < 5の場合、インデックスベースのクエリの高速化を実現できます。

  • クエリ条件がk1 = 10 AND k2 = 20の場合、インデックスベースのクエリ高速化を実現できます。

  • クエリ条件がk1 = 10 AND k2 < 0の場合、インデックスベースのクエリ高速化を実現できます。

  • クエリ条件がk2 < 0の場合、インデックスベースのクエリの高速化を実現できません。 これは、クエリ条件にk1が指定されていないためです。

  • クエリ条件がk1 < 0 AND k2 > 0の場合、インデックスベースのクエリアクセラレーションを使用して、条件k1 < 0を満たすデータを取得できます。 k2 > 0の条件を満たすデータについては、テーブルスキャンが必要である。

最適化によるグループ化

テーブルに対してrangeクラスタリングが有効になっている場合、テーブル内のデータはグローバルにソートされます。 同じ値を持つキーは、範囲クラスタリング中に同じバケットに配置されます。 このデータの物理的特性を使用して、集計操作中にシャッフルステップを削除できます。

たとえば、Tという名前のテーブルは、次のCREATE tableステートメントを使用して作成されます。 テーブルからデータをクエリする場合は、マップステージのテーブルデータに対してGROUP BY操作を実行できます。

CREATE TABLE T (department int, team string, employee string)
       RANGE CLUSTERED BY (department, team)
       SORTED BY (c1, c2)
       INTO 1024 BUCKETS;

SELECT COUNT(*) from T GROUP BY department, team;
説明

GROUP BYの最適なパフォーマンスを実現するには、GROUP BYとRANGE CLUSTERED BYで同じキーを指定する必要があります。

集約最適化

次のステートメントは、テーブルfooのデータ構造を示しています。

create table foo(a bigint, b bigint, c bigint)
       range clustered by (a,b)
       sorted by(a,b) into 3 buckets;

テーブルfooのバケットに格納されているデータの範囲は次のとおりです。

Bucket 0: [1,1 : 3,3]
Bucket 1: [5,5 : 7,7]
Bucket 2: [8,8 : 9,9]

上記のバケット範囲は、bucket N: [lower bound values : upper bound values] の形式で指定します。 データが列aで集計される場合、代わりに次のバケット範囲が使用されます。

Bucket 0: [1 : 3]
Bucket 1: [5 : 7]
Bucket 2: [8 : 9]

列aと列bで集計操作の実行計画を直接生成し、3つのインスタンスを開始して各バケットのデータを集計し、出力結果を返すことができます。

ただし、列aの値が複数のバケットに分散している場合、無効な結果が返されます。 例:

Bucket 0: [1,1 : 3,3]
Bucket 1: [3,5 : 7,7]
Bucket 2: [7,8 : 9,9]

aには2つの値3と7があり、2つのバケットに別々に格納されます。 有効な結果を取得するには、列aに同じ値を持つタプルを同じインスタンスに配置し、タプルを集計する必要があります。 このようにして、次の図に示すように、バケットが再度作成されます。 赤の2本の破線の間隔は、各インスタンスが読み取ることができるデータの範囲を指定します。归并优化ヒストグラムは、範囲クラスタリングに必要です。 範囲クラスター化テーブルの場合、クラスターキーとソートキーが同じ場合、各バケットに対応するワーカーは、範囲クラスター化テーブルにデータを挿入するときにクラスターキーの値を取得するために、10,000行ごとにタプルをサンプリングします。 得られた値はヒストグラムに保存される。 各バケットのヒストグラムは、クラスターメタデータファイルに保存されます。 このタイプのヒストグラムは、等深度ヒストグラムと呼ばれる。

説明

タプルは、クラスターキーとソートキーが同じ場合にのみサンプリングされます。

各バケットのヒストグラムを取得したら、次のルールに基づいて各ワーカーのバケットを再作成できます。

  • 同じグループ化キーを持つタプルは、同じバケットに格納されます。

  • データはバケットに均等に分散されます。

各新しいバケットの下限値に基づいて、各ワーカーは有効な範囲のデータを読み取り、有効な結果を返すことができます。

次のコンテンツでは、TPC-Hデータセット内の1テラバイトのデータを含むpartsuppテーブルを使用して、パフォーマンスの向上をテストします。 次のステートメントを実行して、partsuppテーブルをrange-clusteredテーブルに変換します。

CREATE TABLE partsupp ( PS_PARTKEY BIGINT NOT NULL,
                        PS_SUPPKEY BIGINT NOT NULL,
                        PS_AVAILQTY BIGINT NOT NULL,
                        PS_SUPPLYCOST  DECIMAL(15,2)  NOT NULL,
                        PS_COMMENT     VARCHAR(199) NOT NULL)
             RANGE CLUSTERED BY(PS_PARTKEY, PS_SUPPKEY)
             SORTED BY(PS_PARTKEY, PS_SUPPKEY) INTO 128 BUCKETS;

次のクエリ文を実行してテストを実行します。

SELECT ps_partkey, count(*) c FROM partsupp GROUP BY ps_partkey;
  • 次のコマンドを実行して、最適化を無効にします。

     set odps.optimizer.enable.range.partial.repartitioning=false;

    サンプル出力: 关闭优化

  • 次のコマンドを実行して最適化を有効にします。

    set odps.optimizer.enable.range.partial.repartitioning=true;

    サンプル出力: 打开优化

テスト結果は、最適化が有効になった後、クエリ速度が57% 向上し、CPU使用率が52% 減少し、メモリ使用量が71% 減少したことを示しています。 パフォーマンスの向上は、データ量とクエリの種類によって異なります。

rangeクラスタ化テーブルの最適化の結合

  • この例では、次のステートメントを使用して2つのテーブルを作成します。

    create table t1(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 3 buckets;
    
    create table t2(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 3 buckets;

    次に、2つのテーブルに異なるデータを挿入します。

    結合する必要がある2つのハッシュクラスタ化テーブルの場合、バケットの数が2つのテーブルで同じである場合、テーブルのバケット内のデータを結合できます。 ただし、このルールは範囲クラスタ化テーブルには適用されません。 結合する必要がある2つの範囲クラスタテーブルの場合、テーブルのバケット数が同じであっても、2つのテーブルのバケット内のデータをバケットIDに基づいて直接結合することはできません。 これは、範囲クラスタ化テーブル内の各バケットの境界が異なる可能性があるためです。 2つの範囲クラスタ化テーブルを結合すると、次の図に示すように、シャッフルステップを持つ実行プランが常に生成されます。hash clustering2つの範囲クラスタ化テーブル間の結合を最適化するには、テーブルの境界を揃えて2つのテーブルのバケットを再作成します。 このようにして、各インスタンスによって読み取ることができるデータの境界が再定義される。

  • 2つのテーブルを作成します。

    create table t1(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 5 buckets;
    
    create table t2(a bigint, b bigint, c bigint, d bigint)
           range clustered by(a,b,c)
           sorted by(a,b,c) into 3 buckets;

    次の図に示すように、一定量のデータをテーブルに挿入すると、バケットの境界が定義されます。bucket boundaryサンプルクエリ1:

    SELECT * FROM t1 JOIN t2 ON t1.a=t2.a AND t1.b=t2.b AND t1.c=t2.c;

    次の図に示すように、オプティマイザは、より多くのバケットを持つテーブルの境界を別のテーブルの境界に揃え、各テーブルの新しい境界を取得します。bucket优化后このようにして、シャッフルステップを有さない実行プランが生成される。查询计划サンプルクエリ2:

    SELECT * FROM t1 JOIN t2 ON t1.a=t2.a AND t1.b=t2.b;

    オプティマイザは、列aと列bに基づいて各テーブルのバケットを作成し、次にバケットを整列して再作成し、各テーブルの各バケットから読み取られるデータに基づいて境界を取得します。 このようにして、前の図に示すように、シャッフルステップを持たない実行プランが生成されます。

  • パフォーマンステスト

    • テーブル変換

      PARTとPARTSUPPという名前の2つのテーブルでテストを実行するには、TPC-Hクエリ2ステートメントを使用します。 各テーブルは1テラバイトのデータを含む。 2つのテーブルを範囲クラスタ化テーブルに変換し、他のテーブルは変更されません。

      CREATE TABLE PARTSUPP ( PS_PARTKEY BIGINT NOT NULL,
                              PS_SUPPKEY BIGINT NOT NULL,
                              PS_AVAILQTY BIGINT NOT NULL,
                              PS_SUPPLYCOST  DECIMAL(15,2)  NOT NULL,
                              PS_COMMENT VARCHAR(199) NOT NULL)
                   RANGE CLUSTERED BY(PS_PARTKEY, PS_SUPPKEY)
                   SORTED BY(PS_PARTKEY, PS_SUPPKEY)
                   INTO 128 BUCKETS;
      CREATE TABLE PART ( P_PARTKEY BIGINT NOT NULL,
                          P_NAME VARCHAR(55) NOT NULL,
                          P_MFGR CHAR(25) NOT NULL,
                          P_BRAND CHAR(10) NOT NULL,
                          P_TYPE  VARCHAR(25) NOT NULL,
                          P_SIZE   BIGINT NOT NULL,
                          P_CONTAINER   CHAR(10) NOT NULL,
                          P_RETAILPRICE DECIMAL(15,2) NOT NULL,
                          P_COMMENT VARCHAR(23) NOT NULL)
                   RANGE CLUSTERED BY(P_PARTKEY)
                   SORTED BY(P_PARTKEY)
                   INTO 64 BUCKETS;

      次のTPC-H Query 2ステートメントを使用してデータを照会します。

      select s_acctbal,
             s_name,
             n_name,
             p_partkey,
             p_mfgr,
             s_address,
             s_phone,
             s_comment
        from part,
             supplier,
             partsupp,
             nation,
             region
       where p_partkey = ps_partkey
         and s_suppkey = ps_suppkey
         and p_size = 15
         and p_type like '%BRASS'
         and s_nationkey = n_nationkey
         and n_regionkey = r_regionkey
         and r_name = 'EUROPE'
         and ps_supplycost = (select min(ps_supplycost)
                                from partsupp, supplier, nation, region
                               where p_partkey = ps_partkey
                                 and s_suppkey = ps_suppkey
                                 and s_nationkey = n_nationkey
                                 and n_regionkey = r_regionkey
                                 and r_name = 'EUROPE')
        order by s_acctbal desc, n_name, s_name, p_partkey limit 100;
    • テスト結果

      • 次のコマンドを実行して、最適化を無効にします。

         set odps.optimizer.enable.range.partial.repartitioning=false;

        サンプル出力: 关闭优化

      • 次のコマンドを実行して最適化を有効にします。

        set odps.optimizer.enable.range.partial.repartitioning=true;

        サンプル出力: 开启优化

      最適化後、2つのステージが削除され、クエリ速度が約21.4% 向上し、CPU使用率が約35.4% 減少し、メモリ使用量が約54.6% 減少します。

グローバルソートの高速化

範囲クラスタリングは、グローバルソートの高速化にも使用できます。 ORDER BYが使用される一般的なシナリオでは、すべてのソート済みデータが同じインスタンスに分散され、グローバルなソートが保証されます。 ただし、これらのシナリオでは同時処理を完全に利用できません。 範囲クラスタリングのパーティショニングステップを使用して、同時グローバルソートを実装できます。 グローバルソートでは、データをサンプリングして範囲に分割し、各範囲のデータを並列にソートしてから、グローバルソートの結果を取得する必要があります。

グローバルソートが完了した後も、テーブルまたはテーブル内のパーティションのクラスタープロパティを変更すると、複数のバケットがテーブルに含まれます。 データ消費時には、ファイル内のデータをバケットIDに基づいて読み取る必要があります。

デフォルトでは、範囲クラスタ化テーブルのグローバルソートアクセラレーションは無効になっています。 グローバルソートの高速化を有効にするには、次のコマンドを実行します。

set odps.optimizer.distribute.ordering.enable=true;

制限と使用に関する注意事項

ハッシュクラスタリングと比較して、範囲クラスタリングには次の制限があります。

  • rangeクラスタリングのデータ生成コストは、ハッシュクラスタリングのそれよりも高い。 ハッシュクラスタリングは、データのハッシュとソートのための単純な操作にすぎません。 ただし、範囲クラスタリングでは、データのサンプリング、ソート、およびヒストグラムの組み合わせが必要です。 実行期間、CPUコスト、メモリコストを含む全体的な消費は、ハッシュクラスタリングの全体的な消費よりも高くなります。 したがって、ハッシュクラスタリングを使用して問題を解決できる場合は、範囲クラスタリングを使用する必要はありません。

  • DYNAMIC PARTITIONまたはINSERT INTOでは、範囲クラスタリングはサポートされていません。

  • rangeクラスタリングは、inner join、left outer join、right outer join、semi joinの結合操作でのみサポートされます。 範囲クラスタリングは、反結合または完全外部結合ではサポートされていません。

  • rangeクラスタ化テーブルの場合、range clustered BYで指定されるキーは、SORTED BYで指定されるキーと同じである必要があります。 たとえば、テーブルの作成時にfooという名前のテーブルにrange clustered by (a,b) sorted by (a,b) が指定されている場合、このトピックで説明されている最適化をテーブルで実行できます。 ただし、barという名前のテーブルにrange clustered by(a,b) sorted by (b,a) が指定されている場合、このトピックで説明されている最適化はテーブルでは実行できません。

  • JOINまたはGROUP BYで指定されるキーは、RANGE CLUSTERED BYで指定されるプレフィックスまたはすべてのキーである必要があります。 たとえば、range clustered by(a,b,c) sorted by(a,b,c) をテーブル作成ステートメントで指定します。 このトピックで説明する最適化は、JOINまたはGROUP BYでキーとしてaa、b、またはa、b、cが指定されている場合にのみ、テーブルで実行できます。 JOINまたはGROUP BYでキーとしてbまたはa,cが指定されている場合、このトピックで説明されている最適化は実現できません。

  • rangeクラスタ化パーティションテーブルの場合、テーブルの2つ以上のパーティションからデータを読み取る場合、このトピックで説明されている最適化は実現できません。 このトピックで説明する最適化は、単一のパーティションを持つパーティションテーブルと非パーティションテーブルでのみ実現できます。