Pengantar
Halaman ini menjelaskan detail tentang operator yang digunakan dalam Rencana eksekusi kueri Spanner. Untuk mempelajari cara mengambil rencana eksekusi untuk kueri tertentu menggunakan konsol Google Cloud, lihat Memahami cara Spanner menjalankan kueri.
Kueri dan rencana eksekusi di halaman ini didasarkan pada skema database berikut:
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
BirthDate DATE
) PRIMARY KEY(SingerId);
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
CREATE TABLE Albums (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
AlbumTitle STRING(MAX),
MarketingBudget INT64
) PRIMARY KEY(SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);
CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget);
CREATE TABLE Songs (
SingerId INT64 NOT NULL,
AlbumId INT64 NOT NULL,
TrackId INT64 NOT NULL,
SongName STRING(MAX),
Duration INT64,
SongGenre STRING(25)
) PRIMARY KEY(SingerId, AlbumId, TrackId),
INTERLEAVE IN PARENT Albums ON DELETE CASCADE;
CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC), INTERLEAVE IN Albums;
CREATE INDEX SongsBySongName ON Songs(SongName);
CREATE TABLE Concerts (
VenueId INT64 NOT NULL,
SingerId INT64 NOT NULL,
ConcertDate DATE NOT NULL,
BeginTime TIMESTAMP,
EndTime TIMESTAMP,
TicketPrices ARRAY<INT64>
) PRIMARY KEY(VenueId, SingerId, ConcertDate);
Anda dapat menggunakan pernyataan Bahasa Manipulasi Data (DML) berikut untuk menambahkan data ke tabel ini:
INSERT INTO Singers (SingerId, FirstName, LastName, BirthDate)
VALUES (1, "Marc", "Richards", "1970-09-03"),
(2, "Catalina", "Smith", "1990-08-17"),
(3, "Alice", "Trentor", "1991-10-02"),
(4, "Lea", "Martin", "1991-11-09"),
(5, "David", "Lomond", "1977-01-29");
INSERT INTO Albums (SingerId, AlbumId, AlbumTitle)
VALUES (1, 1, "Total Junk"),
(1, 2, "Go, Go, Go"),
(2, 1, "Green"),
(2, 2, "Forever Hold Your Peace"),
(2, 3, "Terrified"),
(3, 1, "Nothing To Do With Me"),
(4, 1, "Play");
INSERT INTO Songs (SingerId, AlbumId, TrackId, SongName, Duration, SongGenre)
VALUES (2, 1, 1, "Let's Get Back Together", 182, "COUNTRY"),
(2, 1, 2, "Starting Again", 156, "ROCK"),
(2, 1, 3, "I Knew You Were Magic", 294, "BLUES"),
(2, 1, 4, "42", 185, "CLASSICAL"),
(2, 1, 5, "Blue", 238, "BLUES"),
(2, 1, 6, "Nothing Is The Same", 303, "BLUES"),
(2, 1, 7, "The Second Time", 255, "ROCK"),
(2, 3, 1, "Fight Story", 194, "ROCK"),
(3, 1, 1, "Not About The Guitar", 278, "BLUES");
Operator daun
Operator daun adalah operator yang tidak memiliki turunan. Jenis operator daun adalah:
Penghapusan susunan bertingkat array
Operator array unnest meratakan array input menjadi baris elemen. Setiap baris yang dihasilkan berisi hingga dua kolom: nilai aktual dari array, dan secara opsional posisi berbasis nol dalam array.
Misalnya, menggunakan kueri ini:
SELECT a, b FROM UNNEST([1,2,3]) a WITH OFFSET b;
Kueri meratakan array [1,2,3]
di kolom a
dan menampilkan posisi array
di kolom b
.
Berikut adalah hasilnya:
a | b |
---|---|
1 | 0 |
2 | 1 |
3 | 2 |
Berikut adalah rencana eksekusi:
Membuat hubungan
Operator generate relation menampilkan nol baris atau lebih.
Hubungan unit
Hubungan unit menampilkan satu baris. Ini adalah kasus khusus dari operator generate relation.
Misalnya, menggunakan kueri ini:
SELECT 1 + 2 AS Result;
Hasilnya adalah:
Hasil |
---|
3 |
Berikut adalah rencana eksekusi:
Relasi kosong
Hubungan kosong tidak menampilkan baris apa pun. Ini adalah kasus khusus dari operator generate relation.
Misalnya, menggunakan kueri ini:
SELECT *
FROM albums
LIMIT 0
Hasilnya adalah:
Tidak ada hasil
Berikut adalah rencana eksekusi:
Pemindaian
Operator pindai menampilkan baris dengan memindai sumber baris. Berikut adalah jenis operator pemindaian:
- Pemindaian tabel: Pemindaian terjadi pada tabel.
- Pemindaian indeks: Pemindaian terjadi pada indeks.
- Pemindaian batch: Pemindaian terjadi pada tabel perantara yang dibuat oleh operator relasional lainnya (misalnya, tabel yang dibuat oleh cross apply terdistribusi).
Jika memungkinkan, Spanner akan menerapkan predikat pada kunci sebagai bagian dari
pemindaian. Pemindaian dijalankan secara lebih efisien saat predikat diterapkan karena
pemindaian tidak perlu membaca seluruh tabel atau indeks. Predikat muncul dalam
rencana eksekusi dalam bentuk KeyPredicate: column=value
.
Dalam kasus terburuk, kueri mungkin perlu mencari semua baris dalam tabel. Situasi
ini menyebabkan pemindaian penuh, dan muncul dalam rencana eksekusi sebagai full scan:
true
.
Misalnya, menggunakan kueri ini:
SELECT s.lastname
FROM singers@{FORCE_INDEX=SingersByFirstLastName} as s
WHERE s.firstname = 'Catalina';
Berikut adalah hasilnya:
LastName |
---|
Smith |
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi, operator union terdistribusi
tingkat teratas mengirim sub-rencana ke server jarak jauh. Setiap sub-rencana memiliki operator serialisasi
hasil dan operator pemindaian indeks. Predikat
Key Predicate: FirstName = 'Catalina'
membatasi pemindaian ke baris dalam indeks
SingersByFirstLastname
yang memiliki FirstName
sama dengan Catalina
. Output
pemindaian indeks ditampilkan ke operator hasil serialisasi.
Operator uner
Operator unary adalah operator yang memiliki satu turunan relasional.
Operator berikut adalah operator uner:
- Gabungan
- Menerapkan mutasi
- Membuat batch
- Komputasi
- Struct komputasi
- Filter
- Pemindaian filter
- Batas
- Gabungan pemisahan lokal
- Pemberian ID Acak
- Melakukan serialisasi hasil
- Urutkan
- TVF
- Input union
Agregat
Operator agregat menerapkan pernyataan SQL GROUP BY
dan fungsi
agregat (seperti COUNT
). Input untuk operator agregat secara logis
dipartisi menjadi grup yang diatur pada kolom kunci (atau menjadi satu grup jika
GROUP BY
tidak ada). Untuk setiap grup, nol atau beberapa agregat
dihitung.
Misalnya, menggunakan kueri ini:
SELECT s.singerid,
Avg(s.duration) AS average,
Count(*) AS count
FROM songs AS s
GROUP BY singerid;
Kueri mengelompokkan menurut SingerId
dan melakukan agregasi AVG
dan agregasi COUNT
.
Berikut adalah hasilnya:
SingerId | rata-rata | count |
---|---|---|
3 | 278 | 1 |
2 | 225,875 | 8 |
Berikut adalah rencana eksekusi:
Operator agregat dapat berupa berbasis streaming atau berbasis hash. Rencana eksekusi sebelumnya
menunjukkan agregat berbasis streaming. Agregat berbasis aliran dibaca dari
input yang telah diurutkan sebelumnya (jika GROUP BY
ada) dan menghitung grup tanpa
pemblokiran. Agregat berbasis hash membuat tabel hash untuk mempertahankan agregat
inkremental dari beberapa baris input secara bersamaan. Agregat berbasis streaming lebih cepat dan menggunakan lebih sedikit memori daripada agregat berbasis hash, tetapi memerlukan input untuk diurutkan (baik menurut kolom kunci maupun indeks sekunder).
Untuk skenario terdistribusi, operator gabungan dapat dipisahkan menjadi pasangan lokal-global. Setiap server jarak jauh melakukan agregasi lokal pada baris inputnya, lalu menampilkan hasilnya ke server root. Server root melakukan agregasi global.
Menerapkan mutasi
Operator apply mutations menerapkan mutasi dari Data Manipulation Statement (DML) ke tabel. Ini adalah operator teratas dalam rencana kueri untuk pernyataan DML.
Misalnya, menggunakan kueri ini:
DELETE FROM singers
WHERE firstname = 'Alice';
Berikut adalah hasilnya:
4 rows deleted This statement deleted 4 rows and did not return any rows.
Berikut adalah rencana eksekusi:
Membuat batch
Operator create batch mengelompokkan baris inputnya ke dalam urutan. Operasi pembuatan batch biasanya terjadi sebagai bagian dari operasi penerapan lintas terdistribusi. Baris input dapat diurutkan ulang selama pengelompokan. Jumlah baris input yang dikelompokkan dalam setiap eksekusi operator batch bervariasi.
Lihat operator cross apply terdistribusi untuk mengetahui contoh operator batch pembuatan dalam rencana eksekusi.
Compute
Operator compute menghasilkan output dengan membaca baris inputnya dan menambahkan satu atau beberapa kolom tambahan yang dihitung menggunakan ekspresi skalar. Lihat operator union all untuk mengetahui contoh operator komputasi dalam paket eksekusi.
Menghitung struct
Operator compute struct membuat variabel untuk struktur yang berisi kolom untuk setiap kolom input.
Misalnya, menggunakan kueri ini:
SELECT FirstName,
ARRAY(SELECT AS STRUCT song.SongName, song.SongGenre
FROM Songs AS song
WHERE song.SingerId = singer.SingerId)
FROM singers AS singer
WHERE singer.SingerId = 3;
Berikut adalah hasilnya:
FirstName | Tidak ditentukan |
---|---|
Alice | [["Not About The Guitar","BLUES"]] |
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi, operator subkueri array menerima input dari
operator gabungan terdistribusi, yang menerima input dari
operator struct komputasi. Operator compute struct membuat struktur dari
kolom SongName
dan SongGenre
dalam tabel Songs
.
Filter
Operator filter membaca semua baris dari inputnya, menerapkan predikat skalar pada setiap baris, lalu hanya menampilkan baris yang memenuhi predikat.
Misalnya, menggunakan kueri ini:
SELECT s.lastname
FROM (SELECT s.lastname
FROM singers AS s
LIMIT 3) s
WHERE s.lastname LIKE 'Rich%';
Berikut adalah hasilnya:
LastName |
---|
Richards |
Berikut adalah rencana eksekusi:
Predikat untuk penyanyi yang nama belakangnya diawali dengan Rich
diterapkan sebagai
filter. Input filter adalah output dari pemindaian indeks, dan
output filter adalah baris tempat LastName
dimulai dengan Rich
.
Untuk performa, setiap kali filter diposisikan langsung di atas pemindaian,
filter akan memengaruhi cara data dibaca. Misalnya, pertimbangkan tabel dengan kunci k
.
Filter dengan predikat k = 5
langsung di atas pemindaian tabel akan mencari baris yang cocok dengan k = 5
, tanpa membaca seluruh input. Hal ini menghasilkan
eksekusi kueri yang lebih efisien. Pada contoh sebelumnya, operator
filter hanya membaca baris yang memenuhi predikat
WHERE s.LastName LIKE 'Rich%'
.
Pemindaian filter
Operator pemindaian filter selalu berada di atas pemindaian tabel atau indeks. Fungsi ini berfungsi dengan pemindaian untuk mengurangi jumlah baris yang dibaca dari database, dan pemindaian yang dihasilkan biasanya lebih cepat daripada dengan filter. Spanner menerapkan pemindaian filter dalam kondisi tertentu:
- Kondisi yang dapat dicari: Kondisi yang dapat dicari berlaku jika Spanner dapat
menentukan baris tertentu untuk diakses dalam tabel. Secara umum, hal ini terjadi
saat filter berada di awalan kunci utama. Misalnya, jika
kunci utama terdiri dari
Col1
danCol2
, maka klausaWHERE
yang menyertakan nilai eksplisit untukCol1
, atauCol1
danCol2
dapat ditelusuri. Dalam hal ini, Spanner hanya membaca data dalam rentang kunci. - Kondisi residual: Kondisi lain yang memungkinkan Spanner mengevaluasi pemindaian untuk membatasi jumlah data yang dibaca.
Misalnya, menggunakan kueri ini:
SELECT lastname
FROM singers
WHERE singerid = 1
Berikut adalah hasilnya:
LastName |
---|
Richards |
Berikut adalah rencana eksekusi:
Batas
Operator limit membatasi jumlah baris yang ditampilkan. Parameter OFFSET
opsional menentukan baris awal yang akan ditampilkan. Untuk skenario terdistribusi, operator batas dapat dipisahkan menjadi pasangan lokal-global. Setiap server jarak jauh menerapkan batas lokal untuk baris output-nya, lalu menampilkan hasilnya ke server root. Server root menggabungkan baris yang dikirim oleh server jarak jauh, lalu menerapkan batas global.
Misalnya, menggunakan kueri ini:
SELECT s.songname
FROM songs AS s
LIMIT 3;
Berikut adalah hasilnya:
SongName |
---|
Not About The Guitar |
Kali Kedua |
Mulai Lagi |
Berikut adalah rencana eksekusi:
Batas lokal adalah batas untuk setiap server jarak jauh. Server root menggabungkan baris dari server jarak jauh, lalu menerapkan batas global.
Penetapan ID Acak
Operator random ID assign menghasilkan output dengan membaca baris inputnya dan
menambahkan angka acak ke setiap baris. Fungsi ini berfungsi dengan operator Filter
atau Sort
untuk mencapai metode sampling. Metode pengambilan sampel yang didukung adalah Bernoulli dan Reservoir.
Misalnya, kueri berikut menggunakan sampling Bernoulli dengan frekuensi sampling 10 persen.
SELECT s.songname
FROM songs AS s TABLESAMPLE bernoulli (10 PERCENT);
Berikut adalah hasilnya:
SongName |
---|
Mulai Lagi |
Nothing Is The Same |
Perhatikan bahwa karena hasilnya adalah sampel, hasilnya dapat bervariasi setiap kali kueri dijalankan meskipun kueri tersebut sama.
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi ini, operator Random Id Assign
menerima inputnya dari
operator union terdistribusi, yang menerima inputnya
dari pemindaian indeks. Operator menampilkan baris dengan ID acak dan
operator Filter
kemudian menerapkan predikat skalar pada ID acak dan
menampilkan sekitar 10 persen baris.
Contoh berikut menggunakan sampling Reservoir dengan kecepatan sampling 2 baris.
SELECT s.songname
FROM songs AS s TABLESAMPLE reservoir (2 rows);
Berikut adalah hasilnya:
SongName |
---|
I Knew You Were Magic |
Kali Kedua |
Perhatikan bahwa karena hasilnya adalah sampel, hasilnya dapat bervariasi setiap kali kueri dijalankan meskipun kueri tersebut sama.
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi ini, operator Random Id Assign
menerima inputnya dari
operator union terdistribusi, yang menerima inputnya
dari pemindaian indeks. Operator menampilkan baris dengan ID acak dan
operator Sort
kemudian menerapkan urutan pengurutan pada ID acak dan menerapkan
LIMIT
dengan 2 baris.
Gabungan pemisahan lokal
Operator gabungan pemisahan lokal menemukan pemisahan tabel yang disimpan di server lokal, menjalankan subkueri pada setiap pemisahan, lalu membuat gabungan yang menggabungkan semua hasil.
Gabungan pemisahan lokal muncul dalam rencana eksekusi yang memindai tabel penempatan. Penempatan dapat meningkatkan jumlah pemisahan dalam tabel, sehingga lebih efisien untuk memindai pemisahan dalam batch berdasarkan lokasi penyimpanan fisiknya.
Misalnya, tabel Singers
menggunakan kunci penempatan untuk mempartisi
data penyanyi:
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
SingerName STRING(MAX) NOT NULL,
...
Location STRING(MAX) NOT NULL PLACEMENT KEY
) PRIMARY KEY (SingerId);
Sekarang, pertimbangkan kueri ini:
SELECT BirthDate FROM Singers;
Berikut adalah rencana eksekusi:
Union terdistribusi mengirimkan subkueri ke setiap batch pemisahan yang disimpan secara fisik bersama di server yang sama. Di setiap server, gabungan
bagian lokal menemukan bagian yang menyimpan data Singers
, menjalankan subkueri di setiap
bagian, dan menampilkan hasil gabungan. Dengan cara ini, union terdistribusi dan
union pemisahan lokal bekerja sama untuk memindai tabel Singers
secara efisien.
Tanpa penggabungan bagian lokal, penggabungan terdistribusi akan mengirim satu RPC per bagian, bukan per batch bagian, sehingga menghasilkan perjalanan bolak-balik RPC yang redundan jika ada lebih dari satu bagian per batch.
Serialisasi hasil
Operator serialize result adalah kasus khusus dari operator struct komputasi yang melakukan serialisasi setiap baris hasil akhir kueri, untuk ditampilkan ke klien.
Misalnya, menggunakan kueri ini:
SELECT array
(
select as struct so.songname,
so.songgenre
FROM songs AS so
WHERE so.singerid = s.singerid)
FROM singers AS s;
Kueri meminta array SongName
dan SongGenre
berdasarkan SingerId
.
Berikut adalah hasilnya:
Tidak ditentukan |
---|
[] |
[[Let's Get Back Together, COUNTRY], [Starting Again, ROCK]] |
[[Not About The Guitar, BLUES]] |
[] |
[] |
Berikut adalah rencana eksekusi:
Operator hasil serialisasi membuat hasil yang berisi, untuk setiap baris
tabel Singers
, array pasangan SongName
dan SongGenre
untuk lagu
oleh penyanyi.
Urutkan
Operator sort membaca baris inputnya, mengurutkannya berdasarkan kolom, lalu menampilkan hasil yang telah diurutkan.
Misalnya, menggunakan kueri ini:
SELECT s.songgenre
FROM songs AS s
ORDER BY songgenre;
Berikut adalah hasilnya:
SongGenre |
---|
BLUES |
BLUES |
BLUES |
BLUES |
KLASIK |
NEGARA |
ROCK |
ROCK |
ROCK |
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi ini, operator pengurutan menerima baris inputnya dari operator union terdistribusi, mengurutkan baris input, dan menampilkan baris yang diurutkan ke operator hasil serialisasi.
Untuk membatasi jumlah baris yang ditampilkan, operator pengurutan secara opsional dapat memiliki
parameter LIMIT
dan OFFSET
. Untuk skenario terdistribusi, operator pengurutan dengan
operator LIMIT
atau OFFSET
dipisahkan menjadi pasangan lokal-global. Setiap
server jarak jauh menerapkan urutan pengurutan dan batas atau offset lokal untuk baris
inputnya, lalu menampilkan hasilnya ke server root. Server root
menggabungkan baris yang dikirim oleh server jarak jauh, mengurutkannya, lalu menerapkan
batas/offset global.
Misalnya, menggunakan kueri ini:
SELECT s.songgenre
FROM songs AS s
ORDER BY songgenre
LIMIT 3;
Berikut adalah hasilnya:
SongGenre |
---|
BLUES |
BLUES |
BLUES |
Berikut adalah rencana eksekusi:
Rencana eksekusi menunjukkan batas lokal untuk server jarak jauh dan batas global untuk server root.
TVF
Operator fungsi bernilai tabel menghasilkan output dengan membaca baris inputnya dan menerapkan fungsi yang ditentukan. Fungsi ini mungkin menerapkan pemetaan dan menampilkan jumlah baris yang sama dengan input. Ini juga dapat berupa generator yang menampilkan lebih banyak baris atau filter yang menampilkan lebih sedikit baris.
Misalnya, menggunakan kueri ini:
SELECT genre,
songname
FROM ml.predict(model genreclassifier, TABLE songs)
Berikut adalah hasilnya:
Genre | SongName |
---|---|
Negara | Not About The Guitar |
Rock | Kali Kedua |
Pop | Mulai Lagi |
Pop | Nothing Is The Same |
Negara | Let's Get Back Together |
Pop | I Knew You Were Magic |
Elektronik | Biru |
Rock | 42 |
Rock | Cerita Pertarungan |
Berikut adalah rencana eksekusi:
Input union
Operator input gabungan menampilkan hasil ke operator gabungan semua. Lihat operator union all untuk mengetahui contoh operator input gabungan dalam rencana eksekusi.
Operator biner
Operator biner adalah operator yang memiliki dua turunan relasional. Operator berikut adalah operator biner:
Penerapan silang
Operator cross apply menjalankan kueri tabel pada setiap baris yang diambil dengan kueri tabel lain, dan menampilkan gabungan dari semua kueri tabel yang berjalan. Operator penerapan silang dan penerapan luar menjalankan pemrosesan berorientasi baris, tidak seperti operator yang menjalankan pemrosesan berbasis set seperti hash join . Operator cross apply memiliki dua input, input dan map. Operator penerapan silang menerapkan setiap baris di sisi input ke sisi peta. Hasil cross apply memiliki kolom dari sisi input dan peta.
Misalnya, menggunakan kueri ini:
SELECT si.firstname,
(SELECT so.songname
FROM songs AS so
WHERE so.singerid = si.singerid
LIMIT 1)
FROM singers AS si;
Kueri meminta nama depan setiap penyanyi, beserta nama salah satu lagu penyanyi tersebut.
Berikut adalah hasilnya:
FirstName | Tidak ditentukan |
---|---|
Alice | Not About The Guitar |
Catalina | Let's Get Back Together |
David | NULL |
Lea | NULL |
Marc | NULL |
Kolom pertama diisi dari tabel Singers
, dan kolom kedua
diisi dari tabel Songs
. Jika SingerId
ada dalam
tabel Singers
, tetapi tidak ada SingerId
yang cocok dalam tabel Songs
,
kolom kedua akan berisi NULL
.
Berikut adalah rencana eksekusi:
Node tingkat teratas adalah operator union terdistribusi. Operator gabungan terdistribusi mendistribusikan sub-rencana ke server jarak jauh. Sub-rencana berisi operator serialisasi hasil yang menghitung nama depan penyanyi dan nama salah satu lagu penyanyi serta melakukan serialisasi setiap baris output.
Operator hasil serialisasi menerima inputnya dari operator cross apply.
Sisi input untuk operator cross apply adalah pemindaian tabel pada
tabel Singers
.
Sisi peta untuk operasi cross apply berisi hal berikut (dari atas ke bawah):
- Operator agregat yang menampilkan
Songs.SongName
. - Operator limit yang membatasi jumlah lagu yang ditampilkan menjadi satu per penyanyi.
- Pemindaian indeks pada indeks
SongsBySingerAlbumSongNameDesc
.
Operator penerapan silang memetakan setiap baris dari sisi input ke baris di sisi peta yang memiliki SingerId
yang sama. Output operator cross apply adalah nilai FirstName
dari baris input, dan nilai SongName
dari baris peta.
(Nilai SongName
adalah NULL
jika tidak ada baris peta yang cocok di
SingerId
.) Operator union terdistribusi di bagian atas rencana eksekusi
kemudian menggabungkan semua baris output dari server jarak jauh dan menampilkannya sebagai
hasil kueri.
Hash join
Operator hash join adalah implementasi gabungan SQL berbasis hash. Hash join menjalankan pemrosesan berbasis set. Operator join hash membaca baris dari input yang ditandai sebagai build dan menyisipkannya ke dalam tabel hash berdasarkan kondisi join. Operator join hash kemudian membaca baris dari input yang ditandai sebagai probe. Untuk setiap baris yang dibaca dari input probe, operator join hash akan mencari baris yang cocok dalam tabel hash. Operator hash join menampilkan baris yang cocok sebagai hasil.
Misalnya, menggunakan kueri ini:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=hash_join} songs AS s
ON a.singerid = s.singerid
AND a.albumid = s.albumid;
Berikut adalah hasilnya:
AlbumTitle | SongName |
---|---|
Nothing To Do With Me | Not About The Guitar |
Hijau | Kali Kedua |
Hijau | Mulai Lagi |
Hijau | Nothing Is The Same |
Hijau | Let's Get Back Together |
Hijau | I Knew You Were Magic |
Hijau | Biru |
Hijau | 42 |
Sangat takut | Cerita Pertarungan |
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi, build adalah union terdistribusi yang
mendistribusikan pemindaian pada tabel Albums
. Probe adalah operator gabungan
terdistribusi yang mendistribusikan pemindaian pada indeks SongsBySingerAlbumSongNameDesc
.
Operator hash join membaca semua baris dari sisi build. Setiap baris build
ditempatkan dalam tabel hash berdasarkan kolom dalam kondisi a.SingerId =
s.SingerId AND a.AlbumId = s.AlbumId
. Selanjutnya, operator join hash membaca semua
baris dari sisi probe. Untuk setiap baris probe, operator join hash akan mencari
kecocokan dalam tabel hash. Kecocokan yang dihasilkan ditampilkan oleh operator join
hash.
Kecocokan yang dihasilkan dalam tabel hash juga dapat difilter berdasarkan kondisi residual sebelum ditampilkan. (Contoh tempat kondisi residu muncul adalah dalam join non-kesetaraan). Rencana eksekusi join hash dapat menjadi kompleks karena manajemen memori dan varian join. Algoritma hash join utama disesuaikan untuk menangani varian join dalam, semi, anti, dan luar.
Join penggabungan
Operator merge join adalah implementasi gabungan SQL berbasis penggabungan. Kedua sisi join menghasilkan baris yang diurutkan berdasarkan kolom yang digunakan dalam kondisi join. Join
gabungan menggunakan kedua aliran input secara bersamaan dan menghasilkan baris saat
kondisi join terpenuhi. Jika input awalnya tidak diurutkan seperti yang diperlukan, pengoptimal akan menambahkan operator Sort
eksplisit ke rencana.
Merge join tidak dipilih secara otomatis oleh pengoptimal. Untuk menggunakan operator ini, tetapkan metode join ke MERGE_JOIN
pada petunjuk kueri, seperti yang ditunjukkan dalam contoh berikut:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=merge_join} songs AS s
ON a.singerid = s.singerid
AND a.albumid = s.albumid;
Berikut adalah hasilnya:
AlbumTitle | SongName |
---|---|
Hijau | Kali Kedua |
Hijau | Mulai Lagi |
Hijau | Nothing Is The Same |
Hijau | Let's Get Back Together |
Hijau | I Knew You Were Magic |
Hijau | Biru |
Hijau | 42 |
Sangat takut | Cerita Pertarungan |
Nothing To Do With Me | Not About The Guitar |
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi ini, join penggabungan didistribusikan sehingga join dieksekusi
di lokasi data. Hal ini juga memungkinkan join penggabungan dalam contoh ini
beroperasi tanpa pengenalan operator pengurutan tambahan, karena kedua
pemindaian tabel sudah diurutkan menurut SingerId
, AlbumId
, yang merupakan kondisi
join. Dalam rencana ini, pemindaian sisi kiri tabel Albums
akan maju
setiap kali SingerId
, AlbumId
-nya secara komparatif lebih kecil dari pasangan
SingerId_1
, AlbumId_1
pemindaian indeks SongsBySingerAlbumSongNameDesc
sisi kanan.
Demikian pula, sisi kanan akan maju setiap kali lebih kecil dari sisi kiri. Kemajuan penggabungan ini terus menelusuri kesetaraan sehingga
hasil pencocokan dapat ditampilkan.
Pertimbangkan contoh join penggabungan lainnya menggunakan kueri berikut:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=merge_join} songs AS s
ON a.albumid = s.albumid;
Tindakan ini akan menghasilkan hasil berikut:
AlbumTitle | SongName |
---|---|
Total Sampah | Kali Kedua |
Total Sampah | Mulai Lagi |
Total Sampah | Nothing Is The Same |
Total Sampah | Let's Get Back Together |
Total Sampah | I Knew You Were Magic |
Total Sampah | Biru |
Total Sampah | 42 |
Total Sampah | Not About The Guitar |
Hijau | Kali Kedua |
Hijau | Mulai Lagi |
Hijau | Nothing Is The Same |
Hijau | Let's Get Back Together |
Hijau | I Knew You Were Magic |
Hijau | Biru |
Hijau | 42 |
Hijau | Not About The Guitar |
Nothing To Do With Me | Kali Kedua |
Nothing To Do With Me | Mulai Lagi |
Nothing To Do With Me | Nothing Is The Same |
Nothing To Do With Me | Let's Get Back Together |
Nothing To Do With Me | I Knew You Were Magic |
Nothing To Do With Me | Biru |
Nothing To Do With Me | 42 |
Nothing To Do With Me | Not About The Guitar |
Putar | Kali Kedua |
Putar | Mulai Lagi |
Putar | Nothing Is The Same |
Putar | Let's Get Back Together |
Putar | I Knew You Were Magic |
Putar | Biru |
Putar | 42 |
Putar | Not About The Guitar |
Sangat takut | Cerita Pertarungan |
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi sebelumnya, operator Sort
tambahan telah
diperkenalkan oleh pengoptimal kueri untuk mendapatkan properti yang diperlukan agar
join penggabungan dapat dieksekusi. Kondisi JOIN
dalam kueri contoh ini hanya ada di
AlbumId
, yang bukan cara data disimpan, sehingga pengurutan harus ditambahkan. Mesin kueri mendukung algoritma Penggabungan Terdistribusi, yang memungkinkan pengurutan terjadi secara lokal, bukan secara global, yang mendistribusikan dan memparalelkan biaya CPU.
Kecocokan yang dihasilkan juga dapat difilter berdasarkan kondisi residual sebelum ditampilkan. (Contoh tempat kondisi residual muncul adalah dalam join non-kesetaraan). Rencana eksekusi join penggabungan dapat bersifat kompleks karena persyaratan pengurutan tambahan. Algoritma join penggabungan utama diadaptasi untuk menangani varian join dalam, semi, anti, dan luar.
Hash join siaran push
Operator push broadcast hash join adalah implementasi join SQL berbasis hash-join terdistribusi. Operator join hash siaran push membaca baris dari sisi input untuk membuat batch data. Kemudian, batch tersebut akan disiarkan ke semua server yang berisi data sisi peta. Di server tujuan tempat batch data diterima, join hash dibuat menggunakan batch sebagai data sisi build dan data lokal kemudian dipindai sebagai sisi probe join hash.
Push broadcast hash join tidak dipilih secara otomatis oleh pengoptimal. Untuk
menggunakan operator ini, tetapkan metode join ke PUSH_BROADCAST_HASH_JOIN
pada
petunjuk kueri, seperti yang ditunjukkan dalam contoh berikut:
SELECT a.albumtitle,
s.songname
FROM albums AS a join@{join_method=push_broadcast_hash_join} songs AS s
ON a.singerid = s.singerid
AND a.albumid = s.albumid;
Berikut adalah hasilnya:
AlbumTitle | SongName |
---|---|
Hijau | Kali Kedua |
Hijau | Mulai Lagi |
Hijau | Nothing Is The Same |
Hijau | Lets Get Back Together |
Hijau | I Knew You Were Magic |
Hijau | Biru |
Hijau | 42 |
Sangat takut | Cerita Pertarungan |
Nothing To Do With Me | Not About The Guitar |
Berikut adalah rencana eksekusi:
Input ke hash join siaran Push adalah indeks AlbumsByAlbumTitle
.
Input tersebut diserialisasi menjadi batch data. Batch tersebut kemudian dikirim ke semua
pemisahan lokal indeks SongsBySingerAlbumSongNameDesc
, tempat batch
kemudian dideserialisasi dan dibuat menjadi tabel hash. Tabel hash kemudian menggunakan
data indeks lokal sebagai probe yang menampilkan kecocokan yang dihasilkan.
Kecocokan yang dihasilkan juga dapat difilter berdasarkan kondisi residual sebelum ditampilkan. (Contoh tempat kondisi residual muncul adalah dalam join non-kesetaraan).
Penerapan luar
Operator outer apply mirip dengan operator cross apply, tetapi operator outer apply memastikan bahwa setiap eksekusi di sisi peta menampilkan setidaknya satu baris dengan membuat baris yang ditambahkan NULL jika diperlukan. (Dengan kata lain, semantik ini menyediakan semantik left outer join.)
Union rekursif
Operator union rekursif melakukan gabungan dari dua input, satu yang mewakili
kasus base
, dan yang lainnya mewakili kasus recursive
. Fungsi ini digunakan
dalam kueri grafik dengan traversal jalur yang diukur. Input dasar diproses
terlebih dahulu dan tepat satu kali. Input rekursif diproses hingga rekursi
dihentikan. Rekursi dihentikan saat batas atas, jika ditentukan, dicapai, atau saat rekursi tidak menghasilkan hasil baru. Dalam
contoh berikut, tabel Collaborations
ditambahkan ke skema, dan
grafik properti bernama MusicGraph
dibuat.
CREATE TABLE Collaborations (
SingerId INT64 NOT NULL,
FeaturingSingerId INT64 NOT NULL,
AlbumTitle STRING(MAX) NOT NULL,
) PRIMARY KEY(SingerId, FeaturingSingerId, AlbumTitle);
CREATE OR REPLACE PROPERTY GRAPH MusicGraph
NODE TABLES(
Singers
KEY(SingerId)
LABEL Singers PROPERTIES(
BirthDate,
FirstName,
LastName,
SingerId,
SingerInfo)
)
EDGE TABLES(
Collaborations AS CollabWith
KEY(SingerId, FeaturingSingerId, AlbumTitle)
SOURCE KEY(SingerId) REFERENCES Singers(SingerId)
DESTINATION KEY(FeaturingSingerId) REFERENCES Singers(SingerId)
LABEL CollabWith PROPERTIES(
AlbumTitle,
FeaturingSingerId,
SingerId),
);
Kueri grafik berikut menemukan penyanyi yang telah berkolaborasi dengan penyanyi tertentu atau berkolaborasi dengan kolaborator tersebut.
GRAPH MusicGraph
MATCH (singer:Singers {singerId:42})-[c:CollabWith]->{1,2}(featured:Singers)
RETURN singer.SingerId AS singer, featured.SingerId AS featured
Operator rekursif union memfilter tabel Singers
untuk menemukan penyanyi
dengan SingerId
yang diberikan. Ini adalah input dasar untuk union rekursif. Input
rekursif ke union rekursif terdiri dari
cross apply terdistribusi atau operator join lainnya untuk
kueri lain yang berulang kali menggabungkan tabel Collaborations
dengan hasil
iterasi join sebelumnya. Baris dari input dasar membentuk
iterasi nol. Pada setiap iterasi, output iterasi disimpan oleh
pemindaian spool rekursif. Baris dari pemindaian spool rekursif digabungkan dengan
tabel Collaborations
di spoolscan.featuredSingerId =
Collaborations.SingerId
. Rekursi dihentikan saat dua iterasi
selesai, karena itu adalah batas atas yang ditentukan dalam kueri.
Operator n-ary
Operator N-ary adalah operator yang memiliki lebih dari dua turunan relasional. Operator berikut adalah operator N-ary:
Union all
Operator union all menggabungkan semua kumpulan baris turunannya tanpa menghapus duplikat. Gabungan semua operator menerima input dari operator input gabungan yang didistribusikan di beberapa server. Operator gabungan semua mengharuskan inputnya memiliki skema yang sama, yaitu, kumpulan jenis data yang sama untuk setiap kolom.
Misalnya, menggunakan kueri ini:
SELECT 1 a,
2 b
UNION ALL
SELECT 3 a,
4 b
UNION ALL
SELECT 5 a,
6 b;
Jenis baris untuk turunan terdiri dari dua bilangan bulat.
Berikut adalah hasilnya:
a | b |
---|---|
1 | 2 |
3 | 4 |
5 | 6 |
Berikut adalah rencana eksekusi:
Operator union all menggabungkan baris inputnya, dan dalam contoh ini, operator tersebut mengirim hasil ke operator hasil serialisasi.
Kueri seperti berikut akan berhasil, karena kumpulan jenis data yang sama digunakan untuk setiap kolom, meskipun turunan menggunakan variabel yang berbeda untuk nama kolom:
SELECT 1 a,
2 b
UNION ALL
SELECT 3 c,
4 e;
Kueri seperti berikut tidak akan berhasil, karena turunan menggunakan jenis data yang berbeda untuk kolom:
SELECT 1 a,
2 b
UNION ALL
SELECT 3 a,
'This is a string' b;
Subkueri skalar
Subkueri skalar adalah sub-ekspresi SQL yang merupakan bagian dari ekspresi skalar. Spanner akan berusaha menghapus subkueri skalar jika memungkinkan. Namun, dalam skenario tertentu, rencana dapat secara eksplisit berisi subkueri skalar.
Misalnya, menggunakan kueri ini:
SELECT firstname,
IF(firstname = 'Alice', (SELECT Count(*)
FROM songs
WHERE duration > 300), 0)
FROM singers;
Ini adalah sub-ekspresi SQL:
SELECT Count(*)
FROM songs
WHERE duration > 300;
Berikut adalah hasilnya (dari kueri lengkap):
FirstName | |
---|---|
Alice | 1 |
Catalina | 0 |
David | 0 |
Lea | 0 |
Marc | 0 |
Berikut adalah rencana eksekusi:
Rencana eksekusi berisi subkueri skalar, yang ditampilkan sebagai Subkueri Skalar, di atas operator agregat.
Spanner terkadang mengonversi subkueri skalar menjadi operator lain seperti join atau cross apply, untuk meningkatkan performa.
Misalnya, menggunakan kueri ini:
SELECT *
FROM songs
WHERE duration = (SELECT Max(duration)
FROM songs);
Ini adalah sub-ekspresi SQL:
SELECT MAX(Duration)
FROM Songs;
Berikut adalah hasilnya (dari kueri lengkap):
SingerId | AlbumId | TrackId | SongName | Durasi | SongGenre |
---|---|---|---|---|---|
2 | 1 | 6 | Nothing Is The Same | 303 | BLUES |
Berikut adalah rencana eksekusi:
Rencana eksekusi tidak berisi subkueri skalar karena Spanner mengonversi subkueri skalar menjadi cross apply.
Subkueri array
Subkueri array mirip dengan subkueri skalar, kecuali bahwa subkueri diizinkan untuk menggunakan lebih dari satu baris input. Baris yang digunakan dikonversi menjadi satu array output skalar yang berisi satu elemen per baris input yang digunakan.
Misalnya, menggunakan kueri ini:
SELECT a.albumid,
array
(
select concertdate
FROM concerts
WHERE concerts.singerid = a.singerid)
FROM albums AS a;
Ini adalah subkueri:
SELECT concertdate
FROM concerts
WHERE concerts.singerid = a.singerid;
Hasil subkueri untuk setiap AlbumId
dikonversi menjadi array baris ConcertDate
terhadap AlbumId
tersebut. Rencana eksekusi berisi subkueri array, yang ditampilkan sebagai Subkueri Array, di atas operator union terdistribusi:
Operator terdistribusi
Operator yang dijelaskan sebelumnya di halaman ini dieksekusi dalam batas satu mesin. Operator terdistribusi dijalankan di beberapa server.
Operator berikut adalah operator terdistribusi:
- Gabungan terdistribusi
- Gabungan penggabungan terdistribusi
- Cross apply terdistribusi
- Terdistribusikan penerapan luar
- Menerapkan mutasi
Operator union terdistribusi adalah operator primitif yang berasal dari penerapan lintas terdistribusi dan penerapan luar terdistribusi.
Operator terdistribusi muncul dalam rencana eksekusi dengan varian union terdistribusi di atas satu atau beberapa varian union terdistribusi lokal. Varian gabungan terdistribusi melakukan distribusi sub-rencana jarak jauh. Varian gabungan yang didistribusikan secara lokal berada di atas setiap pemindaian yang dilakukan untuk kueri, seperti yang ditunjukkan dalam rencana eksekusi ini:
Varian penggabungan terdistribusi lokal memastikan eksekusi kueri yang stabil saat dimulai ulang terjadi untuk mengubah batas pemisahan secara dinamis.
Jika memungkinkan, varian union terdistribusi memiliki predikat pemisahan yang menghasilkan pemangkasan pemisahan, yang berarti server jarak jauh hanya menjalankan sub-rencana pada pemisahan yang memenuhi predikat. Hal ini meningkatkan latensi dan performa kueri secara keseluruhan.
Union terdistribusi
Operator union terdistribusi secara konseptual membagi satu atau beberapa tabel menjadi beberapa bagian, mengevaluasi subkueri secara terpisah dari jarak jauh pada setiap bagian, lalu menggabungkan semua hasil.
Misalnya, menggunakan kueri ini:
SELECT s.songname,
s.songgenre
FROM songs AS s
WHERE s.singerid = 2
AND s.songgenre = 'ROCK';
Berikut adalah hasilnya:
SongName | SongGenre |
---|---|
Mulai Lagi | ROCK |
Kali Kedua | ROCK |
Cerita Pertarungan | ROCK |
Berikut adalah rencana eksekusi:
Operator union terdistribusi mengirim sub-rencana ke server jarak jauh, yang melakukan
pemindaian tabel di seluruh bagian yang memenuhi predikat kueri WHERE
s.SingerId = 2 AND s.SongGenre = 'ROCK'
. Operator serialize
result menghitung nilai SongName
dan SongGenre
dari baris yang ditampilkan oleh pemindaian tabel. Operator union terdistribusi
kemudian menampilkan hasil gabungan dari server jarak jauh sebagai hasil kueri
SQL.
Gabungan penggabungan terdistribusi
Operator distributed merge union mendistribusikan kueri ke beberapa server jarak jauh. Kemudian, fungsi ini menggabungkan hasil kueri untuk menghasilkan hasil yang diurutkan, yang dikenal sebagai pengurutan penggabungan terdistribusi.
Gabungan penggabungan terdistribusi menjalankan langkah-langkah berikut:
Server root mengirimkan subkueri ke setiap server jarak jauh yang menghosting bagian data yang dikueri. Subkueri menyertakan petunjuk bahwa hasil diurutkan dalam urutan tertentu.
Setiap server jarak jauh mengeksekusi subkueri pada bagiannya, lalu mengirimkan hasilnya kembali dalam urutan yang diminta.
Server root menggabungkan subkueri yang diurutkan untuk menghasilkan hasil yang diurutkan sepenuhnya.
Gabungan penggabungan terdistribusi diaktifkan, secara default, untuk Spanner Versi 3 dan yang lebih baru.
Penerapan silang terdistribusi
Operator cross apply terdistribusi (DCA) memperluas operator cross apply dengan dieksekusi di beberapa server. Sisi input DCA mengelompokkan batch baris (tidak seperti operator penerapan silang reguler, yang hanya bertindak pada satu baris input dalam satu waktu). Sisi peta DCA adalah kumpulan operator cross apply yang dijalankan di server jarak jauh.
Misalnya, menggunakan kueri ini:
SELECT albumtitle
FROM songs
JOIN albums
ON albums.albumid = songs.albumid;
Hasilnya dalam format:
AlbumTitle |
---|
Hijau |
Nothing To Do With Me |
Putar |
Total Sampah |
Hijau |
Berikut adalah rencana eksekusi:
Input DCA berisi pemindaian indeks pada
indeks SongsBySingerAlbumSongNameDesc
yang mengelompokkan baris AlbumId
. Sisi peta
untuk operator cross apply ini adalah pemindaian indeks pada indeks
AlbumsByAlbumTitle
, tunduk pada predikat AlbumId
di baris input
yang cocok dengan kunci AlbumId
di indeks AlbumsByAlbumTitle
. Pemetaan
menampilkan SongName
untuk nilai SingerId
dalam baris input yang di-batch.
Untuk meringkas proses DCA untuk contoh ini, input DCA adalah baris
yang dikelompokkan dari tabel Albums
, dan output DCA adalah penerapan baris
ini ke peta pemindaian indeks.
Penerapan luar terdistribusi
Operator penerapan luar terdistribusi memperluas operator penerapan luar dengan dieksekusi di beberapa server, mirip dengan cara operator penerapan silang terdistribusi memperluas operator penerapan silang.
Misalnya, menggunakan kueri ini:
SELECT lastname,
concertdate
FROM singers LEFT OUTER join@{JOIN_TYPE=APPLY_JOIN} concerts
ON singers.singerid=concerts.singerid;
Hasilnya dalam format:
LastName | ConcertDate |
---|---|
Trentor | 2014-02-18 |
Smith | 2011-09-03 |
Smith | 2010-06-06 |
Lomond | 2005-04-30 |
Martin | 2015-11-04 |
Richards |
Berikut adalah rencana eksekusi:
Menerapkan mutasi
Operator apply mutations menerapkan mutasi dari Data Manipulation Statement (DML) ke tabel. Ini adalah operator teratas dalam rencana kueri untuk pernyataan DML.
Misalnya, menggunakan kueri ini:
DELETE FROM singers
WHERE firstname = 'Alice';
Berikut adalah hasilnya:
4 rows deleted This statement deleted 4 rows and did not return any rows.
Berikut adalah rencana eksekusi:
Informasi tambahan
Bagian ini menjelaskan item yang bukan operator mandiri, tetapi menjalankan tugas untuk mendukung satu atau beberapa operator yang tercantum sebelumnya. Item yang dijelaskan di sini secara teknis adalah operator, tetapi bukan operator terpisah dalam rencana kueri Anda.
Konstruktor struct
Konstruktor struct membuat struct, atau kumpulan kolom. Fungsi ini biasanya membuat struct untuk baris yang dihasilkan dari operasi komputasi. Konstruktor struct bukan operator mandiri. Sebagai gantinya, operator ini muncul di operator compute struct atau operator serialize result.
Untuk operasi struct komputasi, konstruktor struct membuat struct sehingga kolom untuk baris yang dihitung dapat menggunakan satu referensi variabel ke struct.
Untuk operasi hasil serialisasi, konstruktor struct membuat struct untuk melakukan serialisasi hasil.
Misalnya, menggunakan kueri ini:
SELECT IF(TRUE, struct(1 AS A, 1 AS B), struct(2 AS A , 2 AS B)).A;
Berikut adalah hasilnya:
A |
---|
1 |
Berikut adalah rencana eksekusi:
Dalam rencana eksekusi, konstruktor struct muncul di dalam operator hasil serialisasi.