MaxCompute exécute les clauses d'une instruction SELECT dans un ordre différent de celui de leur écriture syntaxique. Comprendre cet ordre d'exécution vous aide à rédiger une logique de requête correcte, en particulier lorsque vous utilisez GROUP BY, HAVING et des clauses spécifiques à MaxCompute telles que DISTRIBUTE BY et SORT BY.
Séquences d'exécution
La syntaxe SELECT prend en charge les clauses suivantes : SELECT, FROM, WHERE, GROUP BY, HAVING, WINDOW, QUALIFY, ORDER BY, DISTRIBUTE BY, SORT BY et LIMIT.
MaxCompute exécute ces clauses selon l'une des deux séquences suivantes, en fonction des clauses utilisées.
Les clausesORDER BYetGROUP BYne peuvent pas être utilisées conjointement avecDISTRIBUTE BYouSORT BY.
Séquence 1 — utilisée lorsque votre requête inclut GROUP BY, ORDER BY ou LIMIT :
FROMWHEREGROUP BYHAVINGSELECTORDER BYLIMIT
Séquence 2 — utilisée lorsque votre requête inclut DISTRIBUTE BY ou SORT BY :
FROMWHERESELECTDISTRIBUTE BYSORT BY
Bien que la clause SELECT apparaisse en premier dans la syntaxe écrite, elle n'est exécutée qu'après le traitement des clauses FROM, WHERE, GROUP BY et HAVING.
Rédaction des instructions selon l'ordre d'exécution
Pour faciliter la lecture de la logique des requêtes, MaxCompute vous permet de rédiger les instructions SELECT dans l'ordre d'exécution, c'est-à-dire en plaçant FROM en premier plutôt que SELECT. Les deux formes sont équivalentes :
-- Standard form (SELECT first)
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;
-- Execution-order form (FROM first) — equivalent to the statement above
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;
La syntaxe complète selon l'ordre d'exécution est la suivante :
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>]
Exemple de données
Les exemples de cette rubrique utilisent une table partitionnée nommée sale_detail. Exécutez les instructions suivantes pour créer et remplir la table :
-- 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);
-- Add partitions
ALTER TABLE sale_detail ADD
PARTITION (sale_date='2013', region='china')
PARTITION (sale_date='2014', region='shanghai');
-- Insert data
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);
Pour afficher l'intégralité de la table :
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 |
+------------+-------------+-------------+------------+------------+
Exemples
Exemple 1 : Séquence 1 (GROUP BY et ORDER BY)
L'interrogation d'une table partitionnée sans spécification de partitions nécessite une analyse complète de la table. Ajoutez SET odps.sql.allow.fullscan=true; avant l'instruction pour l'activer.
Les deux instructions suivantes sont équivalentes. Elles utilisent toutes deux la Séquence 1.
-- Standard form
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;
-- Execution-order form
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;
Résultat :
+------------+------------+
| region | _c1 |
+------------+------------+
| china | 100.3 |
+------------+------------+
Ordre d'exécution des clauses :
FROM
sale_detail— lit les lignes de la table.WHERE
total_price > 100— conserve uniquement les lignes dont la valeurtotal_priceest supérieure à 100.GROUP BY
region— regroupe les lignes restantes par région.HAVING
sum(total_price) > 300.5— conserve uniquement les groupes dont le prix total dépasse 300,5.SELECT
region, max(total_price)— projette la région et le prix maximal de chaque groupe.ORDER BY
region— trie le résultat par région.LIMIT
5— renvoie les cinq premières lignes.
Exemple 2 : Séquence 2 (DISTRIBUTE BY et SORT BY)
Les deux instructions suivantes sont équivalentes. Elles utilisent toutes deux la Séquence 2.
-- Standard form
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;
-- Execution-order form
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;
Résultat :
+------------+-------------+------------+
| shop_name | total_price | region |
+------------+-------------+------------+
| s3 | 100.3 | china |
| s6 | 100.4 | shanghai |
| s7 | 100.5 | shanghai |
+------------+-------------+------------+
Ordre d'exécution des clauses :
FROM
sale_detail— lit les lignes de la table.WHERE
total_price > 100.2— conserve uniquement les lignes dont la valeurtotal_priceest supérieure à 100,2.SELECT
shop_name, total_price, region— projette les trois colonnes.DISTRIBUTE BY
region— répartit les lignes entre les réducteurs à l'aide du hachage sur la colonne region.SORT BY
total_price— trie les lignes au sein de chaque réducteur par ordre croissant detotal_price.