Membuat pembaruan skema

Spanner memungkinkan Anda membuat pembaruan skema tanpa periode nonaktif. Anda dapat memperbarui skema database yang ada dengan beberapa cara:

Pembaruan skema yang didukung

Spanner mendukung pembaruan skema berikut dari database yang ada:

  • Menambahkan atau menghapus skema bernama.
  • Buat tabel baru. Kolom dalam tabel baru dapat berupa NOT NULL.
  • Menghapus tabel, jika tidak ada tabel lain yang diselingi di dalamnya, dan tidak memiliki indeks sekunder.
  • Membuat atau menghapus tabel dengan kunci asing.
  • Menambahkan atau menghapus kunci asing dari tabel yang ada.
  • Menambahkan kolom non-kunci ke tabel mana pun. Kolom non-kunci baru tidak boleh NOT NULL.
  • Hapus kolom non-kunci dari tabel apa pun, kecuali jika digunakan oleh indeks sekunder, kunci asing, kolom yang dihasilkan dan disimpan, atau periksa batasan.
  • Tambahkan NOT NULL ke kolom non-kunci, tidak termasuk kolom ARRAY.
  • Hapus NOT NULL dari kolom non-kunci.
  • Ubah kolom STRING menjadi kolom BYTES atau kolom BYTES menjadi kolom STRING.
  • Ubah kolom PROTO menjadi kolom BYTES atau kolom BYTES menjadi kolom PROTO.
  • Mengubah jenis pesan proto kolom PROTO.
  • Tambahkan nilai baru ke definisi ENUM dan ganti nama nilai yang ada menggunakan ALTER PROTO BUNDLE.
  • Ubah pesan yang ditentukan dalam PROTO BUNDLE dengan cara arbitrer, asalkan kolom yang diubah dari pesan tersebut tidak digunakan sebagai kunci dalam tabel apa pun dan data yang ada memenuhi batasan baru.
  • Meningkatkan atau menurunkan batas panjang untuk jenis STRING atau BYTES (termasuk ke MAX), kecuali jika merupakan kolom kunci utama yang diwarisi oleh satu atau beberapa tabel turunan.
  • Tingkatkan atau turunkan batas panjang untuk kolom ARRAY<STRING>, ARRAY<BYTES>, atau ARRAY<PROTO> ke maksimum yang diizinkan.
  • Aktifkan atau nonaktifkan stempel waktu commit di kolom nilai dan kunci utama.
  • Menambahkan atau menghapus indeks sekunder.
  • Menambahkan atau menghapus batasan pemeriksaan dari tabel yang ada.
  • Menambahkan atau menghapus kolom yang dihasilkan dan disimpan dari tabel yang ada.
  • Buat paket statistik pengoptimal baru.
  • Membuat dan mengelola tampilan.
  • Membuat dan mengelola urutan.
  • Membuat peran database dan memberikan hak istimewa.
  • Menetapkan, mengubah, atau menghapus nilai default kolom.
  • Ubah opsi database (misalnya, default_leader atau version_retention_period).
  • Membuat dan mengelola aliran perubahan.
  • Membuat dan mengelola model ML.

Pembaruan skema yang tidak didukung

Spanner tidak mendukung pembaruan skema berikut dari database yang ada:

  • Jika ada kolom PROTO dari jenis ENUM yang direferensikan oleh kunci tabel atau indeks, Anda tidak dapat menghapus nilai ENUM dari enum proto. (Penghapusan nilai ENUM dari enum yang digunakan oleh kolom ENUM<> didukung, termasuk saat kolom tersebut digunakan sebagai kunci.)

Performa pembaruan skema

Pembaruan skema di Spanner tidak memerlukan periode nonaktif. Saat menerbitkan kumpulan pernyataan DDL ke database Spanner, Anda dapat terus menulis dan membaca dari database tanpa gangguan saat Spanner menerapkan update sebagai operasi yang berjalan lama.

Waktu yang diperlukan untuk mengeksekusi pernyataan DDL bergantung pada apakah pembaruan memerlukan validasi data yang ada atau pengisian ulang data apa pun. Misalnya, jika Anda menambahkan anotasi NOT NULL ke kolom yang ada, Spanner harus membaca semua nilai dalam kolom untuk memastikan bahwa kolom tidak berisi nilai NULL apa pun. Langkah ini dapat memerlukan waktu lama jika ada banyak data yang akan divalidasi. Contoh lainnya adalah jika Anda menambahkan indeks ke database: Spanner mengisi ulang indeks menggunakan data yang ada, dan proses tersebut dapat memerlukan waktu lama, bergantung pada definisi indeks dan ukuran tabel dasar yang sesuai. Namun, jika Anda menambahkan kolom baru ke tabel, tidak ada data yang ada untuk divalidasi, sehingga Spanner dapat melakukan update dengan lebih cepat.

Singkatnya, pembaruan skema yang tidak memerlukan Spanner untuk memvalidasi data yang ada dapat dilakukan dalam hitungan menit. Pembaruan skema yang memerlukan validasi dapat memerlukan waktu lebih lama, bergantung pada jumlah data yang ada yang perlu divalidasi, tetapi validasi data terjadi di latar belakang dengan prioritas yang lebih rendah daripada traffic produksi. Pembaruan skema yang memerlukan validasi data akan dibahas secara lebih mendetail di bagian berikutnya.

Pembaruan skema divalidasi berdasarkan definisi tampilan

Saat Anda melakukan pembaruan skema, Spanner memvalidasi bahwa pembaruan tersebut tidak akan membatalkan validasi kueri yang digunakan untuk menentukan tampilan yang ada. Jika validasi berhasil, update skema akan berhasil. Jika validasi tidak berhasil, update skema akan gagal. Lihat Praktik terbaik saat membuat tampilan untuk mengetahui detailnya.

Pembaruan skema yang memerlukan validasi data

Anda dapat melakukan pembaruan skema yang memerlukan validasi bahwa data yang ada memenuhi batasan baru. Jika update skema memerlukan validasi data, Spanner tidak mengizinkan update skema yang bertentangan ke entitas skema yang terpengaruh dan memvalidasi data di latar belakang. Jika validasi berhasil, update skema akan berhasil. Jika validasi tidak berhasil, update skema tidak akan berhasil. Operasi validasi dijalankan sebagai operasi yang berjalan lama. Anda dapat memeriksa status operasi ini untuk menentukan apakah operasi berhasil atau gagal.

Misalnya, Anda telah menentukan file music.proto berikut dengan enum RecordLabel dan pesan protokol Songwriter:

  enum RecordLabel {
    COOL_MUSIC_INC = 0;
    PACIFIC_ENTERTAINMENT = 1;
    XYZ_RECORDS = 2;
  }

  message Songwriter {
    required string nationality   = 1;
    optional int64  year_of_birth = 2;
  }

Untuk menambahkan tabel Songwriters dalam skema Anda:

GoogleSQL

CREATE PROTO BUNDLE (
  googlesql.example.music.Songwriter,
  googlesql.example.music.RecordLabel,
);

CREATE TABLE Songwriters (
  Id         INT64 NOT NULL,
  FirstName  STRING(1024),
  LastName   STRING(1024),
  Nickname   STRING(MAX),
  OpaqueData BYTES(MAX),
  SongWriter googlesql.example.music.Songwriter
) PRIMARY KEY (Id);

CREATE TABLE Albums (
  SongwriterId     INT64 NOT NULL,
  AlbumId          INT64 NOT NULL,
  AlbumTitle       STRING(MAX),
  Label            INT32
) PRIMARY KEY (SongwriterId, AlbumId);

Update skema berikut diizinkan, tetapi memerlukan validasi dan mungkin memerlukan waktu lebih lama untuk diselesaikan, bergantung pada jumlah data yang ada:

  • Menambahkan anotasi NOT NULL ke kolom non-kunci. Contoh:

    ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL;
    
  • Mengurangi panjang kolom. Contoh:

    ALTER TABLE Songwriters ALTER COLUMN FirstName STRING(10);
    
  • Mengubah dari BYTES menjadi STRING. Contoh:

    ALTER TABLE Songwriters ALTER COLUMN OpaqueData STRING(MAX);
    
  • Mengubah dari INT64/INT32 menjadi ENUM. Contoh:

    ALTER TABLE Albums ALTER COLUMN Label googlesql.example.music.RecordLabel;
    
  • Menghapus nilai yang ada dari definisi enum RecordLabel.

  • Mengaktifkan stempel waktu commit di kolom TIMESTAMP yang ada. Contoh:

    ALTER TABLE Albums ALTER COLUMN LastUpdateTime SET OPTIONS (allow_commit_timestamp = true);
    
  • Menambahkan batasan pemeriksaan ke tabel yang ada.

  • Menambahkan kolom yang dihasilkan dan disimpan ke tabel yang ada.

  • Membuat tabel baru dengan kunci asing.

  • Menambahkan kunci asing ke tabel yang ada.

Update skema ini akan gagal jika data pokok tidak memenuhi batasan baru. Misalnya, pernyataan ALTER TABLE Songwriters ALTER COLUMN Nickname STRING(MAX) NOT NULL gagal jika nilai apa pun di kolom Nickname adalah NULL, karena data yang ada tidak memenuhi batasan NOT NULL definisi baru.

Validasi data dapat memerlukan waktu beberapa menit hingga beberapa jam. Waktu untuk menyelesaikan validasi data bergantung pada:

  • Ukuran set data
  • Kapasitas komputasi instance
  • Beban pada instance

Beberapa update skema dapat mengubah perilaku permintaan ke database sebelum update skema selesai. Misalnya, jika Anda menambahkan NOT NULL ke kolom, Spanner hampir segera mulai menolak operasi tulis untuk permintaan baru yang menggunakan NULL untuk kolom tersebut. Jika update skema baru pada akhirnya gagal untuk validasi data, akan ada periode waktu saat operasi tulis diblokir, meskipun operasi tersebut akan diterima oleh skema lama.

Anda dapat membatalkan operasi validasi data yang berjalan lama menggunakan metode projects.instances.databases.operations.cancel atau menggunakan gcloud spanner operations.

Urutan eksekusi pernyataan dalam batch

Jika menggunakan Google Cloud CLI, REST API, atau RPC API, Anda dapat mengeluarkan batch satu atau beberapa pernyataan CREATE, ALTER, atau DROP.

Spanner menerapkan pernyataan dari batch yang sama secara berurutan, berhenti pada error pertama. Jika penerapan pernyataan menghasilkan error, pernyataan tersebut akan di-roll back. Hasil pernyataan yang diterapkan sebelumnya dalam batch tidak di-rollback.

Spanner dapat menggabungkan dan mengurutkan ulang pernyataan dari batch yang berbeda, yang berpotensi menggabungkan pernyataan dari batch yang berbeda menjadi satu perubahan atomik yang diterapkan ke database. Dalam setiap perubahan atomik, pernyataan dari berbagai batch terjadi dalam urutan arbitrer. Misalnya, jika satu batch pernyataan berisi ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(50) dan batch pernyataan lainnya berisi ALTER TABLE MyTable ALTER COLUMN MyColumn STRING(20), Spanner akan membiarkan kolom tersebut dalam salah satu dari dua status tersebut, tetapi tidak ditentukan mana yang akan digunakan.

Versi skema yang dibuat selama pembaruan skema

Spanner menggunakan pembuatan versi skema sehingga tidak ada periode nonaktif selama pembaruan skema ke database besar. Spanner mempertahankan versi skema lama untuk mendukung operasi baca saat pembaruan skema diproses. Spanner kemudian membuat satu atau beberapa versi baru skema untuk memproses update skema. Setiap versi berisi hasil kumpulan pernyataan dalam satu perubahan atomik.

Versi skema tidak selalu sesuai satu per satu dengan batch pernyataan DDL atau pernyataan DDL individual. Beberapa pernyataan DDL individual, seperti pembuatan indeks untuk tabel dasar yang ada atau pernyataan yang memerlukan validasi data, menghasilkan beberapa versi skema. Dalam kasus lain, beberapa pernyataan DDL dapat dikelompokkan dalam satu versi. Versi skema lama dapat menggunakan resource server dan penyimpanan yang signifikan, dan versi tersebut dipertahankan hingga masa berlakunya habis (tidak lagi diperlukan untuk menayangkan pembacaan data versi sebelumnya).

Tabel berikut menunjukkan waktu yang diperlukan Spanner untuk memperbarui skema.

Operasi skema Estimasi durasi
CREATE TABLE Menit
CREATE INDEX

Menit hingga jam, jika tabel dasar dibuat sebelum indeks.

Menit, jika pernyataan dieksekusi secara bersamaan dengan pernyataan CREATE TABLE untuk tabel dasar.

DROP TABLE Menit
DROP INDEX Menit
ALTER TABLE ... ADD COLUMN Menit
ALTER TABLE ... ALTER COLUMN

Menit hingga jam, jika validasi latar belakang diperlukan.

Menit, jika validasi latar belakang tidak diperlukan.

ALTER TABLE ... DROP COLUMN Menit
ANALYZE

Beberapa menit hingga beberapa jam, bergantung pada ukuran database.

Perubahan jenis data dan aliran perubahan

Jika Anda mengubah jenis data kolom yang dipantau oleh aliran perubahan, kolom column_types dari data aliran perubahan berikutnya yang relevan akan mencerminkan jenis barunya, begitu juga dengan data JSON old_values dalam kolom mods data.

new_values dari kolom mods data aliran perubahan selalu cocok dengan jenis kolom saat ini. Mengubah jenis data kolom yang dipantau tidak akan memengaruhi data aliran perubahan apa pun yang terjadi sebelum perubahan tersebut.

Dalam kasus khusus perubahan BYTES-ke-STRING, Spanner memvalidasi nilai lama kolom sebagai bagian dari pembaruan skema. Akibatnya, Spanner telah mendekode nilai jenis BYTES lama menjadi string dengan aman pada saat menulis data stream perubahan berikutnya.

Praktik terbaik untuk pembaruan skema

Bagian berikut menjelaskan praktik terbaik untuk memperbarui skema.

Prosedur sebelum Anda mengeluarkan pembaruan skema

Sebelum Anda mengeluarkan update skema:

  • Pastikan semua data yang ada dalam database yang Anda ubah memenuhi batasan yang diterapkan oleh pembaruan skema. Karena keberhasilan beberapa jenis update skema bergantung pada data dalam database, bukan hanya skema saat ini, update skema yang berhasil pada database pengujian tidak menjamin update skema yang berhasil pada database produksi. Berikut beberapa contoh umum:

    • Jika Anda menambahkan anotasi NOT NULL ke kolom yang ada, pastikan kolom tidak berisi nilai NULL yang ada.
    • Jika Anda mempersingkat panjang kolom STRING atau BYTES yang diizinkan, pastikan semua nilai yang ada di kolom tersebut memenuhi batasan panjang.
  • Jika Anda menulis ke kolom, tabel, atau indeks yang sedang mengalami pembaruan skema, pastikan nilai yang Anda tulis memenuhi batasan baru.

  • Jika Anda menghapus kolom, tabel, atau indeks, pastikan Anda tidak sedang menulis ke atau membaca dari kolom, tabel, atau indeks tersebut.

Membatasi frekuensi pembaruan skema

Jika Anda melakukan terlalu banyak pembaruan skema dalam jangka waktu yang singkat, Spanner dapat throttle pemrosesan pembaruan skema yang diantrekan. Hal ini karena Spanner membatasi jumlah ruang untuk menyimpan versi skema. Update skema Anda mungkin dibatasi jika ada terlalu banyak versi skema lama dalam periode retensi. Rasio maksimum perubahan skema bergantung pada banyak faktor, salah satunya adalah jumlah total kolom dalam database. Misalnya, database dengan 2.000 kolom (sekitar 2.000 baris di INFORMATION_SCHEMA.COLUMNS) dapat melakukan maksimal 1.500 perubahan skema (lebih sedikit jika perubahan skema memerlukan beberapa versi) dalam periode retensi. Untuk melihat status update skema yang sedang berlangsung, gunakan perintah gcloud spanner operations list dan filter menurut operasi jenis DATABASE_UPDATE_DDL. Untuk membatalkan update skema yang sedang berlangsung, gunakan perintah gcloud spanner operations cancel dan tentukan ID operasi.

Cara pernyataan DDL Anda dikelompokkan, dan urutannya dalam setiap batch, dapat memengaruhi jumlah versi skema yang dihasilkan. Untuk memaksimalkan jumlah update skema yang dapat Anda lakukan selama jangka waktu tertentu, Anda harus menggunakan pengelompokan yang meminimalkan jumlah versi skema. Beberapa aturan umum dijelaskan dalam update besar.

Seperti yang dijelaskan dalam versi skema, beberapa pernyataan DDL akan membuat beberapa versi skema, dan versi ini penting saat mempertimbangkan pengelompokan dan urutan dalam setiap batch. Ada dua jenis pernyataan utama yang dapat membuat beberapa versi skema:

  • Pernyataan yang mungkin perlu mengisi ulang data indeks, seperti CREATE INDEX
  • Pernyataan yang mungkin perlu memvalidasi data yang ada, seperti menambahkan NOT NULL

Namun, jenis pernyataan ini tidak selalu membuat beberapa versi skema. Spanner akan mencoba mendeteksi kapan jenis pernyataan ini dapat dioptimalkan untuk menghindari penggunaan beberapa versi skema, yang bergantung pada pengelompokan. Misalnya, pernyataan CREATE INDEX yang terjadi dalam batch yang sama dengan pernyataan CREATE TABLE untuk tabel dasar indeks, tanpa pernyataan intervensi untuk tabel lain, dapat menghindari perlunya mengisi ulang data indeks karena Spanner dapat menjamin bahwa tabel dasar kosong pada saat indeks dibuat. Bagian update besar menjelaskan cara menggunakan properti ini untuk membuat banyak indeks secara efisien.

Jika tidak dapat mengelompokkan pernyataan DDL untuk menghindari pembuatan banyak versi skema, Anda harus membatasi jumlah pembaruan skema ke skema database tunggal dalam periode retensinya. Tingkatkan periode waktu saat Anda melakukan pembaruan skema agar Spanner dapat menghapus versi skema sebelumnya sebelum versi baru dibuat.

  • Untuk beberapa sistem pengelolaan database relasional, ada paket software yang membuat serangkaian panjang update skema upgrade dan downgrade ke database pada setiap deployment produksi. Jenis proses ini tidak direkomendasikan untuk Spanner.
  • Spanner dioptimalkan untuk menggunakan kunci utama guna mempartisi data untuk solusi multi-tenancy. Solusi multi-tenancy yang menggunakan tabel terpisah untuk setiap pelanggan dapat menghasilkan backlog besar terkait operasi pembaruan skema yang memerlukan waktu lama untuk selesai.
  • Update skema yang memerlukan validasi atau pengisian ulang indeks menggunakan lebih banyak resource server karena setiap pernyataan membuat beberapa versi skema secara internal.

Opsi untuk pembaruan skema besar

Cara terbaik untuk membuat tabel dan sejumlah besar indeks pada tabel tersebut adalah dengan membuat semuanya secara bersamaan, sehingga hanya akan ada satu versi skema yang dibuat. Praktik terbaiknya adalah membuat indeks segera setelah tabel dalam daftar pernyataan DDL. Anda dapat membuat tabel dan indeksnya saat membuat database, atau dalam satu kumpulan pernyataan besar. Jika perlu membuat banyak tabel, masing-masing dengan banyak indeks, Anda dapat menyertakan semua pernyataan dalam satu batch. Anda dapat menyertakan beberapa ribu pernyataan dalam satu batch jika semua pernyataan dapat dijalankan bersama menggunakan satu versi skema.

Jika memerlukan pengisian ulang data indeks atau melakukan validasi data, pernyataan tersebut tidak dapat dijalankan dalam satu versi skema. Hal ini terjadi untuk pernyataan CREATE INDEX saat tabel dasar indeks sudah ada (baik karena dibuat dalam batch pernyataan DDL sebelumnya, atau karena ada pernyataan dalam batch antara pernyataan CREATE TABLE dan CREATE INDEX yang memerlukan beberapa versi skema). Spanner mengharuskan tidak ada lebih dari 10 pernyataan tersebut dalam satu batch. Pembuatan indeks yang memerlukan pengisian ulang, khususnya, menggunakan beberapa versi skema per indeks, sehingga sebaiknya buat tidak lebih dari 3 indeks baru yang memerlukan pengisian ulang per hari (terlepas dari cara pengelompokannya, kecuali jika pengelompokan tersebut dapat menghindari pengisian ulang).

Misalnya, kumpulan pernyataan ini akan menggunakan satu versi skema:

GoogleSQL

CREATE TABLE Singers (
SingerId   INT64 NOT NULL,
FirstName  STRING(1024),
LastName   STRING(1024),
) PRIMARY KEY (SingerId);

CREATE INDEX SingersByFirstName ON Singers(FirstName);

CREATE INDEX SingersByLastName ON Singers(LastName);

CREATE TABLE Albums (
SingerId   INT64 NOT NULL,
AlbumId    INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId);

CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);

Sebaliknya, batch ini akan menggunakan banyak versi skema, karena UnrelatedIndex memerlukan pengisian ulang (karena tabel dasarnya harus sudah ada), dan hal itu memaksa semua indeks berikut juga memerlukan pengisian ulang (meskipun berada dalam batch yang sama dengan tabel dasarnya):

GoogleSQL

CREATE TABLE Singers (
SingerId   INT64 NOT NULL,
FirstName  STRING(1024),
LastName   STRING(1024),
) PRIMARY KEY (SingerId);

CREATE TABLE Albums (
SingerId   INT64 NOT NULL,
AlbumId    INT64 NOT NULL,
AlbumTitle STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId);

CREATE INDEX UnrelatedIndex ON UnrelatedTable(UnrelatedIndexKey);

CREATE INDEX SingersByFirstName ON Singers(FirstName);

CREATE INDEX SingersByLastName ON Singers(LastName);

CREATE INDEX AlbumsByTitle ON Albums(AlbumTitle);

Sebaiknya pindahkan pembuatan UnrelatedIndex ke akhir batch, atau ke batch lain, untuk meminimalkan versi skema.

Menunggu permintaan API selesai

Saat membuat permintaan projects.instances.databases.updateDdl (REST API) atau UpdateDatabaseDdl (RPC API), gunakan projects.instances.databases.operations.get (REST API) atau GetOperation (RPC API) untuk menunggu setiap permintaan selesai sebelum memulai permintaan baru. Menunggu setiap permintaan selesai memungkinkan aplikasi Anda melacak progres update skema. Hal ini juga menjaga backlog pembaruan skema yang tertunda agar tetap dalam ukuran yang dapat dikelola.

Pemuatan massal

Jika Anda memuat data secara massal ke tabel setelah dibuat, biasanya lebih efisien untuk membuat indeks setelah data dimuat. Jika Anda menambahkan beberapa indeks, sebaiknya buat database dengan semua tabel dan indeks dalam skema awal, seperti yang dijelaskan dalam opsi untuk update besar.