Script mode (Script Mode SQL) memungkinkan Anda mengompilasi dan mengirimkan beberapa pernyataan SQL sebagai satu kesatuan. Proses ini menghasilkan satu rencana eksekusi, mengantri skrip sekali, dan menjalankan semua pernyataan dalam satu pekerjaan. Pendekatan ini ideal untuk pipa data ETL, pemrosesan batch periodik, dan skenario orkestrasi kueri yang memerlukan beberapa pernyataan terkoordinasi. Script mode mendukung dua mode eksekusi: mode normal, yang secara default menyediakan eksekusi atomik, dan mode eksekusi langkah demi langkah, yang menjalankan pernyataan secara serial.
-
Script mode tidak mendukung estimasi biaya. Biaya aktual didasarkan pada detail penagihan Anda.
-
Satu skrip dapat mereferensikan hingga 10.000 tabel. Setiap referensi dihitung secara individual, termasuk referensi berulang ke tabel yang sama dan tabel yang direferensikan dalam definisi tampilan.
-
Jika persiapan data untuk beberapa sumber data selesai pada waktu yang sangat berbeda—misalnya, satu pukul 01.00 dan yang lain pukul 07.00—jangan gunakan variabel tabel untuk menggabungkannya menjadi satu pekerjaan Script Mode SQL.
Kasus penggunaan
-
Tulis ulang pernyataan kompleks: Pecah subkueri bersarang menjadi rangkaian penugasan variabel tabel yang mudah dibaca.
-
Buat pipeline multi-pernyataan: Gabungkan pernyataan yang saling terkait secara logis menjadi satu pekerjaan untuk mengurangi overhead antrian dan penjadwalan. Dalam mode normal, semua pernyataan dieksekusi secara atomik. Dalam mode eksekusi langkah demi langkah, pernyataan dijalankan secara serial, yang ideal untuk skenario read-after-write atau migrasi dari platform lain. Untuk informasi lebih lanjut, lihat Mode eksekusi.
Sintaksis
-
Jenis pernyataan: Script mode mendukung pernyataan SET, beberapa pernyataan DDL, dan pernyataan DML. Pernyataan yang menampilkan hasil seperti DESC dan SHOW tidak didukung.
-
Urutan pernyataan: Skrip harus mengikuti urutan tetap
SET→DDL→DML. Setiap bagian dapat berisi nol atau lebih pernyataan, tetapi Anda tidak boleh mencampur pernyataan dari bagian yang berbeda.
-- 1. SET
SET odps.sql.type.system.odps2=true;
[SET odps.stage.reducer.num=xxx;]
[SET odps.sql.step.script.mode=true;] -- Aktifkan mode eksekusi langkah demi langkah
[...]
-- 2. DDL
CREATE TABLE table1 xxx;
[CREATE TEMPORARY TABLE table2 xxx;] -- Buat tabel temporary
[...]
-- 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;]
[...]
Mode eksekusi
Script mode mendukung dua mode eksekusi.
|
Perilaku |
Normal Mode (default) |
Mode eksekusi langkah demi langkah |
|
Cara mengaktifkan |
Default. Tidak diperlukan konfigurasi. |
Tambahkan |
|
Kompilasi |
Semua pernyataan DML dikompilasi menjadi satu rencana eksekusi. |
Setiap pernyataan DML dikompilasi menjadi rencana eksekusi terpisah. Catatan: Skrip yang sangat kompleks, seperti yang memiliki ribuan baris atau banyak operasi, mungkin melebihi batas memori kompilasi. |
|
Eksekusi |
Semua pernyataan dieksekusi secara atomik sebagai satu pekerjaan yang hanya dimulai setelah semua data masukan siap. Jika ada pernyataan yang gagal, seluruh skrip gagal dan semua operasi di-rollback. |
Pernyataan DML dieksekusi secara serial. Jika suatu pernyataan gagal, pernyataan yang telah dieksekusi sebelumnya tidak di-rollback, dan Anda harus menjalankan ulang skrip dari awal. Kami menyarankan agar Anda membagi skrip besar menjadi skrip yang lebih kecil. |
|
Read-after-write |
Tidak didukung. Terjadi error jika Anda menulis ke lalu membaca dari tabel yang sama dalam satu skrip. |
Didukung, tetapi tidak untuk tabel transaksional atau tabel partisi. |
|
Tabel temporary |
Tidak didukung. |
Didukung. |
Sintaksis DDL
Buat tabel temporary
Dalam script mode, Anda dapat membuat tabel temporary untuk menyimpan cache hasil antara agar dapat digunakan kembali dalam skrip yang sama. Operasi ini memerlukan pola read-after-write dan hanya didukung dalam mode eksekusi langkah demi langkah.
Sintaksis
CREATE TEMPORARY TABLE <table_name> (
<col_name> <data_type>, ...
)
[LIFECYCLE <days>]
[AS <select_statement>];
Parameter
|
Parameter |
Deskripsi |
|
|
Hanya dapat diakses dalam skrip saat ini. |
|
|
Opsional. Jumlah hari untuk menyimpan tabel sebelum dihapus secara otomatis. Default: 1. |
|
|
Opsional. Mengisi tabel dengan data dari pernyataan SELECT saat dibuat. |
Batasan
-
Tabel temporary memerlukan mode eksekusi langkah demi langkah. Tambahkan
SET odps.sql.step.script.mode=true;ke bagian SET skrip Anda. -
Tabel temporary hanya dapat diakses dalam skrip tempat tabel tersebut dibuat.
-
Tabel temporary tidak dapat berupa tabel partisi atau tabel transaksional.
-
Untuk menghapus eksplisit tabel temporary, pernyataan
DROP TABLEharus menjadi pernyataan terakhir dalam skrip. -
Hindari membuat lebih dari 20 tabel temporary dalam satu skrip.
Buat tabel standar
Script mode mendukung pembuatan tabel standar. Untuk detail sintaksis, lihat CREATE TABLE.
Sintaksis DML dan DQL
Batasan pernyataan
-
Pernyataan yang menampilkan hasil: Skrip hanya boleh berisi satu pernyataan yang menghasilkan output layar, seperti pernyataan
SELECTmandiri. Memasukkan lebih dari satu akan menyebabkan error. Hindari penggunaan jenis pernyataan ini dalam skrip. -
CREATE TABLE AS: Anda hanya dapat menggunakan pernyataan ini sekali per skrip, dan harus menjadi pernyataan eksekusi terakhir. Kami menyarankan membuat tabel terlebih dahulu lalu memasukkan data.
-
Mode tulis campuran: Anda tidak dapat menggunakan OVERWRITE dan INTO pada tabel yang sama dalam satu skrip. Operasi DML pada tabel transaksional dan tabel standar tidak boleh dicampur.
-
read-after-write: Dalam mode normal, menulis ke lalu membaca dari tabel dalam skrip yang sama menyebabkan error. Untuk mengatasi masalah ini, gunakan variabel tabel atau beralih ke mode eksekusi langkah demi langkah. Mode eksekusi langkah demi langkah mendukung operasi read-after-write, tetapi tidak untuk tabel transaksional atau tabel partisi. Untuk contoh lengkap, lihat Contoh 3: Read-after-write dalam mode normal.
Variabel
Sintaksis
-- Deklarasikan variabel dengan menggunakan @. Jenis yang didukung meliputi TABLE dan semua tipe data MaxCompute.
@var1 <type>
-- Tetapkan nilai dengan menggunakan :=
@var1 := <select_statement>
Catatan penggunaan
-
Anda tidak dapat menetapkan variabel bertipe tabel ke variabel dengan tipe data tertentu. Misalnya, sintaksis berikut tidak diizinkan:
@a TABLE (name STRING); @a := SELECT 'tom'; @b STRING; @b := SELECT * FROM @a; -
Variabel dapat menyimpan nilai konstan. Anda dapat mengonversi nilai variabel menjadi skalar dengan menggunakan
SELECT * FROM @var. Konstanta juga dapat disimpan dalam tabel satu baris, seperti pada contoh berikut. Untuk informasi lebih lanjut tentang sintaksis konversi, lihat subkueri.@a := SELECT 10; -- Tetapkan konstanta 10 @b := SELECT key, value + (SELECT * FROM @a) FROM t2; -- Gunakan @a sebagai skalar SELECT * FROM @b;
Pernyataan IF
Dalam script mode, gunakan pernyataan IF untuk mengontrol alur eksekusi berdasarkan kondisi.
Sintaksis
-- Cabang tunggal
IF (condition) BEGIN
statements
END
-- Cabang ganda
IF (condition) BEGIN
statements
END ELSE IF (condition2) BEGIN
statements
END ELSE BEGIN
statements
END
Catatan penggunaan
-
Jika cabang hanya berisi satu pernyataan, kata kunci
BEGINdanENDbersifat opsional, mirip dengan{ }di Java. -
Pernyataan DDL seperti
CREATE TABLE,ALTER TABLE, danTRUNCATE TABLEtidak didukung dalam cabang IF. -
Kondisi mendukung dua jenis:
-
Ekspresi Boolean: Cabang ditentukan pada waktu kompilasi.
-
Subkueri skalar Boolean: Cabang ditentukan pada waktu eksekusi. MaxCompute mungkin mengirimkan beberapa pekerjaan.
-
Contoh 1: Dalam pernyataan IF, kondisinya adalah ekspresi bertipe BOOLEAN. Jenis pernyataan IF ELSE ini dapat menentukan cabang mana yang dieksekusi pada waktu kompilasi, seperti pada contoh berikut:
@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;
Contoh 2: Kondisi dalam pernyataan IF adalah subkueri skalar Boolean. Untuk jenis pernyataan IF ELSE ini, cabang eksekusi ditentukan pada waktu eksekusi, yang mengharuskan MaxCompute mengirimkan beberapa pekerjaan:
@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;
Contoh
Contoh 1: Contoh dasar
Skrip berikut melakukan join dan union data dari tiga tabel sumber, lalu memasukkan hasilnya ke dua tabel tujuan. Semua pernyataan dikompilasi menjadi satu DAG dan dieksekusi secara atomik.
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;
Contoh 2: Read-after-write dalam mode langkah demi langkah
Skrip berikut mengaktifkan mode eksekusi langkah demi langkah untuk melakukan operasi read-after-write dalam skrip yang sama.
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;
Contoh 3: Read-after-write dalam mode normal
Dalam mode normal, menulis ke lalu membaca dari tabel yang sama dalam skrip menyebabkan error. Contoh ini menunjukkan error tersebut dan dua solusi yang mungkin.
Persiapan data
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);
Contoh error (read-after-write dalam mode normal)
INSERT OVERWRITE TABLE src2 SELECT * FROM src WHERE key > 0;
@a := SELECT * FROM src2; -- Error: src2 ditulis lalu dibaca dalam skrip yang sama.
SELECT * FROM @a;
Solusi 1: Aktifkan mode eksekusi langkah demi langkah
SET odps.sql.step.script.mode=true;
INSERT OVERWRITE TABLE src2 SELECT * FROM src WHERE key > 0;
@a := SELECT * FROM src2;
SELECT * FROM @a;
Solusi 2: Tulis ulang SQL untuk menggunakan variabel tabel
@a := SELECT * FROM src WHERE key > 0;
INSERT OVERWRITE TABLE src2 SELECT * FROM @a;
SELECT * FROM @a;
Contoh 4: Buat dan hapus tabel temporary
Skrip berikut membuat tabel temporary untuk menyimpan cache hasil antara dari operasi JOIN, membacanya dua kali, lalu menghapusnya.
-- Aktifkan mode eksekusi langkah demi langkah (diperlukan untuk tabel temporary).
SET odps.sql.step.script.mode=true;
DROP TABLE IF EXISTS foo_t1;
CREATE TABLE foo_t1(a BIGINT, b BIGINT);
-- Buat tabel temporary dengan menggunakan 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;
-- Hapus tabel temporary (harus menjadi pernyataan terakhir dalam skrip).
DROP TABLE t;
Kirimkan skrip
Script mode didukung di MaxCompute Studio, klien MaxCompute (odpscmd), DataWorks, serta SDK Java dan Python.
Klien MaxCompute (odpscmd)
Gunakan odpscmd v0.27 atau yang lebih baru. Setelah Anda menginstal klien MaxCompute, kirimkan skrip menggunakan flag -s:
Buat file skrip, seperti myscript.sql. Kemudian, jalankan perintah berikut dari antarmuka baris perintah Anda untuk menjalankan odpscmd. Untuk informasi lebih lanjut tentang cara menjalankan klien MaxCompute dari baris perintah, lihat Jalankan klien MaxCompute.
..\bin>odpscmd -s myscript.sql
Script mode dan variabel tabel tidak didukung di shell interaktif odpscmd. Flag -s adalah opsi baris perintah untuk odpscmd, mirip dengan -f dan -e. Ini bukan perintah di lingkungan interaktif.
DataWorks
Di DataWorks, gunakan node ODPS Script untuk menulis dan menjalankan skrip. Anda kemudian dapat melihat rencana eksekusi dan hasilnya menggunakan URL Logview yang disediakan di output.
Di pojok kiri atas, klik + Create > Create Node. Di bawah kategori MaxCompute, pilih ODPS Script.
Setelah Anda menulis skrip, klik ikon Run pada bilah alat untuk mengeksekusinya. Log output menyediakan URL Logview untuk memeriksa rencana eksekusi dan hasil akhir.
SDK
Anda dapat menjalankan skrip SQL langsung menggunakan SDK Java atau SDK Python. Untuk informasi lebih lanjut, lihat pengenalan SDK Java dan SDK Python.
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 {
// Pasangan Kunci Akses Alibaba Cloud Anda memberikan akses penuh ke akun Anda dan membawa risiko tinggi.
// Kami sangat menyarankan agar Anda membuat dan menggunakan Pengguna RAM untuk panggilan API dan operasi harian.
// Untuk membuat Pengguna RAM, login ke konsol RAM.
// Contoh ini menunjukkan cara menggunakan Variabel lingkungan untuk menyimpan kredensial Anda.
// Untuk keamanan, jangan pernah menyematkan Pasangan Kunci Akses Anda secara langsung ke dalam kode.
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;";
// Wajib: Aktifkan 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
# Pasangan Kunci Akses Alibaba Cloud Anda memberikan akses penuh ke akun Anda dan membawa risiko tinggi.
# Kami sangat menyarankan agar Anda membuat dan menggunakan Pengguna RAM untuk panggilan API dan operasi harian.
# Untuk membuat Pengguna RAM, login ke konsol RAM.
# Contoh ini menunjukkan cara menggunakan Variabel lingkungan untuk menyimpan kredensial Anda.
# Untuk keamanan, jangan pernah menyematkan Pasangan Kunci Akses Anda secara langsung ke dalam kode.
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;
"""
# Wajib: Aktifkan 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
Sebelum menjalankan skrip di MaxCompute Studio, lengkapi prasyarat berikut:
Setelah Anda mengompilasi dan menjalankan skrip, MaxCompute Studio menampilkan rencana eksekusi. Meskipun skrip berisi beberapa pernyataan, rencana tersebut dirender sebagai satu DAG.