Dokumen ini menjelaskan cara membuat kueri yang efisien menggunakan praktik terbaik untuk mendesain skema Spanner Graph. Desain skema dapat bersifat iteratif, jadi sebaiknya identifikasi pola kueri penting terlebih dahulu untuk memandu desain skema Anda.
Untuk informasi umum tentang praktik terbaik desain skema Spanner, lihat Praktik terbaik desain skema.
Mengoptimalkan traversal edge
Pencarian tepi adalah proses menavigasi grafik dengan mengikuti tepinya, dimulai dari node tertentu dan bergerak di sepanjang tepi yang terhubung untuk mencapai node lain. Penjelajahan tepi adalah operasi dasar di Spanner Graph, sehingga meningkatkan efisiensi penjelajahan tepi adalah kunci untuk performa aplikasi Anda.
Anda dapat melintasi tepi dalam dua arah: melintasi dari node sumber ke node tujuan disebut traversal tepi maju, sedangkan melintasi dari node tujuan ke node sumber disebut traversal tepi balik.
Mengoptimalkan traversal tepi maju menggunakan interleaving
Untuk meningkatkan performa traversal tepi maju, gabungkan tabel input tepi ke dalam tabel input node sumber untuk menempatkan tepi bersama node sumber. Interleaving adalah teknik pengoptimalan penyimpanan di Spanner yang secara fisik menempatkan baris tabel turunan dengan baris induk yang sesuai di penyimpanan. Untuk mengetahui informasi selengkapnya tentang interleaving, lihat Ringkasan skema.
Contoh berikut menunjukkan praktik terbaik ini:
CREATE TABLE Person (
id INT64 NOT NULL,
name STRING(MAX),
) PRIMARY KEY (id);
CREATE TABLE PersonOwnAccount (
id INT64 NOT NULL,
account_id INT64 NOT NULL,
create_time TIMESTAMP,
) PRIMARY KEY (id, account_id),
INTERLEAVE IN PARENT Person ON DELETE CASCADE;
Mengoptimalkan traversal tepi terbalik menggunakan kunci asing
Untuk menjelajahi tepi terbalik secara efisien, buat batasan kunci asing antara tepi dan node tujuan. Kunci asing ini secara otomatis membuat indeks sekunder di tepi yang diberi kunci oleh kunci node tujuan. Indeks sekunder secara otomatis digunakan selama eksekusi kueri.
Contoh berikut menunjukkan praktik terbaik ini:
CREATE TABLE Person (
id INT64 NOT NULL,
name STRING(MAX),
) PRIMARY KEY (id);
CREATE TABLE Account (
id INT64 NOT NULL,
create_time TIMESTAMP,
) PRIMARY KEY (id);
CREATE TABLE PersonOwnAccount (
id INT64 NOT NULL,
account_id INT64 NOT NULL,
create_time TIMESTAMP,
CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id),
) PRIMARY KEY (id, account_id),
INTERLEAVE IN PARENT Person ON DELETE CASCADE;
Mengoptimalkan traversal tepi terbalik menggunakan indeks sekunder
Jika tidak ingin membuat kunci asing di edge, misalnya, karena integritas data yang ketat yang diterapkannya, Anda dapat langsung membuat indeks sekunder di tabel input edge, seperti yang ditunjukkan dalam contoh berikut:
CREATE TABLE PersonOwnAccount (
id INT64 NOT NULL,
account_id INT64 NOT NULL,
create_time TIMESTAMP,
) PRIMARY KEY (id, account_id),
INTERLEAVE IN PARENT Person ON DELETE CASCADE;
CREATE INDEX Reverse_PersonOwnAccount
ON PersonOwnAccount (account_id);
Tidak mengizinkan tepi yang menggantung
Tepi menggantung adalah tepi yang menghubungkan kurang dari dua node. Tepi yang tidak terikat dapat terjadi saat node dihapus tanpa menghapus tepi terkaitnya, atau saat tepi dibuat tanpa menautkannya dengan benar ke node-nya.
Tidak mengizinkan edge yang menggantung memberikan manfaat berikut:
- Menerapkan integritas struktur grafik.
- Meningkatkan performa kueri dengan menghindari pekerjaan tambahan untuk memfilter tepi tempat endpoint tidak ada.
Tidak mengizinkan tepi yang menggantung menggunakan batasan referensi
Untuk melarang tepi yang menggantung, tentukan batasan pada kedua endpoint:
- Gabungkan tabel input tepi ke dalam tabel input node sumber. Pendekatan ini memastikan bahwa node sumber tepi selalu ada.
- Buat batasan kunci asing pada tepi untuk memastikan bahwa node tujuan tepi selalu ada.
Contoh berikut menggunakan interleaving dan kunci asing untuk menerapkan integritas referensi:
CREATE TABLE PersonOwnAccount (
id INT64 NOT NULL,
account_id INT64 NOT NULL,
create_time TIMESTAMP,
CONSTRAINT FK_Account FOREIGN KEY (account_id) REFERENCES Account (id) ON DELETE CASCADE,
) PRIMARY KEY (id, account_id),
INTERLEAVE IN PARENT Person ON DELETE CASCADE;
Menggunakan ON DELETE CASCADE untuk menghapus tepi secara otomatis saat menghapus node
Saat Anda menggunakan interleaving atau kunci asing untuk melarang edge yang menggantung, gunakan
klausa ON DELETE
untuk mengontrol perilaku saat Anda ingin menghapus node dengan
edge yang masih terpasang. Untuk informasi selengkapnya, lihat
menghapus cascading untuk tabel sisipan
dan
menghapus cascading dengan kunci asing.
Anda dapat menggunakan ON DELETE
dengan cara berikut:
ON DELETE NO ACTION
(atau menghapus klausaON DELETE
): Menghapus node dengan tepi akan gagal.ON DELETE CASCADE
: Menghapus node akan otomatis menghapus sisi terkait dalam transaksi yang sama.
Menghapus kaskade untuk tepi yang menghubungkan berbagai jenis node
Menghapus tepi saat node sumber dihapus. Misalnya,
INTERLEAVE IN PARENT Person ON DELETE CASCADE
menghapus semua tepiPersonOwnAccount
keluar dari nodePerson
yang dihapus. Untuk informasi selengkapnya, lihat Membuat tabel yang diselang-seling.Menghapus tepi saat node tujuan dihapus. Misalnya,
CONSTRAINT FK_Account FOREIGN KEY(account_id) REFERENCES Account(id) ON DELETE CASCADE
menghapus semua tepiPersonOwnAccount
masuk ke nodeAccount
yang dihapus. Untuk informasi selengkapnya, lihat Kunci asing.
Menghapus cascade untuk tepi yang menghubungkan jenis node yang sama
Jika node sumber dan tujuan tepi memiliki jenis yang sama dan
tepi diselingi ke dalam node sumber, Anda dapat menentukan ON DELETE CASCADE
hanya untuk node sumber atau node tujuan (tetapi tidak keduanya).
Untuk menghapus edge yang menggantung secara otomatis dalam kedua kasus tersebut, buat kunci asing pada referensi node sumber edge, bukan menyisipkan tabel input edge ke dalam tabel input node sumber.
Sebaiknya gunakan interleaving untuk
mengoptimalkan traversal tepi maju.
Pastikan untuk memverifikasi dampaknya pada beban kerja Anda sebelum melanjutkan. Lihat
contoh berikut, yang menggunakan AccountTransferAccount
sebagai tabel input
edge:
--Define two Foreign Keys, each on one end Node of Transfer Edge, both with ON DELETE CASCADE action:
CREATE TABLE AccountTransferAccount (
id INT64 NOT NULL,
to_id INT64 NOT NULL,
amount FLOAT64,
create_time TIMESTAMP NOT NULL,
order_number STRING(MAX),
CONSTRAINT FK_FromAccount FOREIGN KEY (id) REFERENCES Account (id) ON DELETE CASCADE,
CONSTRAINT FK_ToAccount FOREIGN KEY (to_id) REFERENCES Account (id) ON DELETE CASCADE,
) PRIMARY KEY (id, to_id);
Memfilter menurut properti node atau edge dengan indeks sekunder
Indeks sekunder sangat penting untuk pemrosesan kueri yang efisien. Fungsi ini mendukung pencarian cepat node dan edge berdasarkan nilai properti tertentu, tanpa harus menelusuri seluruh struktur grafik. Hal ini penting saat Anda menggunakan grafik besar, karena menjelajahi semua node dan tepi dapat sangat tidak efisien.
Mempercepat pemfilteran node berdasarkan properti
Untuk mempercepat pemfilteran berdasarkan properti node, buat indeks sekunder pada properti. Misalnya, kueri berikut menemukan akun untuk nama panggilan
tertentu. Tanpa indeks sekunder, semua node Account
akan dipindai agar cocok dengan
kriteria pemfilteran.
GRAPH FinGraph
MATCH (acct:Account)
WHERE acct.nick_name = "abcd"
RETURN acct.id;
Untuk mempercepat kueri, buat indeks sekunder pada properti yang difilter, seperti yang ditunjukkan dalam contoh berikut:
CREATE TABLE Account (
id INT64 NOT NULL,
create_time TIMESTAMP,
is_blocked BOOL,
nick_name STRING(MAX),
) PRIMARY KEY (id);
CREATE INDEX AccountByNickName
ON Account (nick_name);
Tips: Gunakan indeks yang difilter dengan NULL untuk properti yang jarang. Untuk mengetahui informasi selengkapnya, lihat Menonaktifkan pengindeksan nilai NULL.
Mempercepat traversal tepi maju dengan pemfilteran pada properti tepi
Saat menjelajahi tepi sambil memfilter propertinya, Anda dapat mempercepat kueri dengan membuat indeks sekunder pada properti tepi dan menyisipkan indeks ke dalam node sumber.
Misalnya, kueri berikut menemukan akun yang dimiliki oleh orang tertentu setelah waktu tertentu:
GRAPH FinGraph
MATCH (person:Person)-[owns:Owns]->(acct:Account)
WHERE person.id = 1
AND owns.create_time >= PARSE_TIMESTAMP("%c", "Thu Dec 25 07:30:00 2008")
RETURN acct.id;
Secara default, kueri ini membaca semua edge orang yang ditentukan, lalu memfilter
edge yang memenuhi kondisi di create_time
.
Contoh berikut menunjukkan cara meningkatkan efisiensi kueri dengan membuat
indeks sekunder pada referensi node sumber tepi (id
) dan properti tepi
(create_time
). Gabungkan indeks di bawah tabel input node sumber untuk
meletakkan indeks bersama node sumber.
CREATE TABLE PersonOwnAccount (
id INT64 NOT NULL,
account_id INT64 NOT NULL,
create_time TIMESTAMP,
) PRIMARY KEY (id, account_id),
INTERLEAVE IN PARENT Person ON DELETE CASCADE;
CREATE INDEX PersonOwnAccountByCreateTime
ON PersonOwnAccount (id, create_time)
INTERLEAVE IN Person;
Dengan pendekatan ini, kueri dapat menemukan semua tepi yang memenuhi
kondisi di create_time
secara efisien.
Mempercepat traversal tepi terbalik dengan pemfilteran pada properti tepi
Saat menjelajahi tepi terbalik sambil memfilter propertinya, Anda dapat mempercepat kueri dengan membuat indeks sekunder menggunakan node tujuan dan properti tepi untuk pemfilteran.
Contoh kueri berikut melakukan traversal tepi terbalik dengan pemfilteran pada properti tepi:
GRAPH FinGraph
MATCH (acct:Account)<-[owns:Owns]-(person:Person)
WHERE acct.id = 1
AND owns.create_time >= PARSE_TIMESTAMP("%c", "Thu Dec 25 07:30:00 2008")
RETURN person.id;
Untuk mempercepat kueri ini menggunakan indeks sekunder, gunakan salah satu opsi berikut:
Buat indeks sekunder pada referensi node tujuan tepi (
account_id
) dan properti tepi (create_time
), seperti yang ditunjukkan dalam contoh berikut:CREATE TABLE PersonOwnAccount ( id INT64 NOT NULL, account_id INT64 NOT NULL, create_time TIMESTAMP, ) PRIMARY KEY (id, account_id), INTERLEAVE IN PARENT Person ON DELETE CASCADE; CREATE INDEX PersonOwnAccountByCreateTime ON PersonOwnAccount (account_id, create_time);
Pendekatan ini memberikan performa yang lebih baik karena tepi balik diurutkan menurut
account_id
dancreate_time
, yang memungkinkan mesin kueri menemukan tepi untukaccount_id
secara efisien yang memenuhi kondisi padacreate_time
. Namun, jika pola kueri yang berbeda memfilter properti yang berbeda, setiap properti mungkin memerlukan indeks terpisah, yang dapat menambahkan overhead.Buat indeks sekunder pada referensi node tujuan edge (
account_id
) dan simpan properti edge (create_time
) di kolom penyimpanan, seperti yang ditunjukkan dalam contoh berikut:CREATE TABLE PersonOwnAccount ( id INT64 NOT NULL, account_id INT64 NOT NULL, create_time TIMESTAMP, ) PRIMARY KEY (id, account_id), INTERLEAVE IN PARENT Person ON DELETE CASCADE; CREATE INDEX PersonOwnAccountByCreateTime ON PersonOwnAccount (account_id) STORING (create_time);
Pendekatan ini dapat menyimpan beberapa properti; namun, kueri harus membaca semua tepi node tujuan, lalu memfilter properti tepi.
Anda dapat menggabungkan pendekatan ini dengan mengikuti panduan berikut:
- Gunakan properti edge di kolom indeks jika properti tersebut digunakan dalam kueri yang penting untuk performa.
- Untuk properti yang digunakan dalam kueri yang kurang sensitif terhadap performa, tambahkan properti tersebut di kolom penyimpanan.
Jenis node dan edge model dengan label dan properti
Jenis node dan edge biasanya dimodelkan dengan label. Namun, Anda juga dapat menggunakan properti untuk membuat model jenis. Pertimbangkan contoh yang memiliki banyak jenis akun
yang berbeda, seperti BankAccount
, InvestmentAccount
, dan
RetirementAccount
. Anda dapat menyimpan akun dalam tabel input terpisah dan
membuat modelnya sebagai label terpisah, atau Anda dapat menyimpan akun dalam satu tabel
input dan menggunakan properti untuk membedakan antarjenis.
Mulai proses pemodelan dengan membuat model jenis dengan label. Pertimbangkan penggunaan properti dalam skenario berikut.
Meningkatkan pengelolaan skema
Jika grafik Anda memiliki banyak jenis node dan edge yang berbeda, mengelola tabel input terpisah untuk setiap jenis dapat menjadi sulit. Untuk mempermudah pengelolaan skema, buat model jenis sebagai properti.
Jenis model di properti untuk mengelola jenis yang sering berubah
Saat Anda membuat model jenis sebagai label, penambahan atau penghapusan jenis memerlukan perubahan pada skema. Jika Anda melakukan terlalu banyak pembaruan skema dalam jangka waktu yang singkat, Spanner mungkin memperlambat pemrosesan pembaruan skema yang diantrekan. Untuk mengetahui informasi selengkapnya, lihat Membatasi frekuensi pembaruan skema.
Jika Anda perlu sering mengubah skema, sebaiknya buat model jenis di properti untuk mengatasi batasan frekuensi update skema.
Mempercepat kueri
Membuat model jenis dengan properti dapat mempercepat kueri saat pola node atau tepi
merujuk ke beberapa label. Contoh kueri berikut menemukan semua instance
SavingsAccount
dan InvestmentAccount
yang dimiliki oleh Person
, dengan asumsi jenis akun
dimodelkan dengan label:
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:SavingsAccount|InvestmentAccount)
RETURN acct.id;
Pola node acct
mereferensikan dua label. Jika ini adalah
kueri yang penting untuk performa, pertimbangkan untuk membuat model Account
menggunakan properti. Pendekatan
ini mungkin memberikan performa kueri yang lebih baik, seperti yang ditunjukkan dalam contoh
kueri berikut. Sebaiknya Anda menjalankan benchmark pada kedua kueri tersebut.
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:Account)
WHERE acct.type IN ("Savings", "Investment")
RETURN acct.id;
Menyimpan jenis di kunci elemen node untuk mempercepat kueri
Untuk mempercepat kueri dengan pemfilteran pada jenis node saat jenis node dimodelkan dengan properti dan jenisnya tidak berubah selama masa aktif node, ikuti langkah-langkah berikut:
- Sertakan properti sebagai bagian dari kunci elemen node.
- Tambahkan jenis node di tabel input tepi.
- Sertakan jenis node dalam kunci referensi tepi.
Contoh berikut menerapkan pengoptimalan ini ke node Account
dan
edge AccountTransferAccount
.
CREATE TABLE Account (
type STRING(MAX) NOT NULL,
id INT64 NOT NULL,
create_time TIMESTAMP,
) PRIMARY KEY (type, id);
CREATE TABLE AccountTransferAccount (
type STRING(MAX) NOT NULL,
id INT64 NOT NULL,
to_type STRING(MAX) NOT NULL,
to_id INT64 NOT NULL,
amount FLOAT64,
create_time TIMESTAMP NOT NULL,
order_number STRING(MAX),
) PRIMARY KEY (type, id, to_type, to_id),
INTERLEAVE IN PARENT Account ON DELETE CASCADE;
CREATE PROPERTY GRAPH FinGraph
NODE TABLES (
Account
)
EDGE TABLES (
AccountTransferAccount
SOURCE KEY (type, id) REFERENCES Account
DESTINATION KEY (to_type, to_id) REFERENCES Account
);
Mengonfigurasi TTL pada node dan edge
Time to live (TTL) Spanner adalah mekanisme yang mendukung masa berlaku dan penghapusan data secara otomatis setelah jangka waktu tertentu. Hal ini sering digunakan untuk data yang memiliki masa aktif atau relevansi terbatas, seperti informasi sesi, cache sementara, atau log peristiwa. Dalam kasus ini, TTL membantu mempertahankan ukuran dan performa database.
Contoh berikut menggunakan TTL untuk menghapus akun 90 hari setelah penutupannya:
CREATE TABLE Account (
id INT64 NOT NULL,
create_time TIMESTAMP,
close_time TIMESTAMP,
) PRIMARY KEY (id),
ROW DELETION POLICY (OLDER_THAN(close_time, INTERVAL 90 DAY));
Jika tabel node memiliki TTL dan tabel tepi yang diselingi di dalamnya, interleave harus ditentukan dengan
ON DELETE CASCADE
.
Demikian pula, jika tabel node memiliki TTL dan direferensikan oleh tabel tepi
melalui kunci asing, kunci asing harus ditentukan dengan
ON DELETE CASCADE
.
Dalam contoh berikut, AccountTransferAccount
disimpan hingga sepuluh tahun
selama akun tetap aktif. Jika akun dihapus, histori
transfer juga akan dihapus.
CREATE TABLE AccountTransferAccount (
id INT64 NOT NULL,
to_id INT64 NOT NULL,
amount FLOAT64,
create_time TIMESTAMP NOT NULL,
order_number STRING(MAX),
) PRIMARY KEY (id, to_id),
INTERLEAVE IN PARENT Account ON DELETE CASCADE,
ROW DELETION POLICY (OLDER_THAN(create_time, INTERVAL 3650 DAY));
Menggabungkan tabel input node dan edge
Anda dapat menggunakan tabel input yang sama untuk menentukan lebih dari satu node dan tepi dalam skema Anda.
Dalam contoh tabel berikut, node Account
memiliki kunci komposit
(owner_id, account_id)
. Ada definisi tepi implisit, node Person
dengan kunci (id
) memiliki node Account
dengan kunci komposit
(owner_id, account_id)
saat id
sama dengan owner_id
.
CREATE TABLE Person (
id INT64 NOT NULL,
) PRIMARY KEY (id);
-- Assume each account has exactly one owner.
CREATE TABLE Account (
owner_id INT64 NOT NULL,
account_id INT64 NOT NULL,
) PRIMARY KEY (owner_id, account_id);
Dalam hal ini, Anda dapat menggunakan tabel input Account
untuk menentukan node Account
dan tepi PersonOwnAccount
, seperti yang ditunjukkan dalam contoh skema berikut.
Untuk memastikan bahwa semua nama tabel elemen unik, contoh ini memberikan alias Owns
pada definisi tabel tepi.
CREATE PROPERTY GRAPH FinGraph
NODE TABLES (
Person,
Account
)
EDGE TABLES (
Account AS Owns
SOURCE KEY (owner_id) REFERENCES Person
DESTINATION KEY (owner_id, account_id) REFERENCES Account
);
Langkah selanjutnya
- Membuat, memperbarui, atau menghapus skema Grafik Spanner.
- Menyisipkan, memperbarui, atau menghapus data Spanner Graph.