MaxCompute は、SELECT ステートメントの句を、構文に記述された順序とは異なる順序で実行します。 この実行順序を理解することは、特に GROUP BY、HAVING、および MaxCompute 固有の句である DISTRIBUTE BY や SORT BY を使用する際に、正しいクエリロジックを記述する上で役立ちます。
実行順序
SELECT 構文 では、SELECT、FROM、WHERE、GROUP BY、HAVING、WINDOW、QUALIFY、ORDER BY、DISTRIBUTE BY、SORT BY、および LIMIT の句を使用できます。
MaxCompute は、使用する句に応じて、これらを 2 つのシーケンスのいずれかで実行します。
ORDER BYおよびGROUP BYは、DISTRIBUTE BYまたはSORT BYと一緒に使用することはできません。
シーケンス 1 :クエリに GROUP BY、ORDER BY、または LIMIT が含まれる場合に使用します。
-
FROM -
WHERE -
GROUP BY -
HAVING -
SELECT -
ORDER BY -
LIMIT
シーケンス 2 :クエリに DISTRIBUTE BY または SORT BY が含まれる場合に使用します。
-
FROM -
WHERE -
SELECT -
DISTRIBUTE BY -
SORT BY
SELECT は構文上は最初に記述されますが、FROM、WHERE、GROUP BY、および HAVING が処理された後にのみ実行されます。
実行順序に沿ったステートメントの記述
クエリロジックを読みやすくするために、MaxCompute では SELECT ステートメントを SELECT からではなく FROM から始める実行順序に沿って記述できます。 2 つの形式は同等です:
-- 標準形式 (SELECT が先)
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 が先) - 上記のステートメントと同等
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;
実行順序に沿って記述する場合の構文は次のとおりです:
FROM <table_reference>
[WHERE <where_condition>]
[GROUP BY <col_list>]
[HAVING <having_condition>]
[WINDOW <window_name> AS (<window_definition>)]
[QUALIFY <expression>]
SELECT [ALL | DISTINCT] <select_expr>, <select_expr>, ...
[ORDER BY <order_condition>]
[DISTRIBUTE BY <distribute_condition> [SORT BY <sort_condition>]]
[LIMIT <number>]
サンプルデータ
このトピックの例では、パーティションテーブル sale_detail を使用します。 次のステートメントを実行して、テーブルを作成し、データを挿入します:
-- パーティションテーブル 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');
-- データの挿入
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 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 |
+------------+-------------+-------------+------------+------------+
例
例 1:シーケンス 1 (GROUP BY と ORDER BY)
パーティションを指定せずにパーティションテーブルをクエリするには、フルテーブルスキャンが必要です。 ステートメントの前に SET odps.sql.allow.fullscan=true; を追加して有効にしてください。
次の 2 つのステートメントは同等です。 どちらもシーケンス 1 を使用します。
-- 標準形式
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;
-- 実行順序形式
SET odps.sql.allow.fullscan=true;
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 |
+------------+------------+
句の実行プロセス:
-
FROM
sale_detail:テーブルから行を読み取ります。 -
WHERE
total_price > 100:total_priceが 100 を超える行のみを保持します。 -
GROUP BY
region:残りの行をregionごとにグループ化します。 -
HAVING
sum(total_price) > 300.5:合計価格が 300.5 を超えるグループのみを保持します。 -
SELECT
region, max(total_price):各グループからregionと最大価格を射影します。 -
ORDER BY
region:結果をregionでソートします。 -
LIMIT
5:最初の 5 行を返します。
例 2:シーケンス 2 (DISTRIBUTE BY と SORT BY)
次の 2 つのステートメントは同等です。 どちらもシーケンス 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;
-- 実行順序形式
SET odps.sql.allow.fullscan=true;
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 |
+------------+-------------+------------+
句の実行プロセス:
-
FROM
sale_detail:テーブルから行を読み取ります。 -
WHERE
total_price > 100.2:total_priceが 100.2 を超える行のみを保持します。 -
SELECT
shop_name, total_price, region:3 つの列を射影します。 -
DISTRIBUTE BY
region:region列のハッシュパーティショニングを使用して、レデューサーに行を分散させます。 -
SORT BY
total_price:各レデューサー内で、行をtotal_priceの昇順でソートします。