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

MaxCompute:MAPJOIN HINT

最終更新日:Dec 09, 2024

大きなテーブルと複数の小さなテーブルをjoinする場合は、SELECT文でMAPJOINヒントを明示的に指定して、クエリのパフォーマンスを向上させることができます。 このトピックでは、MAPJOIN hintを使用してテーブルを結合する方法について説明します。

説明

JOIN操作には、マップ、シャッフル、およびリデュースの3つの段階が含まれます。 ほとんどの場合、テーブルはreduceステージでjoinedされます。

MAPJOINは、縮小ステージではなくマップステージでテーブルを結合します。 これにより、データ送信が高速化され、システムリソースの消費が削減され、ジョブのパフォーマンスが最適化されます。

マップステージでは、MAPJOINは指定された小さなテーブルのすべてのデータをJOIN操作を実行するプログラムのメモリにロードします。 これにより、JOIN動作の効率が向上する。

MaxCompute SQLでは、非equijoinsまたはorロジックをON条件で使用することはできません。 ただし、これはMAPJOINで行うことができます。

制限事項

MAPJOINの使用に関する制限:

  • マップステージでは、MAPJOINは指定されたテーブルのすべてのデータをJOIN操作を実行するプログラムのメモリにロードします。 MAPJOINに指定するテーブルは小さなテーブルである必要があり、テーブルデータが占めるメモリの合計は512 MBを超えることはできません。 MaxCompute は、保存する前にデータを圧縮します。 小さなテーブルがメモリにロードされた後、テーブルのデータ量は急激に増加します。 512 MBは、小さなテーブルをメモリにロードした後の最大データ量を示します。

  • MAPJOINでのJOIN操作の制限:

    • left OUTER JOIN操作の左側のテーブルは、大きなテーブルである必要があります。

    • right OUTER JOIN操作の右側のテーブルは、大きなテーブルである必要があります。

    • MAPJOINは、FULL OUTER JOIN操作では使用できません。

    • INNER JOIN操作の左または右のテーブルは、大きなテーブルにすることができます。

  • MaxComputeでは、MAPJOINに最大128個の小さなテーブルを指定できます。 128を超える小さなテーブルを指定すると、構文エラーが返されます。

使用上の注意

MAPJOINは、/* + mapjoin(<table_name>) */ ヒントをSELECTステートメントに追加した後にのみ実行できます。 以下の点にご注意ください。

  • 小さなテーブルまたはサブクエリを参照する場合は、テーブルまたはサブクエリのエイリアスを参照する必要があります。

  • MAPJOINでは、サブクエリを小さなテーブルとして使用できます。

  • MAPJOINでは、orを使用して非equi結合または結合条件を使用できます。 select /* + MAPJOIN (a) */ a.id from shop a join table_name b ON 1=1; などのON条件を指定せずに、mapjoin on 1=1を使用してデカルト積を計算できます。 しかし、この計算方法は、データ量を増大させる。

  • MAPJOIN内の複数の小さなテーブルは、/* + mapjoin(a,b,c)*/ などのコンマ (,) で区切ります。

説明

SCALAR、IN、NOT IN、EXISTS、NOT EXISTSなどの一部のサブクエリは、実行中にJOIN操作に変換できます。 MAPJOINは効率的なJOINアルゴリズムです。 SUBQUERYの結果が小さなテーブルの場合は、サブクエリ文でHINTを使用して、MAPJOINアルゴリズムを明示的に指定できます。

サンプルデータ

サンプルソースデータは、このトピックの例をよりよく理解するために提供されています。 この例では、sale_detailテーブルとsale_detail_sjテーブルが作成され、データがテーブルに挿入されます。

-- Create a partitioned table named sale_detail. 
create table if not exists sale_detail
(
shop_name     string,
customer_id   string,
total_price   double
)
partitioned by (sale_date string, region string);

create table if not exists sale_detail_sj
(
shop_name     string,
customer_id   string,
total_price   double
)
partitioned by (sale_date string, region string);

-- Add partitions to the sale_detail and sale_detail_sj tables. 
alter table sale_detail add partition (sale_date='2013', region='china');
alter table sale_detail_sj add partition (sale_date='2013', region='china');

-- Insert data into the sale_detail and sale_detail_sj tables. 
insert into sale_detail partition (sale_date='2013', region='china') values ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
insert into sale_detail_sj partition (sale_date='2013', region='china') values ('s1','c1',100.1),('s2','c2',100.2),('s5','c2',100.2),('s2','c2',100.2);

例:

sale_detailテーブルとsale_detail_sjテーブルに対してJOIN操作を実行します。 操作は、以下の条件のいずれかを満たさなければならない。 sale_detail_sjテーブルのtotal_price列の合計値は、sale_detailテーブルのtotal_price列の合計値よりも小さい。 2. sale_detail_sjテーブルのtotal_price列の値とsale_detailテーブルのtotal_price列の値の合計は500未満です。 例:

-- Allow a full scan on a partitioned table.
SET odps.sql.allow.fullscan=true;

-- Use MAPJOIN to perform a query.
select /*+ mapjoin(a) */
        a.shop_name,
        a.total_price,
        b.total_price
from sale_detail_sj a join sale_detail b
on a.total_price < b.total_price or a.total_price + b.total_price < 500;

次の応答が返されます。

+-----------+-------------+--------------+
| shop_name | total_price | total_price2 |
+-----------+-------------+--------------+
| s1        | 100.1       | 100.1        |
| s2        | 100.2       | 100.1        |
| s5        | 100.2       | 100.1        |
| s2        | 100.2       | 100.1        |
| s1        | 100.1       | 100.2        |
| s2        | 100.2       | 100.2        |
| s5        | 100.2       | 100.2        |
| s2        | 100.2       | 100.2        |
| s1        | 100.1       | 100.3        |
| s2        | 100.2       | 100.3        |
| s5        | 100.2       | 100.3        |
| s2        | 100.2       | 100.3        |
+-----------+-------------+--------------+