O MaxCompute executa as cláusulas de uma instrução SELECT em uma ordem diferente da sintaxe escrita. Compreender essa ordem de execução ajuda a escrever lógicas de consulta corretas, especialmente ao usar GROUP BY, HAVING e cláusulas específicas do MaxCompute, como DISTRIBUTE BY e SORT BY.
Sequências de execução
A SELECT syntax oferece suporte às seguintes cláusulas: SELECT, FROM, WHERE, GROUP BY, HAVING, WINDOW, QUALIFY, ORDER BY, DISTRIBUTE BY, SORT BY e LIMIT.
O MaxCompute executa essas cláusulas em uma de duas sequências, conforme as cláusulas utilizadas.
Não useORDER BYeGROUP BYjunto comDISTRIBUTE BYouSORT BY.
Sequência 1 — aplicável quando a consulta inclui GROUP BY, ORDER BY ou LIMIT:
FROMWHEREGROUP BYHAVINGSELECTORDER BYLIMIT
Sequência 2 — aplicável quando a consulta inclui DISTRIBUTE BY ou SORT BY:
FROMWHERESELECTDISTRIBUTE BYSORT BY
Embora SELECT apareça primeiro na sintaxe escrita, ele é executado somente após o processamento de FROM, WHERE, GROUP BY e HAVING.
Escreva instruções na ordem de execução
Para facilitar a leitura da lógica de consulta, o MaxCompute permite escrever instruções SELECT na ordem de execução, com FROM antes de SELECT. As duas formas são equivalentes:
-- 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;
A sintaxe completa na ordem de execução é:
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>]
Dados de exemplo
Os exemplos neste tópico usam uma tabela particionada chamada sale_detail. Execute as instruções a seguir para criar e popular a tabela:
-- 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);
Para visualizar a tabela completa:
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 |
+------------+-------------+-------------+------------+------------+
Exemplos
Exemplo 1: Sequência 1 (GROUP BY e ORDER BY)
Consultar uma tabela particionada sem especificar partições exige uma varredura completa da tabela. Adicione SET odps.sql.allow.fullscan=true; antes da instrução para ativar essa opção.
As duas instruções a seguir são equivalentes e usam a Sequência 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;
Resultado:
+------------+------------+
| region | _c1 |
+------------+------------+
| china | 100.3 |
+------------+------------+
Ordem de execução das cláusulas:
FROM
sale_detail— lê as linhas da tabela.WHERE
total_price > 100— mantém apenas as linhas em quetotal_priceexcede 100.GROUP BY
region— agrupa as linhas restantes por região.HAVING
sum(total_price) > 300.5— retém somente os grupos cujo preço total ultrapassa 300,5.SELECT
region, max(total_price)— projeta a região e o preço máximo de cada grupo.ORDER BY
region— ordena o resultado por região.LIMIT
5— retorna as cinco primeiras linhas.
Exemplo 2: Sequência 2 (DISTRIBUTE BY e SORT BY)
As duas instruções a seguir são equivalentes e usam a Sequência 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;
Resultado:
+------------+-------------+------------+
| shop_name | total_price | region |
+------------+-------------+------------+
| s3 | 100.3 | china |
| s6 | 100.4 | shanghai |
| s7 | 100.5 | shanghai |
+------------+-------------+------------+
Ordem de execução das cláusulas:
FROM
sale_detail— lê as linhas da tabela.WHERE
total_price > 100.2— mantém apenas as linhas em quetotal_priceexcede 100,2.SELECT
shop_name, total_price, region— projeta as três colunas.DISTRIBUTE BY
region— distribui as linhas entre os reducers usando particionamento por hash na coluna de região.SORT BY
total_price— classifica as linhas dentro de cada reducer em ordem crescente com base emtotal_price.