Ringkasan skema

Halaman ini membahas persyaratan skema Spanner, cara menggunakan skema untuk membuat hubungan hierarkis, dan fitur skema. Versi ini juga memperkenalkan tabel yang diselingi, yang dapat meningkatkan performa kueri saat membuat kueri tabel dalam hubungan induk-turunan.

Skema adalah namespace yang berisi objek database, seperti tabel, tampilan, indeks, dan fungsi. Anda menggunakan skema untuk mengatur objek, menerapkan hak istimewa kontrol akses terperinci, dan menghindari konflik penamaan. Anda harus menentukan skema untuk setiap database di Spanner.

Anda juga dapat menyegmentasikan dan menyimpan baris lebih lanjut di tabel database di seluruh wilayah geografis yang berbeda. Untuk informasi selengkapnya, lihat Ringkasan partisi geografis.

Data dengan jenis yang kuat

Data di Spanner memiliki jenis yang dikenali. Jenis data mencakup jenis skalar dan kompleks, yang dijelaskan dalam Jenis data di GoogleSQL dan Jenis data PostgreSQL.

Pilih kunci utama

Database Spanner dapat berisi satu atau beberapa tabel. Tabel disusun sebagai baris dan kolom. Skema tabel menentukan satu atau beberapa kolom tabel sebagai kunci utama tabel yang mengidentifikasi setiap baris secara unik. Kunci utama selalu diindeks untuk pencarian baris cepat. Jika Anda ingin memperbarui atau menghapus baris yang ada dalam tabel, tabel tersebut harus memiliki kunci utama. Tabel tanpa kolom kunci utama hanya dapat memiliki satu baris. Hanya database dialek GoogleSQL yang dapat memiliki tabel tanpa kunci utama.

Sering kali aplikasi Anda sudah memiliki kolom yang cocok untuk digunakan sebagai kunci utama. Misalnya, untuk tabel Customers, mungkin ada CustomerId yang disediakan aplikasi yang berfungsi dengan baik sebagai kunci utama. Dalam kasus lain, Anda mungkin perlu membuat kunci utama saat menyisipkan baris. Nilai ini biasanya berupa nilai bilangan bulat unik tanpa signifikansi bisnis (kunci utama pengganti).

Dalam semua kasus, Anda harus berhati-hati agar tidak membuat hotspot dengan pilihan kunci utama. Misalnya, jika Anda menyisipkan data dengan bilangan bulat yang meningkat secara monoton sebagai kunci, Anda akan selalu menyisipkan di akhir ruang kunci. Hal ini tidak diinginkan karena Spanner membagi data di antara server berdasarkan rentang kunci, yang berarti penyisipan Anda akan diarahkan ke satu server, sehingga membuat hotspot. Ada teknik yang dapat menyebarkan beban di beberapa server dan menghindari hotspot:

  • Lakukan hashing pada kunci, lalu simpan di kolom. Gunakan kolom hash (atau kolom hash dan kolom kunci unik secara bersamaan) sebagai kunci utama.
  • Tukar urutan kolom dalam kunci utama.
  • Gunakan ID Unik Universal (UUID). UUID versi 4 direkomendasikan, karena menggunakan nilai acak dalam bit urutan tinggi. Jangan gunakan algoritma UUID (seperti UUID versi 1) yang menyimpan stempel waktu dalam bit urutan tinggi.
  • Lakukan bit-reverse pada nilai berurutan.

Hubungan tabel induk-turunan

Ada dua cara untuk menentukan hubungan induk-turunan di Spanner: interleave tabel dan kunci asing.

Interleaving tabel Spanner adalah pilihan yang tepat untuk banyak hubungan induk-turunan. Dengan interleaving, Spanner secara fisik meletakkan baris turunan dengan baris induk dalam penyimpanan. Lokasi yang sama dapat meningkatkan performa secara signifikan. Misalnya, jika Anda memiliki tabel Customers dan tabel Invoices, dan aplikasi Anda sering mengambil semua invoice untuk pelanggan, Anda dapat menentukan Invoices sebagai tabel turunan yang diselingi dari Customers. Dengan demikian, Anda mendeklarasikan hubungan lokalitas data antara dua tabel independen. Anda memberi tahu Spanner untuk menyimpan satu atau beberapa baris Invoices dengan satu baris Customers.

Anda mengaitkan tabel turunan dengan tabel induk menggunakan DDL yang mendeklarasikan tabel turunan sebagai sisipan di induk, dan dengan menyertakan kunci utama tabel induk sebagai bagian pertama dari kunci utama gabungan tabel turunan. Untuk informasi selengkapnya tentang interleaving, lihat Membuat tabel interleaved nanti di halaman ini.

Kunci asing adalah solusi induk-turunan yang lebih umum dan menangani kasus penggunaan tambahan. Tabel tidak terbatas pada kolom kunci utama, dan tabel dapat memiliki beberapa hubungan kunci asing, baik sebagai induk dalam beberapa hubungan maupun turunan dalam hubungan lainnya. Namun, hubungan kunci asing tidak menyiratkan lokasi yang sama untuk tabel di lapisan penyimpanan.

Google merekomendasikan agar Anda memilih untuk mewakili hubungan induk-turunan sebagai tabel interleave atau sebagai kunci asing, tetapi tidak keduanya. Untuk informasi selengkapnya tentang kunci asing dan perbandingannya dengan tabel yang diselingi, lihat Ringkasan kunci asing.

Kunci utama dalam tabel sisipan

Untuk interleaving, setiap tabel harus memiliki kunci utama. Jika Anda mendeklarasikan tabel menjadi turunan yang diselingi dari tabel lain, tabel harus memiliki kunci utama komposit yang menyertakan semua komponen kunci utama induk, dalam urutan yang sama, dan, biasanya, satu atau beberapa kolom tabel turunan tambahan.

Spanner menyimpan baris dalam urutan yang diurutkan berdasarkan nilai kunci utama, dengan baris turunan disisipkan di antara baris induk. Lihat ilustrasi baris sisipan di Membuat tabel sisipan nanti di halaman ini.

Singkatnya, Spanner dapat menempatkan baris tabel terkait secara fisik di tempat yang sama. Contoh skema menunjukkan tampilan tata letak fisik ini.

Pemisahan database

Anda dapat menentukan hierarki hubungan induk-turunan yang saling tumpang-tindih hingga tujuh lapisan, yang berarti Anda dapat menempatkan baris dari tujuh tabel independen secara berdampingan. Jika ukuran data dalam tabel Anda kecil, satu server Spanner mungkin dapat menangani database Anda. Namun, apa yang terjadi jika tabel terkait Anda bertambah dan mulai mencapai batas resource server individual? Spanner adalah database terdistribusi, yang berarti bahwa seiring berkembangnya database, Spanner membagi data Anda menjadi beberapa bagian yang disebut "bagian". Setiap bagian dapat berpindah secara independen dari satu sama lain dan ditetapkan ke server yang berbeda, yang dapat berada di lokasi fisik yang berbeda. Pemisahan menyimpan rentang baris yang berdekatan. Kunci awal dan akhir rentang ini disebut "batas pemisahan". Spanner secara otomatis menambahkan dan menghapus batas pemisahan berdasarkan ukuran dan beban, yang mengubah jumlah pemisahan dalam database.

Pembagian berbasis beban

Sebagai contoh cara Spanner melakukan pemisahan berbasis beban untuk memitigasi hotspot baca, misalkan database Anda berisi tabel dengan 10 baris yang lebih sering dibaca daripada semua baris lain dalam tabel. Spanner dapat menambahkan batas pemisahan di antara setiap 10 baris tersebut sehingga setiap baris ditangani oleh server yang berbeda, bukan mengizinkan semua pembacaan baris tersebut menggunakan resource satu server.

Sebagai aturan umum, jika Anda mengikuti praktik terbaik untuk desain skema, Spanner dapat mengurangi hotspot sehingga throughput baca akan meningkat setiap beberapa menit hingga Anda memenuhi resource di instance atau mengalami kasus saat tidak ada batas pemisahan baru yang dapat ditambahkan (karena Anda memiliki pemisahan yang hanya mencakup satu baris tanpa turunan yang diselingi).

Skema bernama

Skema bernama membantu Anda mengatur data serupa secara bersamaan. Hal ini membantu Anda menemukan objek dengan cepat di konsol Google Cloud, menerapkan hak istimewa, dan menghindari konflik penamaan.

Skema bernama, seperti objek database lainnya, dikelola menggunakan DDL.

Skema bernama Spanner memungkinkan Anda menggunakan nama yang sepenuhnya memenuhi syarat (FQN) untuk membuat kueri data. FQN memungkinkan Anda menggabungkan nama skema dan nama objek untuk mengidentifikasi objek database. Misalnya, Anda dapat membuat skema yang disebut warehouse untuk unit bisnis gudang. Tabel yang menggunakan skema ini dapat mencakup: product, order, dan customer information. Atau, Anda dapat membuat skema bernama fulfillment untuk unit bisnis fulfillment. Skema ini juga dapat memiliki tabel yang disebut product, order, dan customer information. Pada contoh pertama, FQN adalah warehouse.product dan pada contoh kedua, FQN adalah fulfillment.product. Hal ini mencegah kebingungan dalam situasi saat beberapa objek memiliki nama yang sama.

Dalam DDL CREATE SCHEMA, objek tabel diberi FQN, misalnya, sales.customers, dan nama singkat, misalnya, sales.

Objek database berikut mendukung skema bernama:

  • TABLE
    • CREATE
    • INTERLEAVE IN [PARENT]
    • FOREIGN KEY
    • SYNONYM
  • VIEW
  • INDEX
  • FOREIGN KEY
  • SEQUENCE

Untuk mengetahui informasi selengkapnya tentang penggunaan skema bernama, lihat Mengelola skema bernama.

Menggunakan kontrol akses yang sangat terperinci dengan skema bernama

Skema bernama memungkinkan Anda memberikan akses tingkat skema ke setiap objek dalam skema. Hal ini berlaku untuk objek skema yang ada pada saat Anda memberikan akses. Anda harus memberikan akses ke objek yang ditambahkan nanti.

Kontrol akses terperinci membatasi akses ke seluruh grup objek database, seperti tabel, kolom, dan baris dalam tabel.

Untuk informasi selengkapnya, lihat Memberikan hak istimewa kontrol akses terperinci ke skema bernama.

Contoh skema

Contoh skema di bagian ini menunjukkan cara membuat tabel induk dan turunan dengan dan tanpa interleaving, serta mengilustrasikan tata letak fisik data yang sesuai.

Membuat tabel induk

Misalnya, Anda membuat aplikasi musik dan memerlukan tabel yang menyimpan baris data penyanyi:

Tabel penyanyi dengan lima baris dan empat kolom

Perhatikan bahwa tabel berisi satu kolom kunci utama, SingerId, yang muncul di sebelah kiri baris yang dicetak tebal, dan tabel diatur berdasarkan baris dan kolom.

Anda dapat menentukan tabel dengan DDL berikut:

GoogleSQL

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

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

Perhatikan hal-hal berikut tentang contoh skema:

  • Singers adalah tabel di root hierarki database (karena tidak ditentukan sebagai turunan yang diselingi dari tabel lain).
  • Untuk database dialek GoogleSQL, kolom kunci utama biasanya dianotasi dengan NOT NULL (meskipun Anda dapat menghapus anotasi ini jika ingin mengizinkan nilai NULL di kolom kunci. Untuk informasi selengkapnya, lihat Kolom Kunci).
  • Kolom yang tidak disertakan dalam kunci utama disebut kolom non-kunci, dan dapat memiliki anotasi NOT NULL opsional.
  • Kolom yang menggunakan jenis STRING atau BYTES di GoogleSQL harus ditentukan dengan panjang, yang mewakili jumlah maksimum karakter Unicode yang dapat disimpan di kolom. Spesifikasi panjang bersifat opsional untuk jenis PostgreSQL varchar dan character varying. Untuk informasi selengkapnya, lihat Jenis Data Skalar untuk database dialek GoogleSQL dan jenis data PostgreSQL untuk database dialek PostgreSQL.

Seperti apa tata letak fisik baris dalam tabel Singers? Diagram berikut menunjukkan baris tabel Singers yang disimpan oleh kunci utama ("Singers(1)", lalu "Singers(2)", dengan angka dalam tanda kurung adalah nilai kunci utama.

Contoh baris tabel yang disimpan dalam urutan kunci utama

Diagram sebelumnya mengilustrasikan contoh batas pemisahan antara baris yang diberi kunci oleh Singers(3) dan Singers(4), dengan data dari pemisahan yang dihasilkan ditetapkan ke server yang berbeda. Seiring bertambahnya tabel ini, baris data Singers dapat disimpan di lokasi yang berbeda.

Membuat tabel induk dan turunan

Anggaplah sekarang Anda ingin menambahkan beberapa data dasar tentang album setiap penyanyi ke aplikasi musik.

Tabel Album dengan lima baris dan tiga kolom

Perhatikan bahwa kunci utama Albums terdiri dari dua kolom: SingerId dan AlbumId, untuk mengaitkan setiap album dengan penyanyinya. Contoh skema berikut menentukan tabel Albums dan Singers di root hierarki database, yang menjadikannya tabel saudara.

-- Schema hierarchy:
-- + Singers (sibling table of Albums)
-- + Albums (sibling table of Singers)

GoogleSQL

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

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

PostgreSQL

CREATE TABLE singers (
singer_id   BIGINT PRIMARY KEY,
first_name  VARCHAR(1024),
last_name   VARCHAR(1024),
singer_info BYTEA
);

CREATE TABLE albums (
singer_id     BIGINT,
album_id      BIGINT,
album_title   VARCHAR,
PRIMARY KEY (singer_id, album_id)
);

Tata letak fisik baris Singers dan Albums terlihat seperti diagram berikut, dengan baris tabel Albums yang disimpan oleh kunci utama yang berdekatan, lalu baris Singers yang disimpan oleh kunci utama yang berdekatan:

Tata letak fisik baris

Satu catatan penting tentang skema adalah Spanner tidak mengasumsikan hubungan lokalitas data antara tabel Singers dan Albums, karena tabel tersebut adalah tabel tingkat teratas. Seiring berkembangnya database, Spanner dapat menambahkan batas pemisahan di antara baris mana pun. Artinya, baris tabel Albums dapat berakhir dalam pemisahan yang berbeda dari baris tabel Singers, dan kedua pemisahan tersebut dapat bergerak secara independen satu sama lain.

Bergantung pada kebutuhan aplikasi Anda, Anda dapat mengizinkan data Albums berada di bagian yang berbeda dari data Singers. Namun, hal ini dapat menimbulkan dampak negatif pada performa karena perlunya mengoordinasikan pembacaan dan pembaruan di seluruh resource yang berbeda. Jika aplikasi Anda sering kali perlu mengambil informasi tentang semua album untuk penyanyi tertentu, Anda harus membuat Albums sebagai tabel turunan interleaved dari Singers, yang menempatkan baris dari dua tabel di sepanjang dimensi kunci utama. Contoh berikutnya menjelaskan hal ini secara lebih mendetail.

Membuat tabel sisipan

Tabel sisipan adalah tabel yang Anda deklarasikan sebagai turunan sisipan dari tabel lain karena Anda ingin baris tabel turunan disimpan secara fisik dengan baris induk terkait. Seperti yang disebutkan sebelumnya, kunci utama tabel induk harus menjadi bagian pertama dari kunci utama gabungan tabel turunan.

Setelah Anda menyisipkan tabel, tabel tersebut akan diubah secara permanen. Anda tidak dapat mengurungkan interleaving. Sebagai gantinya, Anda perlu membuat tabel lagi dan memigrasikan data ke tabel tersebut.

Saat mendesain aplikasi musik, Anda menyadari bahwa aplikasi harus sering mengakses baris dari tabel Albums saat mengakses baris Singers. Misalnya, saat mengakses baris Singers(1), Anda juga perlu mengakses baris Albums(1, 1) dan Albums(1, 2). Dalam hal ini, Singers dan Albums harus memiliki hubungan lokalitas data yang kuat. Anda dapat mendeklarasikan hubungan lokalitas data ini dengan membuat Albums sebagai tabel turunan interleaved dari Singers.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)

Baris yang dicetak tebal dalam skema berikut menunjukkan cara membuat Albums sebagai tabel interleaved Singers.

GoogleSQL

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

CREATE TABLE Albums (
 SingerId     INT64 NOT NULL,
 AlbumId      INT64 NOT NULL,
 AlbumTitle   STRING(MAX),
 ) PRIMARY KEY (SingerId, AlbumId),
INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

Catatan tentang skema ini:

  • SingerId, yang merupakan bagian pertama dari kunci utama tabel turunan Albums, juga merupakan kunci utama tabel induknya Singers.
  • Anotasi ON DELETE CASCADE menandakan bahwa saat baris dari tabel induk dihapus, baris turunannya juga akan otomatis dihapus. Jika tabel turunan tidak memiliki anotasi ini, atau anotasi adalah ON DELETE NO ACTION, Anda harus menghapus baris turunan sebelum dapat menghapus baris induk.
  • Baris yang disisipkan diurutkan terlebih dahulu berdasarkan baris tabel induk, lalu berdasarkan baris yang berdekatan dari tabel turunan yang memiliki kunci utama induk. Misalnya, "Penyanyi(1)", lalu "Album(1, 1)", lalu "Album(1, 2)".
  • Hubungan lokalitas data setiap penyanyi dan data albumnya akan dipertahankan jika database ini terpecah, asalkan ukuran baris Singers dan semua baris Albums-nya tetap di bawah batas ukuran pemisahan dan tidak ada hotspot di salah satu baris Albums ini.
  • Baris induk harus ada sebelum Anda dapat menyisipkan baris turunan. Baris induk dapat sudah ada di database atau dapat disisipkan sebelum penyisipan baris turunan dalam transaksi yang sama.

Baris Album diselingi di antara baris Penyanyi

Membuat hierarki tabel yang diselang-seling

Hubungan induk-turunan antara Singers dan Albums dapat diperluas ke tabel turunan lainnya. Misalnya, Anda dapat membuat tabel interleaved yang disebut Songs sebagai turunan dari Albums untuk menyimpan daftar lagu setiap album:

Tabel lagu dengan enam baris dan empat kolom

Songs harus memiliki kunci utama yang menyertakan semua kunci utama tabel yang berada di tingkat yang lebih tinggi dalam hierarki, yaitu SingerId dan AlbumId.

-- Schema hierarchy:
-- + Singers
--   + Albums (interleaved table, child table of Singers)
--     + Songs (interleaved table, child table of Albums)

GoogleSQL

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

CREATE TABLE Albums (
 SingerId     INT64 NOT NULL,
 AlbumId      INT64 NOT NULL,
 AlbumTitle   STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId),
 INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

CREATE TABLE Songs (
 SingerId     INT64 NOT NULL,
 AlbumId      INT64 NOT NULL,
 TrackId      INT64 NOT NULL,
 SongName     STRING(MAX),
) PRIMARY KEY (SingerId, AlbumId, TrackId),
 INTERLEAVE IN PARENT Albums ON DELETE CASCADE;

PostgreSQL

CREATE TABLE singers (
 singer_id   BIGINT PRIMARY KEY,
 first_name  VARCHAR(1024),
 last_name   VARCHAR(1024),
 singer_info BYTEA
 );

CREATE TABLE albums (
 singer_id     BIGINT,
 album_id      BIGINT,
 album_title   VARCHAR,
 PRIMARY KEY (singer_id, album_id)
 )
 INTERLEAVE IN PARENT singers ON DELETE CASCADE;

CREATE TABLE songs (
 singer_id     BIGINT,
 album_id      BIGINT,
 track_id      BIGINT,
 song_name     VARCHAR,
 PRIMARY KEY (singer_id, album_id, track_id)
 )
 INTERLEAVE IN PARENT albums ON DELETE CASCADE;

Diagram berikut menunjukkan tampilan fisik baris yang diselingi.

Lagu diselingi dalam Album, yang diselingi di antara Penyanyi

Dalam contoh ini, seiring bertambahnya jumlah penyanyi, Spanner menambahkan batas pemisahan antara penyanyi untuk mempertahankan lokalitas data antara penyanyi dan data album dan lagunya. Namun, jika ukuran baris penyanyi dan baris turunannya melebihi batas ukuran pemisahan, atau hotspot terdeteksi di baris turunan, Spanner akan mencoba menambahkan batas pemisahan untuk mengisolasi baris hotspot tersebut beserta semua baris turunan di bawahnya.

Singkatnya, tabel induk beserta semua tabel turunan dan turunannya membentuk hierarki tabel dalam skema. Meskipun setiap tabel dalam hierarki bersifat independen secara logis, secara fisik menyisipkan tabel dengan cara ini dapat meningkatkan performa, yang secara efektif menggabungkan tabel dan memungkinkan Anda mengakses baris terkait secara bersamaan sekaligus meminimalkan akses penyimpanan.

Gabungan dengan tabel sisipan

Jika memungkinkan, gabungkan data dalam tabel yang diselingi berdasarkan kunci utama. Karena setiap baris yang diselingi biasanya disimpan secara fisik dalam bagian yang sama dengan baris induk, Spanner dapat melakukan join berdasarkan kunci utama secara lokal, sehingga meminimalkan akses penyimpanan dan traffic jaringan. Dalam contoh berikut, Singers dan Albums digabungkan pada kunci utama SingerId.

GoogleSQL

SELECT s.FirstName, a.AlbumTitle
FROM Singers AS s JOIN Albums AS a ON s.SingerId = a.SingerId;

PostgreSQL

SELECT s.first_name, a.album_title
FROM singers AS s JOIN albums AS a ON s.singer_id = a.singer_id;

Kolom utama

Bagian ini mencakup beberapa catatan tentang kolom utama.

Mengubah kunci tabel

Kunci tabel tidak dapat berubah; Anda tidak dapat menambahkan kolom kunci ke tabel yang ada atau menghapus kolom kunci dari tabel yang ada.

Menyimpan NULL dalam kunci utama

Di GoogleSQL, jika Anda ingin menyimpan NULL di kolom kunci utama, hapus klausa NOT NULL untuk kolom tersebut dalam skema. (Database dialek PostgreSQL tidak mendukung NULL di kolom kunci utama.)

Berikut adalah contoh penghapusan klausa NOT NULL pada kolom kunci utama SingerId. Perhatikan bahwa karena SingerId adalah kunci utama, hanya boleh ada satu baris yang menyimpan NULL di kolom tersebut.

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

Properti nullable kolom kunci utama harus cocok antara deklarasi tabel induk dan turunan. Dalam contoh ini, NOT NULL untuk kolom Albums.SingerId tidak diizinkan karena Singers.SingerId menghapusnya.

CREATE TABLE Singers (
  SingerId   INT64,
  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),
  INTERLEAVE IN PARENT Singers ON DELETE CASCADE;

Jenis yang tidak diizinkan

Kolom berikut tidak boleh berjenis ARRAY:

  • Kolom kunci tabel.
  • Kolom kunci indeks.

Mendesain untuk multi-tenancy

Anda mungkin ingin menerapkan multi-tenancy jika menyimpan data milik pelanggan yang berbeda. Misalnya, layanan musik mungkin ingin menyimpan setiap konten label rekaman secara terpisah.

Multi-tenancy klasik

Cara klasik untuk mendesain multi-tenancy adalah dengan membuat database terpisah untuk setiap pelanggan. Dalam contoh ini, setiap database memiliki tabel Singers-nya sendiri:

Database 1: Ackworth Records
SingerId FirstName LastName
1MarcRichards
2CatalinaSmith
Database 2: Cama Records
SingerId FirstName LastName
1AliceTrentor
2GabrielWright
Database 3: Eagan Records
SingerId FirstName LastName
1BenjaminMartinez
2HannahHarris

Multi-tenancy yang dikelola skema

Cara lain untuk mendesain multi-tenancy di Spanner adalah dengan menempatkan semua pelanggan dalam satu tabel dalam satu database, dan menggunakan nilai kunci utama yang berbeda untuk setiap pelanggan. Misalnya, Anda dapat menyertakan kolom kunci CustomerId dalam tabel. Jika Anda menjadikan CustomerId sebagai kolom kunci pertama, data untuk setiap pelanggan akan memiliki lokalitas yang baik. Spanner kemudian dapat menggunakan pemisahan database secara efektif untuk memaksimalkan performa berdasarkan ukuran data dan pola beban. Dalam contoh berikut, ada satu tabel Singers untuk semua pelanggan:

Database multi-tenancy Spanner
CustomerId SingerId FirstName LastName
11MarcRichards
12CatalinaSmith
21AliceTrentor
22GabrielWright
31BenjaminMartinez
32HannahHarris

Jika Anda harus memiliki database terpisah untuk setiap tenant, ada batasan yang harus diperhatikan:

  • Ada batasan jumlah database per instance dan jumlah tabel dan indeks per database. Bergantung pada jumlah pelanggan, Anda mungkin tidak dapat memiliki database atau tabel terpisah.
  • Menambahkan tabel baru dan indeks non-interleaved dapat memerlukan waktu yang lama. Anda mungkin tidak dapat mendapatkan performa yang diinginkan jika desain skema Anda bergantung pada penambahan tabel dan indeks baru.

Jika ingin membuat database terpisah, Anda mungkin akan lebih berhasil jika mendistribusikan tabel ke seluruh database sedemikian rupa sehingga setiap database memiliki jumlah perubahan skema yang rendah per minggu.

Jika Anda membuat tabel dan indeks terpisah untuk setiap pelanggan aplikasi, jangan tempatkan semua tabel dan indeks dalam database yang sama. Sebagai gantinya, bagi data tersebut ke banyak database, untuk mengurangi masalah performa dengan membuat banyak indeks.

Untuk mempelajari lebih lanjut pola pengelolaan data dan desain aplikasi lainnya untuk multi-tenancy, lihat Menerapkan Multi-Tenancy di Spanner