Operator eksekusi kueri

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 leaf adalah operator yang tidak memiliki turunan. Jenis operator daun adalah:

Unnest array

Operator membuka array 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 hasilnya:

a b
1 0
2 1
3 2

Berikut adalah rencana eksekusi:

operator unnest array

Buat relasi

Operator generate relation menampilkan nol baris atau lebih.

Relasi unit

unit relation menampilkan satu baris. Operator 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:

operator relasi unit

Relasi kosong

Relasi kosong tidak menampilkan baris. Operator 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:

operator relasi kosong

Pindai

Operator scan 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 penerapan silang terdistribusi).

Jika memungkinkan, Spanner menerapkan predikat pada kunci sebagai bagian dari pemindaian. Pemindaian dijalankan 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 hasilnya:

LastName
Smith

Berikut adalah rencana eksekusi:

operator pemindaian

Dalam rencana eksekusi, operator gabungan terdistribusi tingkat teratas mengirimkan sub-rencana ke server jarak jauh. Setiap sub-rencana memiliki operator serialize result 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 unary

Operator unary adalah operator yang memiliki satu turunan relasional.

Operator berikut adalah operator unary:

Agregat

Operator agregat menerapkan pernyataan SQL GROUP BY dan fungsi agregat (seperti COUNT). Input untuk operator agregat secara logis dipartisi ke dalam grup yang disusun pada kolom kunci (atau ke dalam satu grup jika GROUP BY tidak ada). Untuk setiap grup, nol atau lebih 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 dikelompokkan menurut SingerId dan melakukan agregasi AVG dan agregasi COUNT.

Berikut hasilnya:

SingerId rata-rata jumlah
3 278 1
2 225.875 8

Berikut adalah rencana eksekusi:

operator agregasi

Operator agregat dapat berupa berbasis streaming atau berbasis hash. Rencana eksekusi sebelumnya menunjukkan agregat berbasis streaming. Agregat berbasis streaming dibaca dari input yang sudah 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 yang diurutkan (baik berdasarkan kolom kunci atau indeks sekunder).

Untuk skenario terdistribusi, operator gabungan dapat dipisahkan menjadi pasangan lokal-global. Setiap server jarak jauh melakukan agregasi lokal pada baris input-nya, lalu menampilkan hasilnya ke server root. Server root melakukan agregasi global.

Menerapkan mutasi

Operator apply mutations menerapkan mutasi dari Pernyataan Manipulasi Data (DML) ke tabel. Operator ini adalah operator teratas dalam paket kueri untuk pernyataan DML.

Misalnya, menggunakan kueri ini:

DELETE FROM singers
WHERE  firstname = 'Alice';

Berikut hasilnya:

 4 rows deleted  This statement deleted 4 rows and did not return any rows.

Berikut adalah rencana eksekusi:

operator penerapan mutasi

Buat batch

Operator buat batch mengelompokkan baris inputnya ke dalam urutan. Operasi batch pembuatan biasanya terjadi sebagai bagian dari operasi penerapan silang terdistribusi. Baris input dapat diurutkan ulang selama pengelompokan. Jumlah baris input yang dikelompokkan dalam setiap eksekusi operator batch bervariasi.

Lihat operator distributed cross apply untuk mengetahui contoh operator batch buat 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 contoh operator komputasi dalam paket eksekusi.

Struktur komputasi

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 hasilnya:

FirstName Tidak ditentukan
Alice [["Not About The Guitar","BLUES"]]

Berikut adalah rencana eksekusi:

operator struct komputasi

Dalam rencana eksekusi, operator subkueri array menerima input dari operator gabungan terdistribusi, yang menerima input dari operator struktur komputasi. Operator struct compute membuat struktur dari kolom SongName dan SongGenre dalam tabel Songs.

DataBlockToRowAdapter

Operator DataBlockToRowAdapter otomatis disisipkan oleh pengoptimal kueri Spanner di antara sepasang operator yang beroperasi menggunakan metode eksekusi yang berbeda. Inputnya adalah operator yang menggunakan metode eksekusi berorientasi batch dan outputnya dimasukkan ke operator yang dieksekusi dalam metode eksekusi berorientasi baris. Untuk mengetahui informasi selengkapnya, lihat Mengoptimalkan eksekusi kueri.

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 hasilnya:

LastName
Richards

Berikut adalah rencana eksekusi:

operator filter

Predikat untuk penyanyi yang nama belakangnya diawali dengan Rich diimplementasikan sebagai filter. Input filter adalah output dari scan 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 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%'.

Memfilter pemindaian

Operator pemindaian filter selalu berada di atas pemindaian tabel atau indeks. Filter 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 dapat dicari: Kondisi dapat dicari berlaku jika Spanner dapat menentukan baris tertentu yang akan diakses dalam tabel. Secara umum, hal ini terjadi saat filter berada di awalan kunci utama. Misalnya, jika kunci utama terdiri dari Col1 dan Col2, maka klausa WHERE yang mencakup nilai eksplisit untuk Col1, atau Col1 dan Col2 dapat dicari. Dalam hal ini, Spanner hanya membaca data dalam rentang kunci.
  • Kondisi residual: Kondisi lain saat Spanner dapat mengevaluasi pemindaian untuk membatasi jumlah data yang dibaca.

Misalnya, menggunakan kueri ini:

SELECT lastname
FROM   singers
WHERE  singerid = 1

Berikut hasilnya:

LastName
Richards

Berikut adalah rencana eksekusi:

operator pemindaian filter

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 hasilnya:

SongName
Bukan Tentang Gitar
Kedua Kalinya
Mulai Lagi

Berikut adalah rencana eksekusi:

operator batas

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 penugasan ID acak menghasilkan output dengan membaca baris inputnya dan menambahkan angka acak ke setiap baris. Fungsi ini kompatibel dengan operator Filter atau Sort untuk mencapai metode pengambilan sampel. Metode pengambilan sampel yang didukung adalah Bernoulli dan Reservoir.

Misalnya, kueri berikut menggunakan pengambilan sampel Bernoulli dengan rasio pengambilan sampel sebesar 10 persen.

SELECT s.songname
FROM   songs AS s TABLESAMPLE bernoulli (10 PERCENT);

Berikut hasilnya:

SongName
Mulai Lagi
Tidak Ada yang Sama

Perhatikan bahwa karena hasilnya adalah sampel, hasil dapat bervariasi setiap kali kueri dijalankan meskipun kuerinya sama.

Berikut adalah rencana eksekusi:

operator sampel bernoulli

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 Reservoir

sampling dengan frekuensi pengambilan sampel 2 baris.

SELECT s.songname
FROM   songs AS s TABLESAMPLE reservoir (2 rows);

Berikut hasilnya:

SongName
I Knew You Were Magic
Kedua Kalinya

Perhatikan bahwa karena hasilnya adalah sampel, hasil dapat bervariasi setiap kali kueri dijalankan meskipun kuerinya sama.

Berikut adalah rencana eksekusi:

operator sampel reservoir

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.

Local split union muncul dalam rencana eksekusi yang memindai tabel placement. 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:

operator gabungan pemisahan lokal

Gabungan terdistribusi mengirimkan subkueri ke setiap batch pemisahan yang disimpan secara fisik bersama di server yang sama. Di setiap server, local split union menemukan bagian yang menyimpan data Singers, menjalankan subkueri di setiap bagian, dan menampilkan hasil gabungan. Dengan cara ini, gabungan terdistribusi dan gabungan pemisahan lokal bekerja sama untuk memindai tabel Singers secara efisien. Tanpa penggabungan pemisahan lokal, penggabungan terdistribusi akan mengirim satu RPC per pemisahan, bukan per batch pemisahan, sehingga menghasilkan perjalanan pulang pergi RPC yang berlebihan jika ada lebih dari satu pemisahan per batch.

RowToDataBlockAdapter

Operator RowToDataBlockAdapter otomatis disisipkan oleh pengoptimal kueri Spanner di antara sepasang operator yang beroperasi menggunakan metode eksekusi yang berbeda. Inputnya adalah operator yang menggunakan metode eksekusi berorientasi baris dan outputnya dimasukkan ke operator yang dieksekusi dalam metode eksekusi berorientasi batch. Untuk mengetahui informasi selengkapnya, lihat Mengoptimalkan eksekusi kueri.

Hasil serialisasi

Operator serialize result adalah kasus khusus dari operator compute struct 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 hasilnya:

Tidak ditentukan
[]
[[Let's Get Back Together, NEGARA], [Starting Again, ROCK]]
[[Not About The Guitar, BLUES]]
[]
[]

Berikut adalah rencana eksekusi:

Operator hasil serialisasi

Operator hasil serialisasi membuat hasil yang berisi, untuk setiap baris tabel Singers, array pasangan SongName dan SongGenre untuk lagu-lagu dari penyanyi tersebut.

Urutkan

Operator sort membaca baris input, mengurutkannya berdasarkan kolom, lalu menampilkan hasil yang telah diurutkan.

Misalnya, menggunakan kueri ini:

SELECT s.songgenre
FROM   songs AS s
ORDER  BY songgenre;

Berikut hasilnya:

SongGenre
BLUES
BLUES
BLUES
BLUES
KLASIK
NEGARA
ROCK
ROCK
ROCK

Berikut adalah rencana eksekusi:

operator pengurutan

Dalam rencana eksekusi ini, operator pengurutan menerima baris inputnya dari operator gabungan terdistribusi, mengurutkan baris input, dan menampilkan baris yang diurutkan ke operator hasil serialisasi.

Untuk membatasi jumlah baris yang ditampilkan, operator pengurutan dapat secara opsional 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 hasilnya:

SongGenre
BLUES
BLUES
BLUES

Berikut adalah rencana eksekusi:

operator pengurutan dengan batas

Rencana eksekusi menampilkan 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 dapat menerapkan pemetaan dan menampilkan jumlah baris yang sama dengan input. Hal 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 hasilnya:

Genre SongName
Negara Bukan Tentang Gitar
Rock Kedua Kalinya
Pop Mulai Lagi
Pop Tidak Ada yang Sama
Negara Mari Kita Kembali Bersama
Pop I Knew You Were Magic
Elektronik Biru
Rock 42
Rock Fight Story

Berikut adalah rencana eksekusi:

operator tvf

Input gabungan

Operator input gabungan menampilkan hasil ke operator gabungan semua. Lihat operator gabungan semua untuk contoh operator input gabungan dalam rencana eksekusi.

Operator biner

Operator binary adalah operator yang memiliki dua turunan relasional. Operator berikut adalah operator biner:

Menerapkan 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 gabungan hash . Operator cross apply memiliki dua input, input dan map. Operator penerapan silang menerapkan setiap baris di sisi input ke sisi peta. Hasil penerapan silang 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 hanya salah satu lagu penyanyi tersebut.

Berikut hasilnya:

FirstName Tidak ditentukan
Alice Bukan Tentang Gitar
Catalina Mari Kita Kembali Bersama
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 berisi NULL.

Berikut adalah rencana eksekusi:

operator penerapan silang

Node tingkat teratas adalah operator gabungan terdistribusi. Operator gabungan terdistribusi mendistribusikan sub-rencana ke server jarak jauh. Subplan berisi operator serialize result yang menghitung nama depan penyanyi dan nama salah satu lagu penyanyi tersebut, lalu men-serialize setiap baris output.

Operator hasil serialisasi menerima inputnya dari operator lintas penerapan. Sisi input untuk operator penerapan silang adalah pemindaian tabel pada tabel Singers.

Sisi peta untuk operasi lintas penerapan berisi hal berikut (dari atas ke bawah):

  • Operator aggregate 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 dengan SingerId.) Operator gabungan terdistribusi di bagian atas rencana eksekusi kemudian menggabungkan semua baris output dari server jarak jauh dan menampilkannya sebagai hasil kueri.

Gabungan hash

Operator hash join adalah implementasi berbasis hash dari gabungan SQL. Gabungan hash mengeksekusi pemrosesan berbasis set. Operator hash join membaca baris dari input yang ditandai sebagai build dan memasukkannya ke dalam tabel hash berdasarkan kondisi join. Operator hash join kemudian membaca baris dari input yang ditandai sebagai probe. Untuk setiap baris yang dibaca dari input probe, operator hash join mencari baris yang cocok dalam tabel hash. Operator hash join menampilkan baris yang cocok sebagai hasilnya.

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 hasilnya:

AlbumTitle SongName
Tidak Ada Hubungannya Dengan Saya Bukan Tentang Gitar
Hijau Kedua Kalinya
Hijau Mulai Lagi
Hijau Tidak Ada yang Sama
Hijau Mari Kita Kembali Bersama
Hijau I Knew You Were Magic
Hijau Biru
Hijau 42
Ketakutan Kisah Pertarungan

Berikut adalah rencana eksekusi:

operator hash join

Dalam rencana eksekusi, build adalah gabungan 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 hash join membaca semua baris dari sisi probe. Untuk setiap baris probe, operator hash join mencari kecocokan dalam tabel hash. Hasil kecocokan ditampilkan oleh operator gabungan hash.

Kecocokan yang dihasilkan dalam tabel hash juga dapat difilter berdasarkan kondisi residual sebelum ditampilkan. (Contoh kondisi residual muncul dalam gabungan non-persamaan). Rencana eksekusi gabungan hash bisa jadi rumit karena pengelolaan memori dan varian gabungan. Algoritma hash join utama diadaptasi untuk menangani varian gabungan dalam, semi, anti, dan luar.

Gabungkan gabungan

Operator merge join adalah implementasi gabungan SQL berbasis penggabungan. Kedua sisi join menghasilkan baris yang diurutkan berdasarkan kolom yang digunakan dalam kondisi join. Penggabungan gabung menggunakan kedua aliran input secara bersamaan dan menghasilkan baris saat kondisi gabung terpenuhi. Jika input awalnya tidak diurutkan sesuai kebutuhan, pengoptimal akan menambahkan operator Sort eksplisit ke rencana.

Gabungan penggabungan tidak dipilih secara otomatis oleh pengoptimal. Untuk menggunakan operator ini, tetapkan metode gabungan 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 hasilnya:

AlbumTitle SongName
Hijau Kedua Kalinya
Hijau Mulai Lagi
Hijau Tidak Ada yang Sama
Hijau Mari Kita Kembali Bersama
Hijau I Knew You Were Magic
Hijau Biru
Hijau 42
Ketakutan Fight Story
Tidak Ada Hubungannya Dengan Saya Bukan Tentang Gitar

Berikut adalah rencana eksekusi:

merge join operator_1

Dalam rencana eksekusi ini, gabungan penggabungan didistribusikan sehingga gabungan dieksekusi di tempat data berada. Hal ini juga memungkinkan penggabungan gabungan dalam contoh ini beroperasi tanpa pengenalan operator pengurutan tambahan, karena pemindaian kedua tabel sudah diurutkan berdasarkan SingerId, AlbumId, yang merupakan kondisi gabungan. Dalam rencana ini, pemindaian sisi kiri tabel Albums akan maju setiap kali SingerId, AlbumId-nya relatif lebih kecil daripada pemindaian indeks SongsBySingerAlbumSongNameDesc sisi kanan SingerId_1, AlbumId_1. Demikian pula, sisi kanan akan maju setiap kali kurang dari sisi kiri. Penggabungan ini terus menelusuri kesamaan sehingga hasil yang cocok dapat ditampilkan.

Pertimbangkan contoh penggabungan gabungan lain 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;

Hasilnya adalah sebagai berikut:

AlbumTitle SongName
Sampah Total Kedua Kalinya
Sampah Total Mulai Lagi
Sampah Total Tidak Ada yang Sama
Sampah Total Mari Kita Kembali Bersama
Sampah Total I Knew You Were Magic
Sampah Total Biru
Sampah Total 42
Sampah Total Bukan Tentang Gitar
Hijau Kedua Kalinya
Hijau Mulai Lagi
Hijau Tidak Ada yang Sama
Hijau Mari Kita Kembali Bersama
Hijau I Knew You Were Magic
Hijau Biru
Hijau 42
Hijau Bukan Tentang Gitar
Tidak Ada Hubungannya Dengan Saya Kedua Kalinya
Tidak Ada Hubungannya Dengan Saya Mulai Lagi
Tidak Ada Hubungannya Dengan Saya Tidak Ada yang Sama
Tidak Ada Hubungannya Dengan Saya Mari Kita Kembali Bersama
Tidak Ada Hubungannya Dengan Saya I Knew You Were Magic
Tidak Ada Hubungannya Dengan Saya Biru
Tidak Ada Hubungannya Dengan Saya 42
Tidak Ada Hubungannya Dengan Saya Bukan Tentang Gitar
Putar Kedua Kalinya
Putar Mulai Lagi
Putar Tidak Ada yang Sama
Putar Mari Kita Kembali Bersama
Putar I Knew You Were Magic
Putar Biru
Putar 42
Putar Bukan Tentang Gitar
Ketakutan Kisah Pertarungan

Berikut adalah rencana eksekusi:

merge join operator_2

Dalam rencana eksekusi sebelumnya, operator Sort tambahan telah diperkenalkan oleh pengoptimal kueri untuk mencapai properti yang diperlukan agar penggabungan gabungan 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, sehingga pengurutan dapat terjadi secara lokal, bukan global, yang mendistribusikan dan memparalelkan biaya CPU.

Hasil kecocokan juga dapat difilter berdasarkan kondisi residual sebelum ditampilkan. (Contoh tempat kondisi residual muncul adalah dalam gabungan non-persamaan). Rencana eksekusi gabungan penggabungan dapat menjadi rumit karena persyaratan pengurutan tambahan. Algoritma gabungan penggabungan utama disesuaikan untuk menangani varian gabungan dalam, semi, anti, dan luar.

Hash join siaran push

Operator push broadcast hash join adalah implementasi gabungan SQL berbasis hash-join terdistribusi. Operator gabungan hash siaran push membaca baris dari sisi input untuk membuat batch data. Batch tersebut kemudian disiarkan ke semua server yang berisi data sisi peta. Di server tujuan tempat batch data diterima, gabungan hash dibuat menggunakan batch sebagai data sisi pembuatan dan data lokal kemudian dipindai sebagai sisi pemeriksaan gabungan hash.

Push broadcast hash join tidak dipilih secara otomatis oleh pengoptimal. Untuk menggunakan operator ini, tetapkan metode gabungan 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 hasilnya:

AlbumTitle SongName
Hijau Kedua Kalinya
Hijau Mulai Lagi
Hijau Tidak Ada yang Sama
Hijau Mari Kita Kembali Bersama
Hijau I Knew You Were Magic
Hijau Biru
Hijau 42
Ketakutan Fight Story
Tidak Ada Hubungannya Dengan Saya Bukan Tentang Gitar

Berikut adalah rencana eksekusi:

Operator push_broadcast hash_join

Input untuk gabungan hash 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 dibangun menjadi tabel hash. Tabel hash kemudian menggunakan data indeks lokal sebagai probe yang menampilkan kecocokan yang dihasilkan.

Hasil kecocokan juga dapat difilter berdasarkan kondisi residual sebelum ditampilkan. (Contoh tempat kondisi residual muncul adalah dalam gabungan non-persamaan).

Penerapan luar

Operator outer apply mirip dengan operator cross apply, kecuali operator outer apply memastikan bahwa setiap eksekusi di sisi peta menampilkan setidaknya satu baris dengan menghasilkan baris NULL-padded jika diperlukan. (Dengan kata lain, ini memberikan semantik left outer join.)

Gabungan rekursif

Operator recursive union melakukan gabungan dua input, satu yang merepresentasikan kasus base, dan yang lainnya merepresentasikan kasus recursive. Fungsi ini digunakan dalam kueri grafik dengan traversal jalur yang dikuantifikasi. Input dasar diproses terlebih dahulu dan tepat satu kali. Input rekursif diproses hingga rekursi berakhir. Rekursi berakhir saat batas atas, jika ditentukan, tercapai, 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 gabungan rekursif

Operator recursive union memfilter tabel Singers untuk menemukan penyanyi dengan SingerId yang diberikan. Ini adalah input dasar untuk gabungan rekursif. Input rekursif ke gabungan rekursif terdiri dari penerapan silang terdistribusi atau operator gabungan lainnya untuk kueri lain yang berulang kali menggabungkan tabel Collaborations dengan hasil iterasi gabungan sebelumnya. Baris dari input dasar membentuk iterasi nol. Pada setiap iterasi, output iterasi disimpan oleh pemindaian spul rekursif. Baris dari recursive spool scan digabungkan dengan tabel Collaborations pada spoolscan.featuredSingerId = Collaborations.SingerId. Rekursi berakhir saat dua iterasi selesai, karena itulah 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:

Gabungkan semua

Operator gabungan semua menggabungkan semua set baris turunannya tanpa menghapus duplikat. Operator gabungan menerima input dari operator input gabungan yang didistribusikan di beberapa server. Operator gabungan semua mensyaratkan bahwa 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 hasilnya:

a b
1 2
3 4
5 6

Berikut adalah rencana eksekusi:

union_all_operator

Operator gabungan semua menggabungkan baris inputnya, dan dalam contoh ini, operator tersebut mengirimkan hasil ke operator serialize result.

Kueri seperti berikut akan berhasil, karena set 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 kolom anak menggunakan jenis data yang berbeda:

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;

Berikut adalah sub-ekspresi SQL:

SELECT Count(*)
FROM   songs
WHERE  duration > 300;

Berikut hasilnya (dari kueri lengkap):

FirstName
Alice 1
Catalina 0
David 0
Lea 0
Marc 0

Berikut adalah rencana eksekusi:

operator subkueri skalar

Rencana eksekusi berisi subkueri skalar, yang ditampilkan sebagai Scalar Subquery, melalui operator aggregate.

Spanner terkadang mengonversi subkueri skalar menjadi operator lain seperti gabungan atau penerapan silang, untuk meningkatkan performa.

Misalnya, menggunakan kueri ini:

SELECT *
FROM   songs
WHERE  duration = (SELECT Max(duration)
                   FROM   songs);

Berikut adalah sub-ekspresi SQL:

SELECT MAX(Duration)
FROM Songs;

Berikut hasilnya (dari kueri lengkap):

SingerId AlbumId TrackId SongName Durasi SongGenre
2 1 6 Tidak Ada yang Sama 303 BLUES

Berikut adalah rencana eksekusi:

Operator subkueri skalar tidak ditampilkan dalam rencana

Rencana eksekusi tidak berisi subkueri skalar karena Spanner mengonversi subkueri skalar menjadi cross apply.

Subkueri array

Subkueri array mirip dengan subkueri skalar, kecuali subkueri diizinkan untuk menggunakan lebih dari satu baris input. Baris yang digunakan dikonversi menjadi array output skalar tunggal 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 Array Subquery, di atas operator gabungan terdistribusi:

operator subkueri array

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:

Operator gabungan terdistribusi adalah operator primitif yang darinya cross apply terdistribusi dan outer apply terdistribusi berasal.

Operator terdistribusi muncul dalam rencana eksekusi dengan varian union terdistribusi di atas satu atau beberapa varian union terdistribusi lokal. Varian gabungan terdistribusi melakukan distribusi jarak jauh sub-paket. Varian gabungan terdistribusi lokal berada di atas setiap pemindaian yang dilakukan untuk kueri, seperti yang ditunjukkan dalam rencana eksekusi ini:

operator terdistribusi

Varian penggabungan terdistribusi lokal memastikan eksekusi kueri yang stabil saat terjadi mulai ulang untuk batas pemisahan yang berubah secara dinamis.

Jika memungkinkan, varian gabungan terdistribusi memiliki predikat pemisahan yang menghasilkan pemangkasan pemisahan, yang berarti server jarak jauh hanya menjalankan subrencana pada pemisahan yang memenuhi predikat. Hal ini meningkatkan latensi dan performa kueri secara keseluruhan.

Gabungan terdistribusi

Operator gabungan terdistribusi secara konseptual membagi satu atau beberapa tabel menjadi beberapa pemisahan, mengevaluasi subkueri secara terpisah pada setiap pemisahan, 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 hasilnya:

SongName SongGenre
Mulai Lagi ROCK
Kedua Kalinya ROCK
Kisah Pertarungan ROCK

Berikut adalah rencana eksekusi:

operator gabungan terdistribusi

Operator gabungan terdistribusi mengirimkan subrencana ke server jarak jauh, yang melakukan pemindaian tabel di seluruh pemisahan 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 gabungan terdistribusi kemudian menampilkan hasil gabungan dari server jarak jauh sebagai hasil kueri SQL.

Gabungan penggabungan terdistribusi

Operator gabungan penggabungan terdistribusi mendistribusikan kueri di beberapa server jarak jauh. Kemudian, hasil kueri digabungkan untuk menghasilkan hasil yang diurutkan, yang dikenal sebagai penggabungan pengurutan terdistribusi.

Gabungan penggabungan terdistribusi menjalankan langkah-langkah berikut:

  1. Server root mengirimkan subkueri ke setiap server jarak jauh yang menghosting split data yang dikueri. Subkueri menyertakan petunjuk bahwa hasil diurutkan dalam urutan tertentu.

  2. Setiap server jarak jauh menjalankan subkueri pada pemisahannya, lalu mengirimkan kembali hasilnya dalam urutan yang diminta.

  3. 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 mengeksekusi di beberapa server. Sisi input DCA mengelompokkan batch baris (tidak seperti operator penerapan silang biasa, yang hanya bertindak pada satu baris input dalam satu waktu). Sisi peta DCA adalah sekumpulan operator penerapan silang 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
Tidak Ada Hubungannya Dengan Saya
Putar
Sampah Total
Hijau

Berikut adalah rencana eksekusi:

operator penerapan silang terdistribusi

Input DCA berisi pemindaian indeks pada indeks SongsBySingerAlbumSongNameDesc yang mengelompokkan baris AlbumId. Sisi peta untuk operator penerapan silang ini adalah pemindaian indeks pada indeks AlbumsByAlbumTitle, yang tunduk pada predikat AlbumId dalam baris input yang cocok dengan kunci AlbumId dalam indeks AlbumsByAlbumTitle. Pemetaan menampilkan SongName untuk nilai SingerId dalam baris input yang dikelompokkan.

Untuk meringkas proses DCA dalam 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 distributed outer apply memperluas operator outer apply dengan menjalankan beberapa server, mirip dengan cara operator distributed cross apply memperluas operator cross apply.

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:

operator penerapan luar yang didistribusikan

Menerapkan mutasi

Operator apply mutations menerapkan mutasi dari Pernyataan Manipulasi Data (DML) ke tabel. Operator ini adalah operator teratas dalam paket kueri untuk pernyataan DML.

Misalnya, menggunakan kueri ini:

DELETE FROM singers
WHERE  firstname = 'Alice';

Berikut hasilnya:

 4 rows deleted  This statement deleted 4 rows and did not return any rows.

Berikut adalah rencana eksekusi:

operator penerapan mutasi

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. 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 dikomputasi dapat menggunakan satu referensi variabel ke struct.

Untuk operasi hasil serialisasi, konstruktor struct membuat struct untuk menserialisasi hasilnya.

Misalnya, menggunakan kueri ini:

SELECT IF(TRUE, struct(1 AS A, 1 AS B), struct(2 AS A , 2 AS B)).A;

Berikut hasilnya:

A
1

Berikut adalah rencana eksekusi:

konstruktor struct

Dalam rencana eksekusi, konstruktor struct muncul di dalam operator hasil serialisasi.