Le mode script compile et soumet plusieurs instructions SQL sous la forme d'une unité unique. Il génère un seul plan d'exécution, mis en file d'attente une seule fois et exécuté au sein d'un seul job. Cette approche est idéale pour les pipelines de données ETL, le traitement par lots périodique et l'orchestration de requêtes nécessitant plusieurs instructions coordonnées. Elle prend en charge le mode normal (exécution atomique, par défaut) et le mode d'exécution étape par étape (exécution séquentielle).
Le mode script ne prend pas en charge l'estimation des coûts. Les frais réels sont calculés sur la base de vos détails de facturation.
Un seul script peut référencer jusqu'à 10 000 tables. Chaque référence est comptabilisée individuellement, y compris les références répétées à la même table et les tables référencées dans les définitions de vues.
Si la préparation des données pour plusieurs sources se termine à des moments très différents (par exemple, l'une à 01:00 et l'autre à 07:00), n'utilisez pas de variable de table pour les combiner en un seul job SQL en mode script.
Cas d'utilisation
Réécriture d'instructions complexes : décomposez les sous-requêtes profondément imbriquées en une séquence d'affectations de variables de table lisibles.
Création de pipelines multi-instructions : combinez des instructions logiquement liées en un seul job afin de réduire la mise en file d'attente et la surcharge de planification. En mode normal, toutes les instructions s'exécutent de manière atomique. En mode d'exécution étape par étape, les instructions s'exécutent de façon séquentielle, ce qui convient parfaitement aux scénarios de lecture après écriture ou aux migrations depuis d'autres plateformes. Pour plus d'informations, consultez Modes d'exécution.
Syntaxe
Types d'instructions : le mode script prend en charge les instructions SET, certaines instructions DDL et les instructions DML. Les instructions affichant des résultats, telles que DESC et SHOW, ne sont pas prises en charge.
Ordre des instructions : un script doit respecter un ordre fixe
SET→DDL→DML. Chaque section peut contenir zéro ou plusieurs instructions, mais vous ne pouvez pas entremêler des instructions provenant de sections différentes.
-- 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;]
[...]
Modes d'exécution
Le mode script prend en charge deux modes d'exécution.
|**Comportement**
|
**Mode normal (par défaut)**
|
**Mode d'exécution étape par étape**
| | --- | --- | --- | |
Comment l'activer
|
Par défaut. Aucune configuration n'est nécessaire.
|
Ajoutez `SET odps.sql.step.script.mode=true;` à la section SET.
| |
Compilation
|
Toutes les instructions DML sont compilées en un seul plan d'exécution.
|
Chaque instruction DML est compilée en un plan d'exécution distinct. Remarque : les scripts très complexes, tels que ceux comportant des milliers de lignes ou de nombreuses opérations, peuvent dépasser les limites de mémoire de compilation.
| |
Exécution
|
Toutes les instructions sont exécutées de manière atomique sous la forme d'un seul job qui démarre uniquement lorsque toutes les données d'entrée sont prêtes. Si une instruction échoue, l'intégralité du script échoue et toutes les opérations sont annulées.
|
Les instructions DML sont exécutées de manière séquentielle. Si une instruction échoue, les instructions précédemment exécutées ne sont pas annulées et vous devez relancer le script depuis le début. Nous vous recommandons de diviser les scripts volumineux en scripts plus petits.
| |
Lecture après écriture
|
Non pris en charge. Une erreur se produit si vous écrivez dans une table puis la lisez dans le même script.
|
Pris en charge, mais pas pour les tables transactionnelles ou partitionnées.
| |
Table temporaire
|
Non pris en charge.
|
Pris en charge.
|
Syntaxe DDL
Créer une table temporaire
Les tables temporaires mettent en cache les résultats intermédiaires pour les réutiliser au sein du même script. Comme elles reposent sur un modèle de lecture après écriture, elles sont prises en charge uniquement en mode d'exécution étape par étape.
Syntaxe
CREATE TEMPORARY TABLE <table_name> (
<col_name> <data_type>, ...
)
[LIFECYCLE <days>]
[AS <select_statement>];
Paramètres
|**Paramètre**
|
**Description**
| | --- | --- | |
`table_name`
|
Accessible uniquement au sein du script actuel.
| |
`LIFECYCLE
|
Facultatif. Nombre de jours pendant lesquels la table est conservée avant sa suppression automatique. Valeur par défaut : 1.
| |
`AS
|
Facultatif. Remplit la table avec les données issues d'une instruction SELECT lors de sa création.
|
Limitations
Les tables temporaires nécessitent le mode d'exécution étape par étape. Ajoutez
SET odps.sql.step.script.mode=true;à la section SET de votre script.Une table temporaire est accessible uniquement au sein du script où elle a été créée.
Les tables temporaires ne peuvent pas être des tables partitionnées ou transactionnelles.
Pour supprimer explicitement une table temporaire, l'instruction
DROP TABLEdoit être la dernière instruction du script.Évitez de créer plus de 20 tables temporaires dans un seul script.
Créer une table standard
Le mode script prend en charge la création de tables standards. Pour obtenir des détails sur la syntaxe, consultez CREATE TABLE.
Syntaxe DML et DQL
Limitations des instructions
Instructions affichant des résultats : un script ne peut contenir qu'une seule instruction produisant un affichage à l'écran, telle qu'une instruction
SELECTautonome. L'inclusion de plusieurs instructions de ce type provoque une erreur. Évitez d'utiliser ces types d'instructions dans les scripts.CREATE TABLE AS : vous ne pouvez utiliser cette instruction qu'une seule fois par script et elle doit être la dernière instruction exécutable. Nous vous recommandons de créer d'abord la table, puis d'y insérer les données.
Modes d'écriture mixtes : vous ne pouvez pas utiliser à la fois OVERWRITE et INTO sur la même table au sein du même script. Les opérations DML sur les tables transactionnelles et les tables standards ne peuvent pas être mélangées.
Lecture après écriture : en mode normal, écrire dans une table puis la lire dans le même script provoque une erreur. Pour résoudre ce problème, utilisez soit une variable de table, soit passez au mode d'exécution étape par étape. Le mode d'exécution étape par étape prend en charge l'opération de lecture après écriture, mais pas pour les tables transactionnelles ou partitionnées. Pour un exemple détaillé, consultez Exemple 3 : Lecture après écriture en mode normal.
Variables
Syntaxe
-- Declare a variable by using @. Supported types include TABLE and any MaxCompute data type.
@var1 <type>
-- Assign a value by using :=
@var1 := <select_statement>
Remarques d'utilisation
-
Vous ne pouvez pas affecter une variable de type table à une variable dont le type de données est spécifié. Par exemple, la syntaxe suivante n'est pas autorisée :
@a TABLE (name STRING); @a := SELECT 'tom'; @b STRING; @b := SELECT * FROM @a; -
Les variables peuvent stocker des valeurs constantes. Vous pouvez convertir la valeur d'une variable en scalaire en utilisant
SELECT * FROM @var. Une constante peut également être stockée dans une table à ligne unique, comme illustré dans l'exemple suivant. Pour plus d'informations sur la syntaxe de conversion, consultez 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;
Instructions IF
Utilisez les instructions IF pour contrôler le flux d'exécution en fonction de conditions.
Syntaxe
-- Single branch
IF (condition) BEGIN
statements
END
-- Multi-branch
IF (condition) BEGIN
statements
END ELSE IF (condition2) BEGIN
statements
END ELSE BEGIN
statements
END
Remarques d'utilisation
Si une branche contient une seule instruction, les mots-clés
BEGINetENDsont facultatifs, à l'instar de{ }en Java.Les instructions DDL telles que
CREATE TABLE,ALTER TABLEetTRUNCATE TABLEne sont pas prises en charge au sein d'une branche IF.-
La condition prend en charge deux types :
Expression booléenne : la branche est déterminée au moment de la compilation.
Sous-requête scalaire booléenne : la branche est déterminée au moment de l'exécution. MaxCompute peut soumettre plusieurs jobs.
Exemple 1 : dans une instruction IF, la condition est une expression de type BOOLEAN. Ce type d'instruction IF ELSE permet de déterminer quelle branche exécuter au moment de la compilation, comme illustré dans l'exemple suivant :
@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;
Exemple 2 : la condition de l'instruction IF est une sous-requête scalaire booléenne. Pour ce type d'instruction IF ELSE, la branche d'exécution est déterminée au moment de l'exécution, ce qui nécessite que MaxCompute soumette plusieurs 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;
Exemples
Exemple 1 : Exemple de base
Le script suivant joint et fusionne les données de trois tables sources, puis insère les résultats dans deux tables de destination. Toutes les instructions sont compilées en un seul DAG et exécutées de manière atomique.
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;
Exemple 2 : Lecture après écriture en mode étape par étape
Le script suivant active le mode d'exécution étape par étape pour effectuer une opération de lecture après écriture dans le même 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;
Exemple 3 : Lecture après écriture en mode normal
En mode normal, écrire dans une table puis la lire dans le même script provoque une erreur. Cet exemple illustre l'erreur et deux solutions possibles.
Préparation des données
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);
Exemple d'erreur (lecture après écriture en mode 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;
Solution 1 : Activer le mode d'exécution étape par étape
SET odps.sql.step.script.mode=true;
INSERT OVERWRITE TABLE src2 SELECT * FROM src WHERE key > 0;
@a := SELECT * FROM src2;
SELECT * FROM @a;
Solution 2 : Réécrire le SQL pour utiliser une variable de table
@a := SELECT * FROM src WHERE key > 0;
INSERT OVERWRITE TABLE src2 SELECT * FROM @a;
SELECT * FROM @a;
Exemple 4 : Créer et supprimer une table temporaire
Le script suivant crée une table temporaire pour mettre en cache les résultats intermédiaires d'une jointure, la lit deux fois, puis la supprime.
-- 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;
Soumettre des scripts
Le mode script est pris en charge dans MaxCompute Studio, le client MaxCompute (odpscmd), DataWorks, ainsi que dans les SDK Java et Python.
Client MaxCompute (odpscmd)
Utilisez odpscmd v0.27 ou une version ultérieure. Après avoir installé le client MaxCompute, soumettez un script à l'aide de l'option -s :
Créez un fichier de script, tel que myscript.sql. Ensuite, exécutez la commande suivante depuis votre interface de ligne de commande pour lancer odpscmd. Pour plus d'informations sur l'exécution du client MaxCompute depuis la ligne de commande, consultez Run the MaxCompute client.
..\bin>odpscmd -s myscript.sql
Le mode script et les variables de table ne sont pas pris en charge dans le shell interactif odpscmd. L'option -s est une option de ligne de commande pour odpscmd, similaire à -f et -e. Il ne s'agit pas d'une commande dans l'environnement interactif.
DataWorks
Dans DataWorks, utilisez un nœud ODPS Script pour écrire et exécuter des scripts.
Dans le coin supérieur gauche, cliquez sur + Create > Create Node. Dans la catégorie MaxCompute, sélectionnez ODPS Script.
Après avoir écrit le script, cliquez sur l'icône Run de la barre d'outils pour l'exécuter. Le journal de sortie inclut une URL Logview permettant de consulter le plan d'exécution et les résultats.
SDK
Exécutez directement des scripts SQL avec le SDK Java ou le SDK Python. Pour plus d'informations, consultez la documentation du Java SDK et du 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
Avant d'exécuter un script dans MaxCompute Studio, remplissez les conditions préalables suivantes :
Après avoir exécuté le script, MaxCompute Studio affiche le plan d'exécution sous la forme d'un seul DAG, même si le script contient plusieurs instructions.