Mengupdate data tabel berpartisi menggunakan DML
Halaman ini menyediakan ringkasan dukungan bahasa pengolahan data (DML) untuk tabel berpartisi.
Untuk mengetahui informasi selengkapnya tentang DML, lihat:
Tabel yang digunakan dalam contoh
Definisi skema JSON berikut mewakili tabel yang digunakan dalam contoh di halaman ini.
mytable
: tabel berpartisi berdasarkan waktu penyerapan
[ {"name": "field1", "type": "INTEGER"}, {"name": "field2", "type": "STRING"} ]
mytable2
: tabel standar (tidak dipartisi)
[ {"name": "id", "type": "INTEGER"}, {"name": "ts", "type": "TIMESTAMP"} ]
mycolumntable
: tabel berpartisi
yang dipartisi menggunakan kolom TIMESTAMP
ts
[ {"name": "field1", "type": "INTEGER"}, {"name": "field2", "type": "STRING"} {"name": "field3", "type": "BOOLEAN"} {"name": "ts", "type": "TIMESTAMP"} ]
Pada contoh tempat COLUMN_ID muncul, ganti dengan nama kolom yang ingin Anda operasikan.
Menyisipkan data
Anda menggunakan pernyataan INSERT
DML untuk menambahkan baris ke tabel berpartisi.
Menyisipkan data ke tabel berpartisi berdasarkan waktu penyerapan
Saat menggunakan pernyataan DML untuk menambahkan baris ke tabel berpartisi berdasarkan waktu penyerapan,
Anda dapat menentukan partisi yang akan ditambahi baris. Anda mereferensikan
partisi menggunakan kolom semu _PARTITIONTIME
.
Misalnya, pernyataan INSERT
berikut menambahkan baris ke partisi
mytable
1 Mei 2017 — “2017-05-01”
.
INSERT INTO project_id.dataset.mytable (_PARTITIONTIME, field1, field2) SELECT TIMESTAMP("2017-05-01"), 1, "one"
Hanya stempel waktu yang sesuai dengan batas tanggal persis yang dapat digunakan. Misalnya, pernyataan DML berikut menampilkan error:
INSERT INTO project_id.dataset.mytable (_PARTITIONTIME, field1, field2) SELECT TIMESTAMP("2017-05-01 21:30:00"), 1, "one"
Menyisipkan data ke tabel berpartisi
Menyisipkan data ke tabel berpartisi menggunakan DML sama dengan memasukkan data ke dalam tabel yang tidak dipartisi.
Misalnya, pernyataan INSERT
berikut menambahkan baris ke tabel berpartisi
mycolumntable
dengan memilih data dari mytable2
(tabel yang tidak dipartisi).
INSERT INTO project_id.dataset.mycolumntable (ts, field1) SELECT ts, id FROM project_id.dataset.mytable2
Menghapus data
Anda menggunakan pernyataan DELETE
DML untuk menghapus baris dari tabel berpartisi.
Menghapus data di tabel berpartisi berdasarkan waktu penyerapan
Pernyataan DELETE
berikut akan menghapus semua baris dari partisi 1 Juni 2017
("2017-06-01"
) dari mytable
dengan field1
sama dengan 21
. Anda
mereferensikan partisi menggunakan kolom semu _PARTITIONTIME
.
DELETE project_id.dataset.mytable WHERE field1 = 21 AND _PARTITIONTIME = "2017-06-01"
Menghapus data dalam tabel berpartisi
Menghapus data dalam tabel berpartisi menggunakan DML sama dengan menghapus data dari tabel yang tidak dipartisi.
Misalnya, pernyataan DELETE
berikut akan menghapus semua baris dari partisi
1 Juni 2017 ("2017-06-01"
) dari mycolumntable
dengan field1
sama dengan 21
.
DELETE project_id.dataset.mycolumntable WHERE field1 = 21 AND DATE(ts) = "2017-06-01"
Menggunakan DML DELETE untuk menghapus partisi
Jika pernyataan DELETE
yang memenuhi syarat mencakup semua baris dalam partisi, BigQuery akan menghapus seluruh partisi. Penghapusan ini dilakukan
tanpa memindai byte atau menghabiskan slot. Contoh pernyataan DELETE
berikut mencakup seluruh partisi filter di kolom pseudo _PARTITIONDATE
:
DELETE mydataset.mytable WHERE _PARTITIONDATE IN ('2076-10-07', '2076-03-06');
Diskualifikasi umum
Kueri dengan karakteristik berikut mungkin tidak mendapatkan manfaat dari pengoptimalan:
- Cakupan partisi sebagian
- Referensi ke kolom non-partisi
- Data yang baru diserap melalui Storage Write API BigQuery atau API streaming lama
- Filter dengan subkueri atau predikat yang tidak didukung
Kelayakan untuk pengoptimalan dapat bervariasi bergantung pada jenis partisi, metadata penyimpanan yang mendasarinya, dan predikat filter. Sebagai praktik terbaik, lakukan uji coba untuk memverifikasi bahwa kueri menghasilkan 0 byte yang diproses.
Transaksi multi-pernyataan
Pengoptimalan ini berfungsi dalam transaksi multi-pernyataan. Contoh kueri berikut mengganti partisi dengan data dari tabel lain dalam satu transaksi, tanpa memindai partisi untuk
pernyataan DELETE
.
DECLARE REPLACE_DAY DATE; BEGIN TRANSACTION; -- find the partition which we want to replace SET REPLACE_DAY = (SELECT MAX(d) FROM mydataset.mytable_staging); -- delete the entire partition from mytable DELETE FROM mydataset.mytable WHERE part_col = REPLACE_DAY; -- insert the new data into the same partition in mytable INSERT INTO mydataset.mytable SELECT * FROM mydataset.mytable_staging WHERE part_col = REPLACE_DAY; COMMIT TRANSACTION;
Mengupdate data
Anda menggunakan pernyataan UPDATE
untuk mengupdate baris dalam tabel berpartisi.
Mengupdate data di tabel berpartisi berdasarkan waktu penyerapan
Pernyataan UPDATE
berikut akan memindahkan baris dari satu partisi ke partisi lainnya.
Baris dalam partisi 1 Mei 2017 (“2017-05-01”
) dari mytable
dengan field1
sama dengan 21
akan dipindahkan ke partisi 1 Juni 2017 (“2017-06-01”
).
UPDATE project_id.dataset.mytable SET _PARTITIONTIME = "2017-06-01" WHERE _PARTITIONTIME = "2017-05-01" AND field1 = 21
Mengupdate data dalam tabel berpartisi
Mengupdate data dalam tabel berpartisi menggunakan DML sama dengan mengupdate data
dari tabel yang tidak dipartisi. Misalnya, pernyataan UPDATE
berikut akan memindahkan baris dari satu partisi ke partisi lainnya. Baris dalam partisi
1 Mei 2017 (“2017-05-01”
) dari mytable
dengan field1
sama dengan 21
dipindahkan
ke partisi 1 Juni 2017 (“2017-06-01”
).
UPDATE project_id.dataset.mycolumntable SET ts = "2017-06-01" WHERE DATE(ts) = "2017-05-01" AND field1 = 21
DML dalam tabel berpartisi per jam, bulanan, dan tahunan
Anda dapat menggunakan pernyataan DML untuk memodifikasi tabel berpartisi per jam, bulanan, atau tahunan. Berikan rentang jam, bulan, atau tahun dari tanggal/stempel waktu/datetime yang relevan, seperti pada contoh berikut untuk tabel berpartisi bulanan:
bq query --nouse_legacy_sql 'DELETE FROM my_dataset.my_table WHERE TIMESTAMP_TRUNC(ts_column, MONTH) = "2020-01-01 00:00:00";'
Atau contoh lain untuk tabel berpartisi dengan kolom DATETIME
:
bq query --nouse_legacy_sql 'DELETE FROM my_dataset.my_table WHERE dt_column BETWEEN DATETIME("2020-01-01") AND DATETIME("2020-05-01");'
Menggunakan pernyataan MERGE
Anda menggunakan pernyataan MERGE
DML
untuk menggabungkan operasi INSERT
, UPDATE
, dan DELETE
untuk tabel berpartisi
menjadi satu pernyataan dan menjalankannya secara atomik.
Pruning partisi saat menggunakan pernyataan MERGE
Saat Anda menjalankan pernyataan MERGE
terhadap tabel berpartisi, Anda dapat membatasi
partisi mana yang dipindai dengan menyertakan kolom partisi dalam
filter subkueri, filter search_condition
, atau filter merge_condition
.
Pruning dapat terjadi saat memindai tabel sumber atau tabel target, atau keduanya.
Setiap contoh di bawah menjalankan kueri tabel berpartisi berdasarkan waktu penyerapan menggunakan
kolom semu _PARTITIONTIME
sebagai filter.
Menggunakan subkueri untuk memfilter data sumber
Dalam pernyataan MERGE
berikut, subkueri dalam klausa USING
memfilter
pada kolom semu _PARTITIONTIME
di tabel sumber.
MERGE dataset.target T USING (SELECT * FROM dataset.source WHERE _PARTITIONTIME = '2018-01-01') S ON T.COLUMN_ID = S.COLUMN_ID WHEN MATCHED THEN DELETE
Dengan melihat rencana eksekusi kueri, subkueri akan berjalan terlebih dahulu. Hanya baris di
partisi '2018-01-01'
dalam tabel sumber yang dipindai. Berikut adalah
tahap yang relevan dalam rencana kueri:
READ $10:name, $11:_PARTITIONTIME
FROM temp.source
WHERE equal($11, 1514764800.000000000)
Menggunakan filter di search_condition
dari when_clause
Jika search_condition
berisi filter, maka pengoptimal kueri akan mencoba
memangkas partisi. Misalnya, dalam pernyataan MERGE
berikut, setiap klausa WHEN
MATCHED
dan WHEN NOT MATCHED
berisi filter pada kolom semu
_PARTITIONTIME
.
MERGE dataset.target T USING dataset.source S ON T.COLUMN_ID = S.COLUMN_ID WHEN MATCHED AND T._PARTITIONTIME = '2018-01-01' THEN UPDATE SET COLUMN_ID = S.COLUMN_ID WHEN MATCHED AND T._PARTITIONTIME = '2018-01-02' THEN UPDATE SET COLUMN_ID = S.COLUMN_ID + 10 WHEN NOT MATCHED BY SOURCE AND T._PARTITIONTIME = '2018-01-03' THEN DELETE
Selama tahap join, hanya partisi berikut yang dipindai dalam tabel
target: '2018-01-01'
, '2018-01-02'
, dan '2018-01-03'
— yang merupakan
gabungan semua filter search_condition
.
Dari rencana eksekusi kueri:
READ
$1:COLUMN_ID, $2:_PARTITIONTIME, $3:$file_temp_id, $4:$row_temp_id
FROM temp.target
WHERE or(equal($2, 1514764800.000000000), equal($2, 1514851200.000000000), equal($2, 1514937600.000000000))
Namun, dalam contoh berikut, klausa WHEN NOT MATCHED BY SOURCE
tidak
memiliki ekspresi filter:
MERGE dataset.target T USING dataset.source S ON T.COLUMN_ID = S.COLUMN_ID WHEN MATCHED AND T._PARTITIONTIME = '2018-01-01' THEN UPDATE SET COLUMN_ID = S.COLUMN_ID WHEN NOT MATCHED BY SOURCE THEN UPDATE SET COLUMN_ID = COLUMN_ID + 1
Kueri ini harus memindai seluruh tabel target untuk menghitung klausa WHEN NOT MATCHED BY
SOURCE
. Akibatnya, tidak ada partisi yang dipangkas.
Menggunakan predikat salah (false) konstan dalam merge_condition
Jika Anda menggunakan klausa WHEN NOT MATCHED
dan WHEN NOT MATCHED BY SOURCE
secara bersamaan, maka BigQuery biasanya akan melakukan outer join penuh, yang tidak dapat dipangkas. Namun, jika kondisi penggabungan menggunakan predikat false yang konstan, BigQuery dapat menggunakan kondisi filter untuk pruning partisi. Untuk mengetahui informasi selengkapnya tentang penggunaan predikat false
yang onstan, lihat deskripsi klausa merge_condition
dalam dokumentasi
pernyataan MERGE
.
Contoh berikut hanya memindai partisi '2018-01-01'
dalam tabel target
dan sumber.
MERGE dataset.target T USING dataset.source S ON FALSE WHEN NOT MATCHED AND _PARTITIONTIME = '2018-01-01' THEN INSERT(COLUMN_ID) VALUES(COLUMN_ID) WHEN NOT MATCHED BY SOURCE AND _PARTITIONTIME = '2018-01-01' THEN DELETE
Menggunakan filter di merge_condition
Pengoptimal kueri akan mencoba menggunakan filter dalam merge_condition
untuk memangkas
partisi. Pengoptimal kueri mungkin dapat atau tidak dapat mendorong predikat
ke tahap pemindaian tabel, bergantung pada jenis gabungan.
Pada contoh berikut, merge_condition
digunakan sebagai predikat untuk menggabungkan
tabel sumber dan target. Pengoptimal kueri dapat mendorong predikat ini ke bawah
saat memindai kedua tabel. Akibatnya, kueri hanya memindai partisi '2018-01-01'
di tabel target dan sumber.
MERGE dataset.target T USING dataset.source S ON T.COLUMN_ID = S.COLUMN_ID AND T._PARTITIONTIME = '2018-01-01' AND S._PARTITIONTIME = '2018-01-01' WHEN MATCHED THEN UPDATE SET COLUMN_ID = NEW_VALUE
Pada contoh berikutnya, merge_condition
tidak berisi predikat untuk
tabel sumber, sehingga tidak ada pruning partisi yang dapat dilakukan pada tabel sumber. Pernyataan
tersebut berisi predikat untuk tabel target, tetapi pernyataan tersebut menggunakan
klausa WHEN NOT MATCHED BY SOURCE
, bukan klausa WHEN MATCHED
. Itu
berarti kueri harus memindai seluruh tabel target untuk menemukan baris yang
tidak cocok.
MERGE dataset.target T USING dataset.source S ON T.COLUMN_ID = S.COLUMN_ID AND T._PARTITIONTIME = '2018-01-01' WHEN NOT MATCHED BY SOURCE THEN UPDATE SET COLUMN_ID = NEW_VALUE
Batasan
Untuk mengetahui informasi tentang batasan DML, lihat Batasan di halaman Referensi DML.
Kuota
Untuk mengetahui informasi tentang informasi kuota DML, lihat Pernyataan DML di halaman Kuota dan batas.
Harga
Untuk mengetahui informasi tentang harga DML, lihat Harga DML untuk tabel berpartisi.
Keamanan tabel
Untuk mengontrol akses ke tabel di BigQuery, lihat Pengantar kontrol akses tabel.
Langkah selanjutnya
- Pelajari cara membuat tabel berpartisi
- Pelajari cara menjalankan kueri pada tabel berpartisi
- Dapatkan pengantar DML
- Pelajari cara menulis pernyataan DML menggunakan sintaksis DML