Proses Kueri Spanner

Klien

Spanner mendukung kueri SQL. Berikut adalah contoh kueri:

SELECT s.SingerId, s.FirstName, s.LastName, s.SingerInfo
FROM Singers AS s
WHERE s.FirstName = @firstName;

Konstruksi @firstName adalah referensi ke parameter kueri. Anda dapat menggunakan parameter kueri di mana pun nilai literal dapat digunakan. Sebaiknya gunakan parameter dalam API terprogram. Penggunaan parameter kueri membantu menghindari serangan injeksi SQL dan kueri yang dihasilkan lebih cenderung mendapatkan manfaat dari berbagai cache sisi server. Lihat Penyimpanan ke cache, di bawah.

Parameter kueri harus terikat dengan nilai saat kueri dieksekusi. Misalnya:

Statement statement =
    Statement.newBuilder("SELECT s.SingerId...").bind("firstName").to("Jimi").build();
try (ResultSet resultSet = dbClient.singleUse().executeQuery(statement)) {
 while (resultSet.next()) {
 ...
 }
}

Setelah menerima panggilan API, Spanner akan menganalisis kueri dan parameter terikat untuk menentukan node server Spanner mana yang harus memproses kueri. Server mengirim kembali aliran baris hasil yang digunakan oleh panggilan ke ResultSet.next().

Eksekusi kueri

Eksekusi kueri dimulai dengan kedatangan permintaan "eksekusi kueri" di beberapa server Spanner. Server melakukan langkah-langkah berikut:

  • Memvalidasi permintaan
  • Mengurai teks kueri
  • Membuat aljabar kueri awal
  • Membuat algebra kueri yang dioptimalkan
  • Membuat rencana kueri yang dapat dieksekusi
  • Menjalankan rencana (memeriksa izin, membaca data, mengenkode hasil, dll.)

Diagram alir eksekusi kueri yang menampilkan klien, server root, dan server daun

Menguraikan

Parser SQL menganalisis teks kueri dan mengonversinya menjadi hierarki sintaksis abstrak. Fungsi ini mengekstrak struktur kueri dasar (SELECT … FROM … WHERE …) dan melakukan pemeriksaan sintaksis.

Aljabar

Sistem jenis Spanner dapat merepresentasikan skalar, array, struktur, dll. Aljabar kueri menentukan operator untuk pemindaian tabel, pemfilteran, pengurutan/pengelompokan, semua jenis join, agregasi, dan banyak lagi. Aljabar kueri awal dibuat dari output parser. Referensi nama kolom dalam pohon penguraian diselesaikan menggunakan skema database. Kode ini juga memeriksa error semantik (misalnya, jumlah parameter yang salah, ketidakcocokan jenis, dan sebagainya).

Langkah berikutnya ("pengoptimalan kueri") mengambil aljabar awal dan menghasilkan aljabar yang lebih optimal. Hal ini mungkin lebih sederhana, lebih efisien, atau lebih sesuai dengan kemampuan mesin eksekusi. Misalnya, aljabar awal mungkin hanya menentukan "join", sedangkan aljabar yang dioptimalkan menentukan "hash join".

Eksekusi

Rencana kueri akhir yang dapat dieksekusi dibuat dari aljabar yang ditulis ulang. Pada dasarnya, rencana yang dapat dieksekusi adalah directed acyclic graph dari "iterator". Setiap iterator mengekspos urutan nilai. Iterator dapat menggunakan input untuk menghasilkan output (misalnya, iterator pengurutan). Kueri yang melibatkan satu pemisahan dapat dijalankan oleh satu server (server yang menyimpan data). Server akan memindai rentang dari berbagai tabel, menjalankan join, melakukan agregasi, dan semua operasi lainnya yang ditentukan oleh aljabar kueri.

Kueri yang melibatkan beberapa pemisahan akan difaktorkan menjadi beberapa bagian. Beberapa bagian kueri akan terus dieksekusi di server utama (root). Subkueri parsial lainnya akan diserahkan ke node daun (node yang memiliki bagian yang dibaca). Pengalihan ini dapat diterapkan secara rekursif untuk kueri yang kompleks, sehingga menghasilkan hierarki eksekusi server. Semua server menyetujui stempel waktu sehingga hasil kueri adalah ringkasan data yang konsisten. Setiap server leaf mengirim kembali aliran hasil parsial. Untuk kueri yang melibatkan agregasi, ini dapat berupa hasil agregasi sebagian. Server root kueri memproses hasil dari server daun dan menjalankan sisa rencana kueri. Untuk mengetahui informasi selengkapnya, lihat Rencana eksekusi kueri.

Jika kueri melibatkan beberapa bagian, Spanner dapat mengeksekusi kueri secara paralel di seluruh bagian. Tingkat paralelisme bergantung pada rentang data yang dipindai kueri, rencana eksekusi kueri, dan distribusi data di seluruh bagian. Spanner secara otomatis menetapkan tingkat paralelisme maksimum untuk kueri berdasarkan ukuran instance dan konfigurasi instance (regional atau multi-region) untuk mencapai performa kueri yang optimal dan menghindari melebihi kapasitas CPU.

Menyimpan data ke dalam cache

Banyak artefak pemrosesan kueri yang otomatis di-cache dan digunakan kembali untuk kueri berikutnya. Hal ini mencakup aljabar kueri, rencana kueri yang dapat dieksekusi, dan sebagainya. Penyimpanan dalam cache didasarkan pada teks kueri, nama, dan jenis parameter terikat, dan sebagainya. Itulah sebabnya menggunakan parameter terikat (seperti @firstName dalam contoh di atas) lebih baik daripada menggunakan nilai literal dalam teks kueri. Yang pertama dapat di-cache satu kali dan digunakan kembali, terlepas dari nilai yang terikat sebenarnya. Lihat Mengoptimalkan Performa Kueri Spanner untuk mengetahui detail selengkapnya.

Penanganan error

Streaming baris hasil dari metode executeQuery dapat terganggu karena berbagai alasan: error jaringan sementara, pengalihan pemisahan dari satu server ke server lain (misalnya, load balancing), server dimulai ulang (misalnya, upgrade ke versi baru), dll. Untuk membantu memulihkan dari error ini, Spanner mengirimkan "token lanjutkan" buram bersama dengan batch data hasil parsial. Token lanjutan ini dapat digunakan saat mencoba ulang kueri untuk melanjutkan dari tempat kueri yang terganggu berhenti. Jika Anda menggunakan library klien Spanner, hal ini dilakukan secara otomatis; sehingga, pengguna library klien tidak perlu khawatir dengan jenis kegagalan sementara ini.