Dalam database Spanner, Spanner otomatis membuat
indeks untuk setiap kunci utama tabel. Misalnya, Anda tidak perlu melakukan apa pun untuk mengindeks kunci utama Singers
, karena kunci tersebut diindeks secara otomatis untuk Anda.
Anda juga dapat membuat indeks sekunder untuk kolom lain. Menambahkan indeks sekunder pada kolom akan membuat pencarian data di kolom tersebut menjadi lebih efisien. Misalnya, jika Anda perlu mencari album dengan cepat berdasarkan judul, Anda harus
membuat indeks sekunder di AlbumTitle
,
sehingga Spanner tidak perlu memindai seluruh tabel.
Jika pencarian dalam contoh sebelumnya dilakukan dalam transaksi baca-tulis,
pencarian yang lebih efisien juga akan menghindari penahanan kunci di seluruh tabel,
yang memungkinkan penyisipan dan pembaruan serentak ke tabel untuk baris di luar
rentang pencarian AlbumTitle
.
Selain manfaat yang diberikannya untuk pencarian, indeks sekunder juga dapat membantu Spanner menjalankan pemindaian secara lebih efisien, sehingga memungkinkan pemindaian indeks, bukan pemindaian tabel penuh.
Spanner menyimpan data berikut di setiap indeks sekunder:
- Semua kolom kunci dari tabel dasar
- Semua kolom yang disertakan dalam indeks
- Semua kolom yang ditentukan dalam klausa
STORING
(database dialek GoogleSQL) atau klausaINCLUDE
(database dialek PostgreSQL) opsional dari definisi indeks.
Seiring waktu, Spanner akan menganalisis tabel Anda untuk memastikan bahwa indeks sekunder Anda digunakan untuk kueri yang sesuai.
Menambahkan indeks sekunder
Waktu yang paling efisien untuk menambahkan indeks sekunder adalah saat Anda membuat tabel. Untuk membuat tabel dan indeksnya secara bersamaan, kirim pernyataan DDL untuk tabel baru dan indeks baru dalam satu permintaan ke Spanner.
Di Spanner, Anda juga dapat menambahkan indeks sekunder baru ke tabel yang ada saat database terus menyalurkan traffic. Seperti perubahan skema lainnya di Spanner, menambahkan indeks ke database yang ada tidak mengharuskan database offline dan tidak mengunci seluruh kolom atau tabel.
Setiap kali indeks baru ditambahkan ke tabel yang ada, Spanner akan otomatis mengisi ulang, atau mengisi, indeks untuk mencerminkan tampilan terbaru data yang diindeks. Spanner mengelola proses pengisian ulang ini untuk Anda, dan proses ini berjalan di latar belakang menggunakan resource node dengan prioritas rendah. Dalam sebagian besar kasus, proses ini tidak dapat dipercepat (misalnya, dengan menambahkan lebih banyak node), dan pengisian ulang tidak memengaruhi performa database secara signifikan.
Pembuatan indeks dapat memerlukan waktu dari beberapa menit hingga beberapa jam. Karena pembuatan indeks adalah update skema, pembuatan indeks terikat oleh batasan performa yang sama seperti update skema lainnya. Waktu yang diperlukan untuk membuat indeks sekunder bergantung pada beberapa faktor:
- Ukuran set data
- Kapasitas komputasi instance
- Beban pada instance
Untuk melihat progres yang dibuat untuk proses pengisian ulang indeks, lihat bagian progres.
Perhatikan bahwa penggunaan kolom stempel waktu commit sebagai bagian pertama dari indeks sekunder dapat membuat hotspot dan mengurangi performa operasi tulis.
Gunakan pernyataan CREATE INDEX
untuk menentukan indeks sekunder
dalam skema Anda. Berikut beberapa contohnya:
Untuk mengindeks semua Singers
dalam database berdasarkan nama depan dan nama belakangnya:
GoogleSQL
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
PostgreSQL
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
Untuk membuat indeks semua Songs
dalam database berdasarkan nilai SongName
:
GoogleSQL
CREATE INDEX SongsBySongName ON Songs(SongName);
PostgreSQL
CREATE INDEX SongsBySongName ON Songs(SongName);
Untuk mengindeks hanya lagu untuk penyanyi tertentu, gunakan
klausa INTERLEAVE IN
untuk menyisipkan indeks dalam
tabel Singers
:
GoogleSQL
CREATE INDEX SongsBySingerSongName ON Songs(SingerId, SongName),
INTERLEAVE IN Singers;
PostgreSQL
CREATE INDEX SongsBySingerSongName ON Songs(SingerId, SongName)
INTERLEAVE IN Singers;
Untuk mengindeks hanya lagu di album tertentu:
GoogleSQL
CREATE INDEX SongsBySingerAlbumSongName ON Songs(SingerId, AlbumId, SongName),
INTERLEAVE IN Albums;
PostgreSQL
CREATE INDEX SongsBySingerAlbumSongName ON Songs(SingerId, AlbumId, SongName)
INTERLEAVE IN Albums;
Untuk mengindeks menurut urutan menurun SongName
:
GoogleSQL
CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC),
INTERLEAVE IN Albums;
PostgreSQL
CREATE INDEX SongsBySingerAlbumSongNameDesc ON Songs(SingerId, AlbumId, SongName DESC)
INTERLEAVE IN Albums;
Perhatikan bahwa anotasi DESC
sebelumnya hanya berlaku untuk SongName
. Untuk mengindeks menurut
urutan menurun kunci indeks lainnya, beri anotasi dengan DESC
juga:
SingerId DESC, AlbumId DESC
.
Perhatikan juga bahwa PRIMARY_KEY
adalah kata khusus untuk sistem dan tidak dapat digunakan sebagai nama
indeks. Ini adalah nama yang diberikan ke pseudo-indeks
yang dibuat saat tabel dengan spesifikasi PRIMARY KEY dibuat
Untuk mengetahui detail selengkapnya dan praktik terbaik dalam memilih indeks non-sisipan dan indeks sisipan, lihat Opsi indeks dan Menggunakan indeks sisipan pada kolom yang nilainya meningkat atau menurun secara monoton.
Memeriksa progres pengisian ulang indeks
Konsol
Di menu navigasi Spanner, klik tab Operations. Halaman Operasi menampilkan daftar operasi yang sedang berjalan.
Temukan operasi pengisian ulang dalam daftar. Jika masih berjalan, indikator progres di kolom Waktu berakhir akan menampilkan persentase operasi yang sudah selesai, seperti yang ditunjukkan pada gambar berikut:
gcloud
Gunakan gcloud spanner operations describe
untuk memeriksa progres operasi.
Mendapatkan ID operasi:
gcloud spanner operations list --instance=INSTANCE-NAME \ --database=DATABASE-NAME --type=DATABASE_UPDATE_DDL
Ganti kode berikut:
- INSTANCE-NAME dengan nama instance Spanner.
- DATABASE-NAME dengan nama database.
Catatan penggunaan:
Untuk membatasi daftar, tentukan flag
--filter
. Contoh:--filter="metadata.name:example-db"
hanya mencantumkan operasi di database tertentu.--filter="error:*"
hanya mencantumkan operasi pencadangan yang gagal.
Untuk informasi tentang sintaksis filter, lihat filter topik gcloud. Untuk informasi tentang cara memfilter operasi pencadangan, lihat kolom
filter
di ListBackupOperationsRequest.Flag
--type
tidak peka huruf besar/kecil.
Outputnya terlihat mirip dengan yang berikut ini:
OPERATION_ID STATEMENTS DONE @TYPE _auto_op_123456 CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName) False UpdateDatabaseDdlMetadata CREATE INDEX SongsBySingerAlbumSongName ON Songs(SingerId, AlbumId, SongName), INTERLEAVE IN Albums _auto_op_234567 True CreateDatabaseMetadata
Jalankan
gcloud spanner operations describe
:gcloud spanner operations describe \ --instance=INSTANCE-NAME \ --database=DATABASE-NAME \ projects/PROJECT-NAME/instances/INSTANCE-NAME/databases/DATABASE-NAME/operations/OPERATION_ID
Ganti kode berikut:
- INSTANCE-NAME: Nama instance Spanner.
- DATABASE-NAME: Nama database Spanner.
- PROJECT-NAME: Nama project.
- OPERATION-ID: ID operasi dari operasi yang ingin Anda periksa.
Bagian
progress
dalam output menunjukkan persentase operasi yang telah selesai. Output-nya terlihat mirip dengan berikut ini:done: true ... progress: - endTime: '2021-01-22T21:58:42.912540Z' progressPercent: 100 startTime: '2021-01-22T21:58:11.053996Z' - progressPercent: 67 startTime: '2021-01-22T21:58:11.053996Z' ...
REST v1
Mendapatkan ID operasi:
gcloud spanner operations list --instance=INSTANCE-NAME
--database=DATABASE-NAME --type=DATABASE_UPDATE_DDL
Ganti kode berikut:
- INSTANCE-NAME dengan nama instance Spanner.
- DATABASE-NAME dengan nama database.
Sebelum menggunakan salah satu data permintaan, lakukan penggantian berikut:
- PROJECT-ID: project ID.
- INSTANCE-ID: ID instance.
- DATABASE-ID: ID database.
- OPERATION-ID: ID operasi.
Metode HTTP dan URL:
GET https://spanner.googleapis.com/v1/projects/PROJECT-ID/instances/INSTANCE-ID/databases/DATABASE-ID/operations/OPERATION-ID
Untuk mengirim permintaan, perluas salah satu opsi berikut:
Anda akan melihat respons JSON seperti berikut:
{ ... "progress": [ { "progressPercent": 100, "startTime": "2023-05-27T00:52:27.366688Z", "endTime": "2023-05-27T00:52:30.184845Z" }, { "progressPercent": 100, "startTime": "2023-05-27T00:52:30.184845Z", "endTime": "2023-05-27T00:52:40.750959Z" } ], ... "done": true, "response": { "@type": "type.googleapis.com/google.protobuf.Empty" } }
Untuk gcloud
dan REST, Anda dapat menemukan progres setiap pernyataan pengisian ulang indeks di bagian progress
. Untuk setiap pernyataan dalam array pernyataan,
ada kolom yang sesuai dalam array progres. Urutan array progres ini
sesuai dengan urutan array pernyataan. Setelah tersedia, kolom startTime
, progressPercent
, dan endTime
akan diisi sebagaimana mestinya.
Perhatikan bahwa output tidak menampilkan perkiraan waktu saat progres pengisian ulang akan selesai.
Jika operasi membutuhkan waktu terlalu lama, Anda dapat membatalkannya. Untuk mengetahui informasi selengkapnya, lihat Membatalkan pembuatan indeks.
Skenario saat melihat progres pengisian ulang indeks
Ada berbagai skenario yang dapat Anda temui saat mencoba memeriksa progres pengisian ulang indeks. Pernyataan pembuatan indeks yang memerlukan pengisian ulang indeks adalah bagian dari operasi pembaruan skema, dan mungkin ada beberapa pernyataan yang merupakan bagian dari operasi pembaruan skema.
Skenario pertama adalah yang paling sederhana, yaitu saat pernyataan pembuatan indeks
adalah pernyataan pertama dalam operasi pembaruan skema. Karena pernyataan pembuatan indeks
adalah pernyataan pertama, pernyataan ini adalah yang pertama diproses dan dijalankan karena
urutan eksekusi.
Kolom startTime
dari pernyataan pembuatan indeks akan langsung diisi dengan waktu mulai operasi pembaruan skema. Selanjutnya, kolom progressPercent
pernyataan pembuatan indeks diisi saat progres pengisian ulang indeks lebih dari 0%. Terakhir, kolom endTime
diisi setelah
pernyataan di-commit.
Skenario kedua adalah saat pernyataan pembuatan indeks bukan pernyataan
pertama dalam operasi pembaruan skema. Tidak ada kolom yang terkait dengan pernyataan pembuatan indeks yang akan diisi hingga pernyataan sebelumnya telah di-commit karena urutan eksekusi.
Serupa dengan skenario sebelumnya, setelah pernyataan sebelumnya di-commit, kolom startTime
dari pernyataan pembuatan indeks akan diisi terlebih dahulu, diikuti dengan
kolom progressPercent
. Terakhir, kolom endTime
akan terisi setelah
pernyataan selesai di-commit.
Membatalkan pembuatan indeks
Anda dapat menggunakan Google Cloud CLI untuk membatalkan pembuatan indeks. Untuk mengambil daftar operasi pembaruan skema untuk database Spanner, gunakan perintah gcloud spanner operations list
, dan sertakan opsi --filter
:
gcloud spanner operations list \
--instance=INSTANCE \
--database=DATABASE \
--filter="@TYPE:UpdateDatabaseDdlMetadata"
Temukan OPERATION_ID
untuk operasi yang ingin Anda batalkan, lalu gunakan perintah gcloud spanner operations cancel
untuk membatalkannya:
gcloud spanner operations cancel OPERATION_ID \
--instance=INSTANCE \
--database=DATABASE
Melihat indeks yang ada
Untuk melihat informasi tentang indeks yang ada dalam database, Anda dapat menggunakan konsol Google Cloud atau Google Cloud CLI:
Konsol
Buka halaman Instance Spanner di konsol Google Cloud.
Klik nama instance yang ingin Anda lihat.
Di panel kiri, klik database yang ingin Anda lihat, lalu klik tabel yang ingin Anda lihat.
Klik tab Indeks. Konsol Google Cloud menampilkan daftar indeks.
Opsional: Untuk mendapatkan detail tentang indeks, seperti kolom yang disertakan, klik nama indeks.
gcloud
Gunakan perintah gcloud spanner databases ddl describe
:
gcloud spanner databases ddl describe DATABASE \
--instance=INSTANCE
CLI gcloud mencetak pernyataan Data Definition Language (DDL) untuk membuat tabel dan indeks database. Pernyataan CREATE
INDEX
menjelaskan indeks yang ada. Misalnya:
--- |-
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
FirstName STRING(1024),
LastName STRING(1024),
SingerInfo BYTES(MAX),
) PRIMARY KEY(SingerId)
---
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName)
Membuat kueri dengan indeks tertentu
Bagian berikut menjelaskan cara menentukan indeks dalam pernyataan SQL dan
dengan antarmuka baca untuk Spanner. Contoh di bagian ini mengasumsikan bahwa Anda menambahkan kolom MarketingBudget
ke tabel Albums
dan membuat indeks bernama AlbumsByAlbumTitle
:
GoogleSQL
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);
PostgreSQL
CREATE TABLE Albums (
SingerId BIGINT NOT NULL,
AlbumId BIGINT NOT NULL,
AlbumTitle VARCHAR,
MarketingBudget BIGINT,
PRIMARY KEY (SingerId, AlbumId)
) INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);
Menentukan indeks dalam pernyataan SQL
Saat Anda menggunakan SQL untuk membuat kueri tabel Spanner, Spanner akan otomatis
menggunakan indeks yang cenderung membuat kueri lebih efisien. Akibatnya,
Anda tidak perlu menentukan indeks untuk kueri SQL. Namun,
untuk kueri yang penting bagi beban kerja Anda, Google menyarankan Anda untuk menggunakan
perintah FORCE_INDEX
dalam pernyataan SQL untuk performa yang lebih konsisten.
Dalam beberapa kasus, Spanner mungkin memilih indeks yang menyebabkan latensi kueri meningkat. Jika telah mengikuti langkah-langkah pemecahan masalah untuk regresi performa dan mengonfirmasi bahwa sebaiknya coba indeks lain untuk kueri, Anda dapat menentukan indeks sebagai bagian dari kueri.
Untuk menentukan indeks dalam pernyataan SQL, gunakan petunjuk FORCE_INDEX
untuk memberikan perintah indeks. Direktif indeks menggunakan sintaksis berikut:
GoogleSQL
FROM MyTable@{FORCE_INDEX=MyTableIndex}
PostgreSQL
FROM MyTable /*@ FORCE_INDEX = MyTableIndex */
Anda juga dapat menggunakan perintah indeks untuk memberi tahu Spanner agar memindai tabel dasar, bukan menggunakan indeks:
GoogleSQL
FROM MyTable@{FORCE_INDEX=_BASE_TABLE}
PostgreSQL
FROM MyTable /*@ FORCE_INDEX = _BASE_TABLE */
Contoh berikut menunjukkan kueri SQL yang menentukan indeks:
GoogleSQL
SELECT AlbumId, AlbumTitle, MarketingBudget
FROM Albums@{FORCE_INDEX=AlbumsByAlbumTitle}
WHERE AlbumTitle >= "Aardvark" AND AlbumTitle < "Goo";
PostgreSQL
SELECT AlbumId, AlbumTitle, MarketingBudget
FROM Albums /*@ FORCE_INDEX = AlbumsByAlbumTitle */
WHERE AlbumTitle >= 'Aardvark' AND AlbumTitle < 'Goo';
Perintah indeks dapat memaksa pemroses kueri Spanner untuk membaca
kolom tambahan yang diperlukan oleh kueri, tetapi tidak disimpan dalam indeks.
Pemroses kueri mengambil kolom ini dengan menggabungkan indeks dan tabel dasar. Untuk menghindari join tambahan ini, gunakan
klausa STORING
(database dialek GoogleSQL) atau klausa INCLUDE
(database dialek PostgreSQL) untuk
menyimpan kolom tambahan dalam indeks.
Pada contoh sebelumnya, kolom MarketingBudget
tidak
disimpan dalam indeks, tetapi kueri SQL memilih kolom ini. Akibatnya,
Spanner harus mencari kolom MarketingBudget
di tabel dasar,
lalu menggabungkannya dengan data dari indeks, untuk menampilkan hasil kueri.
Spanner akan memunculkan error jika perintah indeks memiliki salah satu masalah berikut:
- Indeks tidak ada.
- Indeks berada di tabel dasar yang berbeda.
- Kueri tidak memiliki ekspresi pemfilteran
NULL
yang diperlukan untuk indeksNULL_FILTERED
.
Contoh berikut menunjukkan cara menulis dan menjalankan kueri yang mengambil nilai AlbumId
, AlbumTitle
, dan MarketingBudget
menggunakan indeks AlbumsByAlbumTitle
:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Menentukan indeks di antarmuka baca
Saat menggunakan antarmuka baca ke Spanner, dan Anda ingin Spanner menggunakan indeks, Anda harus menentukan indeks. Antarmuka baca tidak memilih indeks secara otomatis.
Selain itu, indeks Anda harus berisi semua data yang muncul dalam hasil kueri, tidak termasuk kolom yang merupakan bagian dari kunci utama. Batasan ini ada karena antarmuka baca tidak mendukung join antara indeks dan tabel dasar. Jika perlu menyertakan kolom lain dalam hasil kueri, Anda memiliki beberapa opsi:
- Gunakan klausa
STORING
atauINCLUDE
untuk menyimpan kolom tambahan dalam indeks. - Buat kueri tanpa menyertakan kolom tambahan, lalu gunakan kunci utama untuk mengirim kueri lain yang membaca kolom tambahan.
Spanner menampilkan nilai dari indeks dalam urutan pengurutan menaik menurut kunci indeks. Untuk mengambil nilai dalam urutan menurun, selesaikan langkah-langkah berikut:
Anotasikan kunci indeks dengan
DESC
. Contoh:CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle DESC);
Anotasi
DESC
berlaku untuk satu kunci indeks. Jika indeks menyertakan lebih dari satu kunci, dan Anda ingin hasil kueri muncul dalam urutan menurun berdasarkan semua kunci, sertakan anotasiDESC
untuk setiap kunci.Jika pembacaan menentukan rentang kunci, pastikan rentang kunci juga dalam urutan menurun. Dengan kata lain, nilai kunci awal harus lebih besar dari nilai kunci akhir.
Contoh berikut menunjukkan cara mengambil nilai AlbumId
dan
AlbumTitle
menggunakan indeks AlbumsByAlbumTitle
:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Membuat indeks untuk pemindaian khusus indeks
Secara opsional, Anda dapat menggunakan klausa STORING
(untuk database dialek GoogleSQL) atau klausa INCLUDE
(untuk database dialek PostgreSQL) untuk menyimpan salinan kolom dalam indeks. Jenis indeks ini memberikan keuntungan untuk kueri dan panggilan baca yang menggunakan
indeks, dengan biaya penggunaan penyimpanan tambahan:
- Kueri SQL yang menggunakan indeks dan memilih kolom yang disimpan dalam klausa
STORING
atauINCLUDE
tidak memerlukan join tambahan ke tabel dasar. - Panggilan
read()
yang menggunakan indeks dapat membaca kolom yang disimpan oleh klausaSTORING
/INCLUDE
.
Misalnya, Anda membuat versi alternatif AlbumsByAlbumTitle
yang menyimpan salinan kolom MarketingBudget
dalam indeks (perhatikan
klausa STORING
atau INCLUDE
yang dicetak tebal):
GoogleSQL
CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) STORING (MarketingBudget);
PostgreSQL
CREATE INDEX AlbumsByAlbumTitle2 ON Albums(AlbumTitle) INCLUDE (MarketingBudget);
Dengan indeks AlbumsByAlbumTitle
lama, Spanner harus menggabungkan indeks
dengan tabel dasar, lalu mengambil kolom dari tabel dasar. Dengan indeks
AlbumsByAlbumTitle2
baru, Spanner membaca kolom langsung dari
indeks, yang lebih efisien.
Jika Anda menggunakan antarmuka baca, bukan SQL, indeks AlbumsByAlbumTitle2
baru juga memungkinkan Anda membaca kolom MarketingBudget
secara langsung:
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
Mengubah indeks
Anda dapat menggunakan pernyataan ALTER INDEX
untuk menambahkan kolom tambahan ke indeks yang ada atau menghapus kolom. Tindakan ini dapat memperbarui daftar kolom yang ditentukan oleh klausa STORING
(database dialek GoogleSQL) atau klausa INCLUDE
(database dialek PostgreSQL) saat Anda membuat indeks. Anda tidak dapat menggunakan pernyataan ini untuk menambahkan kolom ke atau menghapus
kolom dari kunci indeks. Misalnya, daripada membuat indeks AlbumsByAlbumTitle2
baru, Anda dapat menggunakan ALTER INDEX
untuk menambahkan kolom ke AlbumsByAlbumTitle
, seperti yang ditunjukkan dalam contoh berikut:
GoogleSQL
ALTER INDEX AlbumsByAlbumTitle ADD STORED COLUMN MarketingBudget
PostgreSQL
ALTER INDEX AlbumsByAlbumTitle ADD INCLUDE COLUMN MarketingBudget
Saat Anda menambahkan kolom baru ke indeks yang ada, Spanner
akan menggunakan proses pengisian ulang latar belakang. Saat pengisian ulang sedang berlangsung, kolom dalam indeks tidak dapat dibaca, sehingga Anda mungkin tidak mendapatkan peningkatan performa yang diharapkan. Anda dapat menggunakan perintah gcloud spanner operations
untuk mencantumkan operasi yang berjalan lama dan melihat statusnya.
Untuk informasi selengkapnya, lihat menjelaskan operasi.
Anda juga dapat menggunakan cancel operation untuk membatalkan operasi yang sedang berjalan.
Setelah pengisian ulang selesai, Spanner akan menambahkan kolom ke indeks. Seiring Indeks menjadi lebih besar, hal ini dapat memperlambat kueri yang menggunakan indeks.
Contoh berikut menunjukkan cara menghapus kolom dari indeks:
GoogleSQL
ALTER INDEX AlbumsByAlbumTitle DROP STORED COLUMN MarketingBudget
PostgreSQL
ALTER INDEX AlbumsByAlbumTitle DROP INCLUDE COLUMN MarketingBudget
Indeks nilai NULL
Secara default, Spanner mengindeks nilai NULL
. Misalnya, ingat kembali
definisi indeks SingersByFirstLastName
pada tabel Singers
:
CREATE INDEX SingersByFirstLastName ON Singers(FirstName, LastName);
Semua baris Singers
diindeks meskipun FirstName
atau LastName
, atau
keduanya, adalah NULL
.
Saat nilai NULL
diindeks, Anda dapat menjalankan kueri SQL yang efisien dan membaca
data yang menyertakan nilai NULL
. Misalnya, gunakan pernyataan kueri SQL ini
untuk menemukan semua Singers
dengan NULL
FirstName
:
GoogleSQL
SELECT s.SingerId, s.FirstName, s.LastName
FROM Singers@{FORCE_INDEX=SingersByFirstLastName} AS s
WHERE s.FirstName IS NULL;
PostgreSQL
SELECT s.SingerId, s.FirstName, s.LastName
FROM Singers /* @ FORCE_INDEX = SingersByFirstLastName */ AS s
WHERE s.FirstName IS NULL;
Urutan pengurutan untuk nilai NULL
Spanner mengurutkan NULL
sebagai nilai terkecil untuk jenis tertentu. Untuk kolom dalam urutan menaik (ASC
), nilai NULL
diurutkan terlebih dahulu. Untuk kolom dalam
urutan menurun (DESC
), nilai NULL
diurutkan terakhir.
Menonaktifkan pengindeksan nilai NULL
GoogleSQL
Untuk menonaktifkan pengindeksan null, tambahkan kata kunci NULL_FILTERED
ke definisi
indeks. Indeks NULL_FILTERED
sangat berguna untuk mengindeks kolom
yang jarang, dengan sebagian besar baris berisi nilai NULL
. Dalam hal ini, indeks NULL_FILTERED
dapat jauh lebih kecil dan lebih efisien untuk dikelola
daripada indeks normal yang menyertakan nilai NULL
.
Berikut adalah definisi alternatif SingersByFirstLastName
yang tidak
mengalihkan nilai NULL
:
CREATE NULL_FILTERED INDEX SingersByFirstLastNameNoNulls
ON Singers(FirstName, LastName);
Kata kunci NULL_FILTERED
berlaku untuk semua kolom kunci indeks. Anda tidak dapat menentukan
pemfilteran NULL
per kolom.
PostgreSQL
Untuk memfilter baris dengan nilai null di satu atau beberapa kolom yang diindeks, gunakan predikat WHERE COLUMN IS NOT NULL
.
Indeks yang difilter null sangat berguna untuk mengindeks kolom
yang jarang, dengan sebagian besar baris berisi nilai NULL
. Dalam hal ini, indeks yang difilter null dapat jauh lebih kecil dan lebih efisien untuk dikelola
daripada indeks normal yang menyertakan nilai NULL
.
Berikut adalah definisi alternatif SingersByFirstLastName
yang tidak
mengalihkan nilai NULL
:
CREATE INDEX SingersByFirstLastNameNoNulls
ON Singers(FirstName, LastName)
WHERE FirstName IS NOT NULL
AND LastName IS NOT NULL;
Memfilter nilai NULL
akan mencegah Spanner menggunakannya untuk beberapa
kueri. Misalnya, Spanner tidak menggunakan indeks untuk kueri ini,
karena indeks menghilangkan baris Singers
yang LastName
-nya adalah NULL
; sebagai
akibatnya, penggunaan indeks akan mencegah kueri menampilkan baris yang benar:
GoogleSQL
FROM Singers@{FORCE_INDEX=SingersByFirstLastNameNoNulls}
WHERE FirstName = "John";
PostgreSQL
FROM Singers /*@ FORCE_INDEX = SingersByFirstLastNameNoNulls */
WHERE FirstName = 'John';
Agar Spanner dapat menggunakan indeks, Anda harus menulis ulang kueri sehingga mengecualikan baris yang juga dikecualikan dari indeks:
GoogleSQL
SELECT FirstName, LastName
FROM Singers@{FORCE_INDEX=SingersByFirstLastNameNoNulls}
WHERE FirstName = 'John' AND LastName IS NOT NULL;
PostgreSQL
SELECT FirstName, LastName
FROM Singers /*@ FORCE_INDEX = SingersByFirstLastNameNoNulls */
WHERE FirstName = 'John' AND LastName IS NOT NULL;
Mengindeks kolom proto
Gunakan kolom yang dihasilkan untuk mengindeks
kolom dalam buffering protokol yang disimpan di kolom PROTO
, selama kolom
yang diindeks menggunakan jenis data primitif atau ENUM
.
Jika menentukan indeks pada kolom pesan protokol, Anda tidak dapat mengubah atau menghapus kolom tersebut dari skema proto. Untuk mengetahui informasi selengkapnya, lihat Pembaruan pada skema yang berisi indeks pada kolom proto.
Berikut adalah contoh tabel Singers
dengan kolom pesan proto
SingerInfo
. Untuk menentukan indeks di kolom nationality
dari PROTO
,
Anda perlu membuat kolom yang dihasilkan dan disimpan:
GoogleSQL
CREATE PROTO BUNDLE (googlesql.example.SingerInfo, googlesql.example.SingerInfo.Residence);
CREATE TABLE Singers (
SingerId INT64 NOT NULL,
...
SingerInfo googlesql.example.SingerInfo,
SingerNationality STRING(MAX) AS (SingerInfo.nationality) STORED
) PRIMARY KEY (SingerId);
Proto ini memiliki definisi jenis proto googlesql.example.SingerInfo
berikut:
GoogleSQL
package googlesql.example;
message SingerInfo {
optional string nationality = 1;
repeated Residence residence = 2;
message Residence {
required int64 start_year = 1;
optional int64 end_year = 2;
optional string city = 3;
optional string country = 4;
}
}
Kemudian, tentukan indeks pada kolom nationality
proto:
GoogleSQL
CREATE INDEX SingersByNationality ON Singers(SingerNationality);
Kueri SQL berikut membaca data menggunakan indeks sebelumnya:
GoogleSQL
SELECT s.SingerId, s.FirstName
FROM Singers AS s
WHERE s.SingerNationality = "English";
Catatan:
- Gunakan petunjuk indeks untuk mengakses indeks di kolom buffer protokol.
- Anda tidak dapat membuat indeks pada kolom buffering protokol berulang.
Pembaruan pada skema yang berisi indeks pada kolom proto
Jika menentukan indeks pada kolom pesan protokol, Anda tidak dapat mengubah atau menghapus kolom tersebut dari skema proto. Hal ini karena setelah Anda menentukan indeks, pemeriksaan jenis dilakukan setiap kali skema diperbarui. Spanner mengambil informasi jenis untuk semua kolom di jalur yang digunakan dalam definisi indeks.
Indeks unik
Indeks dapat dideklarasikan UNIQUE
. Indeks UNIQUE
menambahkan batasan ke
data yang diindeks yang melarang entri duplikat untuk kunci indeks tertentu.
Batasan ini diterapkan oleh Spanner pada waktu commit transaksi.
Secara khusus, setiap transaksi yang akan menyebabkan beberapa entri indeks untuk
kunci yang sama akan gagal di-commit.
Jika tabel berisi data non-UNIQUE
, upaya untuk membuat indeks UNIQUE
di dalamnya akan gagal.
Catatan tentang indeks UNIQUE NULL_FILTERED
Indeks UNIQUE NULL_FILTERED
tidak menerapkan keunikan kunci indeks jika setidaknya salah satu bagian kunci indeks adalah NULL.
Misalnya, Anda membuat tabel dan indeks berikut:
GoogleSQL
CREATE TABLE ExampleTable (
Key1 INT64 NOT NULL,
Key2 INT64,
Key3 INT64,
Col1 INT64,
) PRIMARY KEY (Key1, Key2, Key3);
CREATE UNIQUE NULL_FILTERED INDEX ExampleIndex ON ExampleTable (Key1, Key2, Col1);
PostgreSQL
CREATE TABLE ExampleTable (
Key1 BIGINT NOT NULL,
Key2 BIGINT,
Key3 BIGINT,
Col1 BIGINT,
PRIMARY KEY (Key1, Key2, Key3)
);
CREATE UNIQUE INDEX ExampleIndex ON ExampleTable (Key1, Key2, Col1)
WHERE Key1 IS NOT NULL
AND Key2 IS NOT NULL
AND Col1 IS NOT NULL;
Dua baris berikut di ExampleTable
memiliki nilai yang sama untuk kunci indeks sekunder Key1
, Key2
, dan Col1
:
1, NULL, 1, 1
1, NULL, 2, 1
Karena Key2
adalah NULL
dan indeks difilter null, baris tidak akan
ada dalam indeks ExampleIndex
. Karena tidak disisipkan ke dalam
indeks, indeks tidak akan menolaknya karena melanggar keunikan di (Key1, Key2,
Col1)
.
Jika Anda ingin indeks menerapkan keunikan nilai tuple (Key1
,
Key2
, Col1
), Anda harus menganotasi Key2
dengan NOT NULL
dalam definisi
tabel atau membuat indeks tanpa memfilter null.
Menghapus indeks
Gunakan pernyataan DROP INDEX
untuk menghapus indeks sekunder dari skema Anda.
Untuk menghapus indeks bernama SingersByFirstLastName
:
DROP INDEX SingersByFirstLastName;
Indeks untuk pemindaian yang lebih cepat
Saat Spanner perlu melakukan pemindaian tabel (bukan pencarian terindek) untuk mengambil nilai dari satu atau beberapa kolom, Anda dapat menerima hasil yang lebih cepat jika indeks ada untuk kolom tersebut, dan dalam urutan yang ditentukan oleh kueri. Jika Anda sering melakukan kueri yang memerlukan pemindaian, sebaiknya buat indeks sekunder untuk membantu pemindaian ini berjalan dengan lebih efisien.
Secara khusus, jika Anda memerlukan Spanner untuk sering memindai kunci utama tabel atau indeks lainnya dalam urutan terbalik, Anda dapat meningkatkan efisiensinya melalui indeks sekunder yang membuat urutan yang dipilih eksplisit.
Misalnya, kueri berikut selalu menampilkan hasil yang cepat, meskipun
Spanner perlu memindai Songs
untuk menemukan nilai SongId
terendah:
SELECT SongId FROM Songs LIMIT 1;
SongId
adalah kunci utama tabel, yang disimpan (seperti semua kunci utama)
dalam urutan menaik. Spanner dapat memindai indeks kunci tersebut dan menemukan
hasil pertama dengan cepat.
Namun, tanpa bantuan indeks sekunder, kueri berikut tidak akan ditampilkan dengan cepat, terutama jika Songs
menyimpan banyak data:
SELECT SongId FROM Songs ORDER BY SongId DESC LIMIT 1;
Meskipun SongId
adalah kunci utama tabel, Spanner tidak memiliki
cara untuk mengambil nilai tertinggi kolom tanpa menggunakan pemindaian
tabel penuh.
Menambahkan indeks berikut akan memungkinkan kueri ini ditampilkan lebih cepat:
CREATE INDEX SongIdDesc On Songs(SongId DESC);
Dengan indeks ini, Spanner akan menggunakannya untuk menampilkan hasil kueri kedua dengan lebih cepat.
Langkah selanjutnya
- Pelajari praktik terbaik SQL untuk Spanner.
- Pahami rencana eksekusi kueri untuk Spanner.
- Cari tahu cara memecahkan masalah regresi performa dalam kueri SQL.