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. Penggunaan parameter dalam API terprogram sangat direkomendasikan. Penggunaan parameter kueri membantu menghindari serangan injeksi SQL dan kueri yang dihasilkan lebih mungkin mendapatkan manfaat dari berbagai cache sisi server. Lihat Pembuatan cache, di bawah.

Parameter kueri harus terikat dengan nilai saat kueri dijalankan. 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 yang harus memproses kueri. Server mengirimkan kembali aliran baris hasil yang digunakan oleh panggilan ke ResultSet.next().

Eksekusi kueri

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

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

Diagram alur eksekusi kueri yang menampilkan server klien, server root, dan leaf

Penguraian

Parser SQL menganalisis teks kueri dan mengonversinya menjadi pohon 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, segala jenis penggabungan, agregasi, dan banyak lagi. Aljabar kueri awal dibuat dari output parser. Referensi nama kolom di hierarki penguraian diselesaikan menggunakan skema database. Kode ini juga memeriksa error semantik (misalnya, jumlah parameter yang salah, ketidakcocokan jenis, dan sebagainya).

Langkah berikutnya ("pengoptimalan kueri") menggunakan 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 menentukan "join" saja, sedangkan aljabar yang dioptimalkan menentukan "hash join".

Eksekusi

Rencana kueri akhir yang dapat dieksekusi dibangun dari aljabar yang ditulis ulang. Pada dasarnya, rencana yang dapat dieksekusi adalah grafik asiklik terarah dari "iterator". Setiap iterator menampilkan urutan nilai. Iterator dapat menggunakan input untuk menghasilkan output (misalnya, mengurutkan iterator). Kueri yang melibatkan satu pemisahan dapat dijalankan oleh satu server (yang menyimpan data). Server akan memindai rentang dari berbagai tabel, mengeksekusi gabungan, melakukan agregasi, dan semua operasi lain yang ditentukan oleh aljabar kueri.

Kueri yang melibatkan beberapa bagian akan difaktorkan ke dalam beberapa bagian. Beberapa bagian kueri akan terus dijalankan di server utama (root). Subquery sebagian lainnya diserahkan ke node daun (yang memiliki pemisahan yang sedang dibaca). Proses serah terima ini dapat diterapkan secara berulang untuk kueri yang kompleks, sehingga menghasilkan hierarki eksekusi server. Semua server menyetujui stempel waktu sehingga hasil kueri adalah snapshot data yang konsisten. Setiap server leaf mengirimkan kembali aliran hasil parsial. Untuk kueri yang melibatkan agregasi, kueri ini dapat berupa hasil yang digabungkan sebagian. Server root kueri memproses hasil dari server leaf dan menjalankan sisa paket kueri. Untuk mengetahui informasi selengkapnya, lihat Rencana eksekusi kueri.

Jika kueri melibatkan beberapa bagian, Spanner dapat menjalankan 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-nya (regional atau multi-region) untuk mencapai performa kueri yang optimal dan menghindari overload CPU.

Menyimpan data ke dalam cache

Banyak artefak pemrosesan kueri yang secara otomatis disimpan dalam cache dan digunakan kembali untuk kueri berikutnya. Hal ini mencakup aljabar kueri, paket kueri yang dapat dieksekusi, dll. Penyimpanan 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. Sebelumnya, dapat di-cache satu kali dan digunakan kembali terlepas dari nilai terikat yang sebenarnya. Lihat Mengoptimalkan Performa Kueri Spanner untuk detail selengkapnya.

Penanganan error

Aliran baris hasil dari metode executeQuery dapat dihentikan karena sejumlah alasan: error jaringan sementara, pengalihan pemisahan dari satu server ke server lainnya (misalnya, load balancing), server dimulai ulang (misalnya, mengupgrade ke versi baru), dll. Untuk membantu memulihkan dari error ini, Spanner mengirimkan "token melanjutkan" buram bersama dengan batch data hasil sebagian. Token melanjutkan ini dapat digunakan saat mencoba kembali kueri untuk melanjutkan kueri yang terhenti. Jika Anda menggunakan library klien Spanner, proses ini dilakukan secara otomatis. Dengan demikian, pengguna library klien tidak perlu khawatir dengan jenis kegagalan sementara ini.