大きなテーブルと複数の小さなテーブルを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 |
+-----------+-------------+--------------+