O modo script compila e envia várias instruções SQL como uma única unidade. Isso gera um plano de execução que entra na fila uma única vez e roda em um job único. Essa abordagem é ideal para pipelines de dados ETL, processamento em lote periódico e cenários de orquestração de consultas que exigem múltiplas instruções coordenadas. O recurso suporta o modo normal (execução atômica, padrão) e o modo de execução passo a passo (execução serial).
O modo script não suporta cost estimation. As taxas reais dependem da sua billing details.
Um único script pode referenciar até 10.000 tabelas. Cada referência é contada individualmente, incluindo referências repetidas à mesma tabela e tabelas referenciadas em definições de view.
Se a preparação de dados de múltiplas fontes terminar em horários muito distintos — por exemplo, uma às 01:00 e outra às 07:00 —, evite usar uma variável de tabela para combiná-las em um único job de SQL em modo script.
Casos de uso
Reescrever instruções complexas: Divida subconsultas profundamente aninhadas em uma sequência legível de atribuições de variáveis de tabela.
Construir pipelines com múltiplas instruções: Combine instruções logicamente relacionadas em um único job para reduzir a sobrecarga de fila e agendamento. No modo normal, todas as instruções são executadas atomicamente. Já no modo de execução passo a passo, as instruções rodam serialmente, o que é ideal para cenários de leitura após escrita ou migrações de outras plataformas. Para mais informações, consulte Execution modes.
Sintaxe
Tipos de instrução: O modo script suporta instruções SET, algumas instruções DDL e instruções DML. Instruções de exibição de resultados, como DESC e SHOW, não são suportadas.
Ordem das instruções: Um script deve seguir a ordem fixa
SET→DDL→DML. Cada seção pode conter zero ou mais instruções, mas não é permitido intercalar instruções de seções diferentes.
-- 1. SET
SET odps.sql.type.system.odps2=true;
[SET odps.stage.reducer.num=xxx;]
[SET odps.sql.step.script.mode=true;] -- Enable step-by-step execution mode
[...]
-- 2. DDL
CREATE TABLE table1 xxx;
[CREATE TEMPORARY TABLE table2 xxx;] -- Create a temporary table
[...]
-- 3. DML&DQL
@var1 := SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table3
[WHERE where_condition];
@var2 := SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table4
[WHERE where_condition];
@var3 := SELECT [ALL | DISTINCT] var1.select_expr, var2.select_expr, ...
FROM @var1 JOIN @var2 ON ...;
INSERT OVERWRITE|INTO TABLE [PARTITION (partcol1=val1, partcol2=val2 ...)]
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM @var3;
[@var4 := SELECT [ALL | DISTINCT] var1.select_expr, var1.select_expr, ... FROM @var1
UNION ALL | UNION
SELECT [ALL | DISTINCT] var2.select_expr, var2.select_expr, ... FROM @var2;
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
AS
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM @var4;]
[...]
Modos de execução
O modo script oferece suporte a dois modos de execução.
|
Comportamento |
Modo normal (padrão) |
Modo de execução passo a passo |
|
Como ativar |
Padrão. Nenhuma configuração é necessária. |
Adicione |
|
Compilação |
Todas as instruções DML são compiladas em um único plano de execução. |
Cada instrução DML é compilada em um plano de execução separado. Nota: Scripts muito complexos, como aqueles com milhares de linhas ou numerosas operações, podem exceder os limites de memória de compilação. |
|
Execução |
Todas as instruções são executadas atomicamente como um único job, que inicia apenas após todos os dados de entrada estarem prontos. Se alguma instrução falhar, todo o script falha e todas as operações são revertidas. |
As instruções DML são executadas serialmente. Se uma instrução falhar, as instruções executadas anteriormente não serão revertidas, e você deverá tentar executar o script novamente desde o início. Recomendamos dividir scripts grandes em menores. |
|
Leitura após escrita |
Não suportado. Ocorre um erro se você gravar e depois ler da mesma tabela em um script. |
Suportado, exceto para tabelas transacionais ou particionadas. |
|
Tabela temporária |
Não suportado. |
Suportado. |
Sintaxe DDL
Criar uma tabela temporária
Tabelas temporárias armazenam resultados intermediários em cache para reutilização dentro do mesmo script. Como dependem de um padrão de leitura após escrita, elas são suportadas apenas no modo de execução passo a passo.
Sintaxe
CREATE TEMPORARY TABLE <table_name> (
<col_name> <data_type>, ...
)
[LIFECYCLE <days>]
[AS <select_statement>];
Parâmetros
|
Parâmetro |
Descrição |
|
|
Acessível apenas dentro do script atual. |
|
|
Opcional. Número de dias para reter a tabela antes que ela seja excluída automaticamente. Padrão: 1. |
|
|
Opcional. Popula a tabela com dados de uma instrução SELECT no momento da criação. |
Limitações
Tabelas temporárias exigem o modo de execução passo a passo. Adicione
SET odps.sql.step.script.mode=true;à seção SET do seu script.Uma tabela temporária é acessível somente dentro do script onde foi criada.
Tabelas temporárias não podem ser tabelas particionadas nem tabelas transacionais.
Para remover explicitamente uma tabela temporária, a instrução
DROP TABLEdeve ser a última instrução do script.Evite criar mais de 20 tabelas temporárias em um único script.
Criar uma tabela padrão
O modo script permite a criação de tabelas padrão. Para detalhes sobre a sintaxe, consulte CREATE TABLE.
Sintaxe DML e DQL
Limitações de instruções
Instruções de exibição de resultados: Um script pode conter apenas uma instrução que produza saída na tela, como uma instrução
SELECTisolada. Incluir mais de uma causa um erro. Evite usar esses tipos de instrução em scripts.CREATE TABLE AS: Use esta instrução apenas uma vez por script, e ela deve ser a última instrução executável. Recomendamos criar a tabela primeiro e depois inserir os dados.
Modos de gravação mistos: Não é possível usar OVERWRITE e INTO na mesma tabela dentro do mesmo script. Operações DML em tabelas transacionais e tabelas padrão não podem ser misturadas.
Leitura após escrita: No modo normal, gravar e depois ler de uma tabela no mesmo script causa um erro. Para resolver esse problema, use uma variável de tabela ou mude para o modo de execução passo a passo. O modo passo a passo suporta a operação de leitura após escrita, mas não para tabelas transacionais ou particionadas. Para um exemplo detalhado, consulte Example 3: Read-after-write in normal mode.
Variáveis
Sintaxe
-- Declare a variable by using @. Supported types include TABLE and any MaxCompute data type.
@var1 <type>
-- Assign a value by using :=
@var1 := <select_statement>
Notas de uso
-
Não é possível atribuir uma variável do tipo tabela a uma variável com um tipo de dados especificado. Por exemplo, a seguinte sintaxe não é permitida:
@a TABLE (name STRING); @a := SELECT 'tom'; @b STRING; @b := SELECT * FROM @a; -
Variáveis podem armazenar valores constantes. Converta o valor de uma variável para um escalar usando
DDL0. Uma constante também pode ser armazenada em uma tabela de linha única, conforme mostrado no exemplo a seguir. Para mais informações sobre a sintaxe de conversão, consulte subquery.@a := SELECT 10; -- Assign the constant 10 @b := SELECT key, value + (SELECT * FROM @a) FROM t2; -- Use @a as a scalar SELECT * FROM @b;
Instruções IF
Utilize instruções IF para controlar o fluxo de execução com base em condições.
Sintaxe
-- Single branch
IF (condition) BEGIN
statements
END
-- Multi-branch
IF (condition) BEGIN
statements
END ELSE IF (condition2) BEGIN
statements
END ELSE BEGIN
statements
END
Notas de uso
Se uma ramificação contiver apenas uma única instrução, as palavras-chave
DDL1 eDDL2 são opcionais, semelhante aoDDL3 em Java.Instruções DDL como
DDL4,DDL5 eDDL6 não são suportadas dentro de uma ramificação IF.-
A condição suporta dois tipos:
Expressão booleana: A ramificação é determinada no momento da compilação.
Subconsulta escalar booleana: A ramificação é determinada no tempo de execução. O MaxCompute pode enviar múltiplos jobs.
Exemplo 1: Em uma instrução IF, a condição é uma expressão do tipo BOOLEAN. Esse tipo de instrução DDL 7 pode determinar qual ramificação executar no momento da compilação, conforme mostrado no exemplo a seguir:
@date := '20190101';
@row TABLE(id STRING);
IF (CAST(@date AS BIGINT) % 2 == 0) BEGIN
@row := SELECT id FROM src1;
END ELSE BEGIN
@row := SELECT id FROM src2;
END
INSERT OVERWRITE TABLE dest SELECT * FROM @row;
Exemplo 2: A condição na instrução IF é uma subconsulta escalar booleana. Para esse tipo de instrução DDL 8, a ramificação de execução é determinada no tempo de execução, o que exige que o MaxCompute envie múltiplos jobs:
@i BIGINT;
@t TABLE(id BIGINT, value BIGINT);
IF ((SELECT COUNT(*) FROM src WHERE a = '5') > 1) BEGIN
@i := 1;
@t := SELECT @i, @i*2;
END ELSE BEGIN
@i := 2;
@t := SELECT @i, @i*2;
END
SELECT id, value FROM @t;
Exemplos
Exemplo 1: Exemplo básico
O script a seguir faz join e união de dados de três tabelas de origem e, em seguida, insere os resultados em duas tabelas de destino. Todas as instruções são compiladas em um único DAG e executadas atomicamente.
CREATE TABLE IF NOT EXISTS dest(key STRING, value BIGINT) PARTITIONED BY (d STRING);
CREATE TABLE IF NOT EXISTS dest2(key STRING, value BIGINT) PARTITIONED BY (d STRING);
@a := SELECT * FROM src WHERE value > 0;
@b := SELECT * FROM src2 WHERE key IS NOT NULL;
@c := SELECT * FROM src3 WHERE value IS NOT NULL;
@d := SELECT a.key, b.value FROM @a LEFT OUTER JOIN @b ON a.key = b.key AND b.value > 0;
@e := SELECT a.key, c.value FROM @a INNER JOIN @c ON a.key = c.key;
@f := SELECT * FROM @d UNION SELECT * FROM @e UNION SELECT * FROM @a;
INSERT OVERWRITE TABLE dest PARTITION (d='20171111') SELECT * FROM @f;
@g := SELECT e.key, c.value FROM @e JOIN @c ON e.key = c.key;
INSERT OVERWRITE TABLE dest2 PARTITION (d='20171111') SELECT * FROM @g;
Exemplo 2: Leitura após escrita no modo passo a passo
O script a seguir ativa o modo de execução passo a passo para realizar uma operação de leitura após escrita no mesmo script.
SET odps.sql.step.script.mode=true;
DROP TABLE IF EXISTS foo_t1;
DROP TABLE IF EXISTS foo_t2;
CREATE TABLE foo_t1(a STRING) LIFECYCLE 1;
CREATE TABLE foo_t2(a STRING) LIFECYCLE 1;
@x := SELECT 'hello, world' AS a;
INSERT OVERWRITE TABLE foo_t1 SELECT * FROM @x;
INSERT INTO foo_t2 SELECT * FROM foo_t1 UNION ALL SELECT * FROM foo_t1;
SELECT * FROM foo_t2;
Exemplo 3: Leitura após escrita no modo normal
No modo normal, gravar e depois ler da mesma tabela em um script causa um erro. Este exemplo demonstra o erro e duas soluções possíveis.
Preparação de dados
CREATE TABLE src(key BIGINT, value BIGINT) LIFECYCLE 1;
CREATE TABLE src2(key BIGINT, value BIGINT) LIFECYCLE 1;
INSERT INTO src VALUES(1, 2), (3, 3);
Exemplo de erro (leitura após escrita no modo normal)
INSERT OVERWRITE TABLE src2 SELECT * FROM src WHERE key > 0;
@a := SELECT * FROM src2; -- Error: src2 is written to and then read from in the same script.
SELECT * FROM @a;
Solução 1: Ativar o modo de execução passo a passo
SET odps.sql.step.script.mode=true;
INSERT OVERWRITE TABLE src2 SELECT * FROM src WHERE key > 0;
@a := SELECT * FROM src2;
SELECT * FROM @a;
Solução 2: Reescrever o SQL para usar uma variável de tabela
@a := SELECT * FROM src WHERE key > 0;
INSERT OVERWRITE TABLE src2 SELECT * FROM @a;
SELECT * FROM @a;
Exemplo 4: Criar e excluir uma tabela temporária
O script a seguir cria uma tabela temporária para armazenar em cache os resultados intermediários de um JOIN, lê dela duas vezes e, em seguida, a remove.
-- Enable step-by-step execution mode (required for temporary tables).
SET odps.sql.step.script.mode=true;
DROP TABLE IF EXISTS foo_t1;
CREATE TABLE foo_t1(a BIGINT, b BIGINT);
-- Create a temporary table by using a JOIN.
CREATE TEMPORARY TABLE t AS
SELECT t1.a AS a, t2.d AS b FROM
(SELECT 1 a, 2 b) t1
JOIN
(SELECT 1 c, 10 d) t2
ON t1.a = t2.c;
INSERT INTO foo_t1 SELECT * FROM t UNION ALL SELECT * FROM t;
SELECT * FROM foo_t1;
-- Drop the temporary table (must be the last statement in the script).
DROP TABLE t;
Enviar scripts
O modo script é suportado no MaxCompute Studio, no cliente MaxCompute (odpscmd), no DataWorks e nos SDKs Java e Python.
Cliente MaxCompute (odpscmd)
Use o odpscmd v0.27 ou posterior. Após instalar o cliente MaxCompute, envie um script usando a flag DDL 9:
Crie um arquivo de script, como myscript.sql. Em seguida, execute o comando abaixo na sua interface de linha de comando para rodar o odpscmd. Para mais informações sobre como executar o cliente MaxCompute via linha de comando, consulte Run the MaxCompute client.
..\bin>odpscmd -s myscript.sql
O modo script e as variáveis de tabela não são suportados no shell interativo do odpscmd. A flag DML 0 é uma opção de linha de comando para o odpscmd, semelhante a DML 1 e DML 2. Não se trata de um comando dentro do ambiente interativo.
DataWorks
No DataWorks, utilize um nó ODPS Script para escrever e executar scripts.
No canto superior esquerdo, clique em + Create > Create Node. Na categoria MaxCompute, selecione ODPS Script.
Após escrever o script, clique no ícone Run na barra de ferramentas para executá-lo. O log de saída inclui uma URL do Logview para verificar o plano de execução e os resultados.
SDKs
Execute scripts SQL diretamente com o SDK Java ou Python SDK. Para mais informações, consulte a documentação de Java SDK e Python SDK.
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.aliyun.odps.Instance;
import com.aliyun.odps.Odps;
import com.aliyun.odps.OdpsException;
import com.aliyun.odps.account.Account;
import com.aliyun.odps.account.AliyunAccount;
import com.aliyun.odps.data.Record;
import com.aliyun.odps.task.SQLTask;
public class SdkTest {
public static void main(String[] args) throws OdpsException {
// Your Alibaba Cloud AccessKey pair grants full access to your account and carries high risks.
// We strongly recommend that you create and use a RAM user for API calls and daily operations.
// To create a RAM user, log on to the RAM console.
// This example shows how to use environment variables to store your credentials.
// For security, never hard-code your AccessKey pair into your code.
Account account = new AliyunAccount(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"), System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
Odps odps = new Odps(account);
odps.setDefaultProject("your project_name");
odps.setEndpoint("your end_point");
String sqlScript = "@a := SELECT * FROM jdbc_test;\n"
+ "SELECT * FROM @a;";
// Required: Enable script mode.
Map<String, String> hints = new HashMap<>();
hints.put("odps.sql.submit.mode", "script");
Instance instance = SQLTask.run(odps, "your project_name", sqlScript, hints, null);
instance.waitForSuccess();
List<Record> recordList = SQLTask.getResult(instance);
for (Record record : recordList) {
System.out.println(record.get(0));
System.out.println(record.get(1));
}
}
}import os
from odps import ODPS
# Your Alibaba Cloud AccessKey pair grants full access to your account and carries high risks.
# We strongly recommend that you create and use a RAM user for API calls and daily operations.
# To create a RAM user, log on to the RAM console.
# This example shows how to use environment variables to store your credentials.
# For security, never hard-code your AccessKey pair into your code.
o = ODPS(
os.environ["ALIBABA_CLOUD_ACCESS_KEY_ID"],
os.environ["ALIBABA_CLOUD_ACCESS_KEY_SECRET"],
"your project_name",
"your end_point"
)
sql_script = """
@a := SELECT * FROM jdbc_test;
SELECT * FROM @a;
"""
# Required: Enable script mode.
hints = {"odps.sql.submit.mode", "script"}
instance = o.execute_sql(sql_script, hints=hints)
with instance.open_reader() as reader:
for rec in reader:
print(rec[0], rec[1])MaxCompute Studio
Antes de executar um script no MaxCompute Studio, conclua os seguintes pré-requisitos:
Após a execução do script, o MaxCompute Studio exibe o plano de execução como um único DAG, mesmo quando o script contém múltiplas instruções.