MaxCompute では、SELECT 文の句は、記述された順序とは異なる順序で実行されます。この論理的な処理順序を理解することは、正しいクエリを記述し、定義される前に列エイリアスを参照するなどのエラーを回避するのに役立ちます。
仕組み
MaxCompute の SELECT 文は、SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY、DISTRIBUTE BY、SORT BY、LIMIT の 9 つの句をサポートしています。
これらの句は、どの句が存在するかに応じて、2 つのシーケンスのいずれかで処理されます。
シーケンス 1 — GROUP BY、HAVING、または ORDER BY が存在する場合に使用されます:
| ステップ | 句 | 処理内容 |
|---|---|---|
| 1 | FROM | ソーステーブルを識別します |
| 2 | WHERE | 集約前に行をフィルターします |
| 3 | GROUP BY | フィルターされた行をグループ化します |
| 4 | HAVING | 集約条件に基づいてグループをフィルターします |
| 5 | SELECT | 列を射影し、式を計算します |
| 6 | ORDER BY | 結果セットをソートします |
| 7 | LIMIT | 出力行数を制限します |
シーケンス 2 — DISTRIBUTE BY または SORT BY が存在する場合に使用されます:
| ステップ | 句 | 処理内容 |
|---|---|---|
| 1 | FROM | ソーステーブルを識別します |
| 2 | WHERE | 行をフィルターします |
| 3 | SELECT | 列を射影します |
| 4 | DISTRIBUTE BY | ハッシュパーティショニングを使用して、Reducer 間で行を分散させます |
| 5 | SORT BY | 各パーティション内で行をソートします |
ORDER BYとGROUP BYは、同じクエリ内でDISTRIBUTE BYまたはSORT BYと一緒に使用することはできません。
実行順序での SELECT 文の記述
MaxCompute では、FROM を SELECT の前に配置することで、実行順序で句を指定して SELECT 文を記述できます。これにより、論理的なフローが明確になり、読みやすくなります。
標準構文 (記述順):
SELECT [ALL | DISTINCT] <select_expr>, <select_expr>, ...
FROM <table_reference>
[WHERE <where_condition>]
[GROUP BY <col_list>]
[HAVING <having_condition>]
[ORDER BY <order_condition>]
[DISTRIBUTE BY <distribute_condition> [SORT BY <sort_condition>]]
[LIMIT <number>]実行順序構文 (FROM-first):
FROM <table_reference>
[WHERE <where_condition>]
[GROUP BY <col_list>]
[HAVING <having_condition>]
SELECT [ALL | DISTINCT] <select_expr>, <select_expr>, ...
[ORDER BY <order_condition>]
[DISTRIBUTE BY <distribute_condition> [SORT BY <sort_condition>]]
[LIMIT <number>]どちらの形式でも、生成される結果は同じです。コード内で実行シーケンスを可視化したい場合は、FROM-first 形式を推奨します。
サンプルデータ
このトピックの例では、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);
-- パーティションの追加
ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china') PARTITION (sale_date='2014', region='shanghai');
-- 2013/china パーティションへのデータ挿入
INSERT INTO sale_detail PARTITION (sale_date='2013', region='china')
VALUES ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
-- 2014/shanghai パーティションへのデータ挿入
INSERT INTO sale_detail PARTITION (sale_date='2014', region='shanghai')
VALUES ('null','c5',null),('s6','c6',100.4),('s7','c7',100.5);挿入されたデータを確認するには:
SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail;結果:
+------------+-------------+-------------+------------+------------+
| shop_name | customer_id | total_price | sale_date | region |
+------------+-------------+-------------+------------+------------+
| s1 | c1 | 100.1 | 2013 | china |
| s2 | c2 | 100.2 | 2013 | china |
| s3 | c3 | 100.3 | 2013 | china |
| null | c5 | NULL | 2014 | shanghai |
| s6 | c6 | 100.4 | 2014 | shanghai |
| s7 | c7 | 100.5 | 2014 | shanghai |
+------------+-------------+-------------+------------+------------+パーティションを指定せずにパーティションテーブルをクエリするには、ステートメントの前に SET odps.sql.allow.fullscan=true; が必要です。本番環境では、全表スキャンを避けるためにパーティションを直接指定してください。例
例 1:シーケンス 1 (GROUP BY、HAVING、ORDER BY)
次の 2 つのクエリは同等です。1 つ目は標準の記述順を使用し、2 つ目は実行順を使用します。
-- 標準の記述順
SET odps.sql.allow.fullscan=true;
SELECT region, MAX(total_price)
FROM sale_detail
WHERE total_price > 100
GROUP BY region
HAVING SUM(total_price) > 300.5
ORDER BY region
LIMIT 5;
-- 実行順 (FROM-first) — 上記のクエリと同等
FROM sale_detail
WHERE total_price > 100
GROUP BY region
HAVING SUM(total_price) > 300.5
SELECT region, MAX(total_price)
ORDER BY region
LIMIT 5;結果:
+------------+------------+
| region | _c1 |
+------------+------------+
| china | 100.3 |
+------------+------------+クエリがステップバイステップでどのように処理されるか:
| ステップ | 句 | 中間結果 |
|---|---|---|
| 1 | FROM sale_detail | テーブルからの全 6 行 |
| 2 | WHERE total_price > 100 | total_price が 100 を超える 5 行 (NULL 行は除外) |
| 3 | GROUP BY region | 2 つのグループ:china (3 行) と shanghai (2 行) |
| 4 | HAVING SUM(total_price) > 300.5 | 1 つのグループ:china (合計 = 300.6) |
| 5 | SELECT region, MAX(total_price) | 1 行:(china, 100.3) |
| 6 | ORDER BY region | リージョンで昇順に並べ替えられています。リージョン |
| 7 | LIMIT 5 | 最大 5 行が返されます |
例 2:シーケンス 2 (DISTRIBUTE BY、SORT BY)
次の 2 つのクエリは同等です:
-- 標準の記述順
SET odps.sql.allow.fullscan=true;
SELECT shop_name,
total_price,
region
FROM sale_detail
WHERE total_price > 100.2
DISTRIBUTE BY region
SORT BY total_price;
-- 実行順 (FROM-first) — 上記のクエリと同等
FROM sale_detail
WHERE total_price > 100.2
SELECT shop_name,
total_price,
region
DISTRIBUTE BY region
SORT BY total_price;結果:
+------------+-------------+------------+
| shop_name | total_price | region |
+------------+-------------+------------+
| s3 | 100.3 | china |
| s6 | 100.4 | shanghai |
| s7 | 100.5 | shanghai |
+------------+-------------+------------+クエリがステップバイステップでどのように処理されるか:
| ステップ | 句 | 中間結果 |
|---|---|---|
| 1 | FROM sale_detail | テーブルからの全 6 行 |
| 2 | WHERE total_price > 100.2 | 3 行:s3 (100.3)、s6 (100.4)、s7 (100.5) |
| 3 | SELECT shop_name, total_price, region | 3 つの列が射影されます |
| 4 | DISTRIBUTE BY region | ハッシュパーティショニングを使用して、region によって Reducer 間で行が分散されます |
| 5 | SORT BY total_price | 各パーティション内で total_price の昇順で行がソートされます |