Dokumen ini menjelaskan cara membuat kueri yang efisien menggunakan praktik terbaik untuk mendesain skema Spanner Graph. Desain skema bisa iteratif, jadi kami sarankan Anda terlebih dahulu mengidentifikasi pola kueri penting untuk memandu desain skema.
Untuk informasi umum tentang desain skema Spanner yang paling baik lihat Praktik terbaik desain skema.
Mengoptimalkan edge traversal
Edge traversal adalah proses navigasi melalui grafik dengan mengikuti tepi, mulai pada {i>node<i} tertentu dan bergerak di sepanjang tepi yang terhubung untuk mencapai node lainnya. Edge traversal adalah operasi mendasar di Spanner Graph, jadi meningkatkan efisiensi edge traversal adalah kunci performa aplikasi Anda.
Anda bisa melintasi tepi dalam dua arah: melintas dari {i>node<i} sumber ke node tujuan disebut forward edge traversal, saat melintas dari node tujuan ke node sumber disebut reverse edge traversal.
Mengoptimalkan forward edge traversal menggunakan interleaving
Untuk meningkatkan performa forward edge traversal, masukkan tabel input tepi ke depan ke dalam tabel input node sumber untuk menempatkan tepi-tepinya dengan node sumber. Interleaving adalah teknik pengoptimalan penyimpanan di Spanner yang secara fisik menempatkan baris tabel turunan dengan baris induknya yang sesuai di Storage. Untuk informasi selengkapnya tentang interleaving, lihat Ringkasan skema.
Contoh berikut menunjukkan praktik terbaik tersebut:
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 reverse edge traversal menggunakan kunci asing
Untuk melintasi tepi balik secara efisien, buat batasan kunci asing antara {i>edge<i} dan {i>node <i}tujuan. {i>Foreign key<i} ini secara otomatis membuat indeks sekunder di bagian tepi yang dikunci oleh kunci {i>node<i} tujuan. Indeks sekundernya adalah digunakan secara otomatis selama eksekusi kueri.
Contoh berikut menunjukkan praktik terbaik tersebut:
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 edge terbalik menggunakan indeks sekunder
Jika Anda tidak ingin membuat {i>foreign key<i} di tepi, misalnya, karena integritas data ketat yang diberlakukannya, Anda dapat langsung membuat indeks sekunder di tabel input edge, seperti yang ditunjukkan pada 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);
Larang tepi yang menjuntai
Tepi menjuntai adalah tepi yang menghubungkan kurang dari dua node. Menggantung tepi dapat terjadi ketika sebuah {i>node<i} dihapus tanpa menghilangkan tepian yang terkait, atau ketika tepian dibuat tanpa menghubungkannya dengan benar ke {i>node-<i}nya.
Melarang tepi yang tidak rapi akan memberikan manfaat berikut:
- Menerapkan integritas struktur grafik.
- Meningkatkan performa kueri dengan menghindari pekerjaan tambahan untuk memfilter tepi yang tidak memiliki endpoint.
Melarang tepi yang menjuntai menggunakan batasan referensial
Untuk melarang tepi yang menjuntai, tentukan batasan pada keduanya endpoint:
- Masukkan tabel input edge ke tabel input node sumber. Ini memastikan bahwa {i>node<i} sumber dari sebuah edge selalu ada.
- Buat batasan {i>foreign key<i} di tepian untuk memastikan bahwa node tujuan dari tepi selalu ada.
Contoh berikut menggunakan interleaving dan {i>foreign key<i} untuk memberlakukan integritas referensial:
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;
Gunakan ON DELETE CASCADE untuk otomatis menghapus tepi saat menghapus node
Saat Anda menggunakan interleaving atau {i>foreign key<i} untuk melarang tepi yang menjuntai, gunakan
Klausa ON DELETE
untuk mengontrol perilaku saat Anda ingin menghapus node dengan
tepi yang masih melekat. Untuk informasi selengkapnya, lihat
menghapus jenjang 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 simpul dengan tepi akan gagal.ON DELETE CASCADE
: Menghapus node akan otomatis menghapus tepi yang terkait dalam transaksi yang sama.
Menghapus jenjang untuk tepi yang menghubungkan berbagai jenis {i>node<i}
Hapus edge saat node sumber dihapus. Misalnya,
INTERLEAVE IN PARENT Person ON DELETE CASCADE
akan menghapus semua permintaan keluarPersonOwnAccount
tepi dari nodePerson
yang sedang dihapus. Untuk selengkapnya informasi, lihat Membuat tabel sisipan.Hapus edge saat node tujuan dihapus. Misalnya,
CONSTRAINT FK_Account FOREIGN KEY(account_id) REFERENCES Account(id) ON DELETE CASCADE
menghapus semua tepiPersonOwnAccount
yang masuk ke nodeAccount
yang dihapus. Untuk informasi selengkapnya, lihat Foreign key.
Hapus jenjang untuk tepi yang menghubungkan jenis simpul yang sama
Ketika {i>node<i} sumber dan tujuan dari suatu edge memiliki jenis yang sama dan
edge disisipi ke node sumber, Anda dapat menentukan ON DELETE CASCADE
hanya untuk node sumber atau node tujuan (tetapi tidak untuk kedua node tersebut).
Untuk secara otomatis menghapus tepian yang menjuntai pada kedua kasus tersebut, buat {i>foreign key <i}di referensi node sumber edge alih-alih menyisipkan tabel input edge tabel input simpul sumber.
Kami merekomendasikan {i>interleaving <i}untuk
mengoptimalkan traversal edge maju.
Pastikan untuk memverifikasi dampak beban kerja Anda sebelum melanjutkan. Lihat
contoh berikut, yang menggunakan AccountTransferAccount
sebagai input edge
tabel:
--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. Mendukung pencarian cepat terhadap simpul dan tepi berdasarkan nilai properti tertentu, tanpa harus menjelajahi seluruh struktur grafik. Hal ini penting ketika Anda bekerja dengan grafik besar, karena melintasi semua {i>node<i} dan tepi bisa sangat tidak efisien.
Mempercepat pemfilteran node berdasarkan properti
Untuk mempercepat pemfilteran berdasarkan properti {i>node<i}, buat indeks sekunder di
properti baru. Misalnya, kueri berikut menemukan akun untuk
nama panggilan. Tanpa indeks sekunder, semua node Account
akan dipindai agar sesuai
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, sebagai 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 AccountByEmail
ON Account (nick_name);
Tips: Gunakan indeks yang difilter NULL untuk properti sparse. Untuk informasi selengkapnya, lihat Menonaktifkan pengindeksan nilai NULL.
Mempercepat traversal tepi maju dengan pemfilteran pada properti edge
Saat Anda melintasi tepian sambil memfilter propertinya, Anda dapat mempercepat kueri dengan membuat indeks sekunder pada properti edge dan menyisipkan indeks ke dalam node sumber.
Misalnya, kueri berikut menemukan akun milik 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 tepian orang yang ditentukan, lalu memfilter
tepian yang memenuhi kondisi pada create_time
.
Contoh berikut menunjukkan cara meningkatkan efisiensi kueri dengan membuat
indeks sekunder pada referensi node sumber edge (id
) dan properti edge
(create_time
). Sisipkan indeks di bawah tabel input node sumber untuk
menempatkan indeks dengan 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 menggunakan pendekatan ini, kueri bisa secara efisien menemukan semua tepi yang memenuhi
kondisi pada create_time
.
Mempercepat traversal tepi terbalik dengan pemfilteran pada properti edge
Ketika Anda melintasi tepi balik saat memfilter propertinya, Anda bisa mempercepat kueri dengan membuat indeks sekunder menggunakan simpul tujuan dan properti tepi untuk pemfilteran.
Kueri contoh berikut melakukan {i>reverse edge traversal<i} dengan pemfilteran pada properti edge:
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:
Membuat indeks sekunder pada referensi node tujuan edge (
account_id
) dan properti edge (create_time
), seperti yang ditunjukkan di 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 kinerja yang lebih baik karena tepi baliknya diurutkan menurut
account_id
dancreate_time
, yang memungkinkan mesin kueri menemukan tepi untukaccount_id
yang memenuhi kondisi dengan efisiencreate_time
. Namun, jika pola kueri yang berbeda memfilter maka setiap properti mungkin memerlukan indeks terpisah, yang dapat menambahkan {i>overhead<i}.Membuat indeks sekunder pada referensi node tujuan edge (
account_id
) dan simpan properti edge (create_time
) di elemen 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 tersebut harus membaca semua tepian {i>node<i} tujuan dan kemudian memfilter properti edge.
Anda dapat menggabungkan pendekatan ini dengan mengikuti panduan berikut:
- Gunakan properti tepi dalam kolom indeks jika digunakan dalam kueri yang penting bagi performa.
- Untuk properti yang digunakan dalam kueri yang kurang sensitif terhadap performa, tambahkan properti tersebut dalam kolom yang disimpan.
Node model dan jenis edge dengan label dan properti
Jenis node dan edge biasanya dimodelkan dengan label. Namun, Anda juga dapat menggunakan
properti ke jenis model. Bayangkan sebuah contoh di mana ada banyak
jenis akun, seperti BankAccount
, InvestmentAccount
, dan
RetirementAccount
. Anda dapat menyimpan akun dalam tabel input dan
membuat modelnya sebagai label terpisah, atau
menyimpan akun dengan satu input
tabel dan menggunakan properti untuk membedakan jenis-jenis.
Mulai proses pemodelan dengan memodelkan jenis dengan label. Pertimbangkan menggunakan properti dalam skenario berikut.
Meningkatkan pengelolaan skema
Jika grafik Anda memiliki berbagai jenis node dan tepi, mengelola input terpisah untuk setiap tabel bisa menjadi sulit. Untuk mempermudah pengelolaan skema, buat model jenis sebagai properti.
Jenis model di properti untuk mengelola jenis yang sering berubah
Saat Anda memodelkan jenis sebagai label, penambahan atau penghapusan jenis memerlukan perubahan pada skemanya. Jika Anda melakukan terlalu banyak pembaruan skema dalam waktu singkat, Spanner mungkin throttle pemrosesan pembaruan skema dalam antrean. Untuk informasi selengkapnya, lihat Batasi frekuensi pembaruan skema.
Jika Anda sering mengubah skema, sebaiknya buat model yang ketik properti untuk mengatasi keterbatasan frekuensi skema pembaruan.
Mempercepat kueri
Jenis pemodelan dengan properti dapat mempercepat kueri saat pola node atau tepi
merujuk pada beberapa label. Contoh kueri berikut menemukan semua {i>instance <i}
SavingsAccount
dan InvestmentAccount
dimiliki oleh Person
, dengan asumsi akun
type ini dimodelkan dengan label:
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:SavingsAccount|InvestmentAccount)
RETURN acct.id;
Pola node acct
merujuk pada dua label. Jika ini adalah
kueri yang penting bagi performa, pertimbangkan untuk membuat model Account
menggunakan properti. Ini
mungkin memberikan performa kueri yang lebih baik, seperti yang ditampilkan dalam kueri
contoh. Sebaiknya Anda menjalankan tolok ukur untuk kedua kueri tersebut.
GRAPH FinGraph
MATCH (:Person {id: 1})-[:Owns]->(acct:Account)
WHERE acct.type IN ("Savings", "Investment")
RETURN acct.id;
Jenis penyimpanan 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 sepanjang masa aktif node, ikuti langkah-langkah berikut:
- Sertakan properti sebagai bagian dari kunci elemen node.
- Tambahkan jenis node di tabel input edge.
- Sertakan jenis node di kunci yang merujuk pada edge.
Contoh berikut menerapkan pengoptimalan ini ke node Account
dan
tepi 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
Spanner Time to live (TTL) adalah mekanisme yang mendukung akhir masa berlaku dan penghapusan data setelah periode tertentu. Ini sering digunakan untuk data yang memiliki masa aktif atau relevansi, seperti informasi sesi, cache sementara, atau peristiwa log. Dalam kasus ini, TTL membantu menjaga ukuran dan performa database.
Contoh berikut menggunakan TTL untuk menghapus akun 90 hari setelah penutupan:
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 {i>node<i} memiliki TTL dan tabel tepi
yang disisipkan di dalamnya,
interleaf harus didefinisikan dengan
ON DELETE CASCADE
Demikian pula, jika tabel {i>node<i} memiliki TTL
dan dirujuk oleh tabel {i>edge<i}
melalui {i>foreign key<i}, {i>foreign key<i}
harus didefinisikan dengan
ON DELETE CASCADE
.
Dalam contoh berikut, AccountTransferAccount
disimpan hingga sepuluh tahun
saat akun tetap aktif. Setelah akun dihapus, transfer
juga 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 tepi
Anda bisa menggunakan tabel input yang sama untuk mendefinisikan lebih dari satu {i>node<i} dan {i>edge<i} di skema.
Pada tabel contoh berikut, node Account
memiliki kunci gabungan
(owner_id, account_id)
. Ada definisi edge implisit, node Person
dengan kunci (id
) memiliki node Account
dengan kunci gabungan
(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 Account
node dan tepi PersonOwnAccount
, seperti yang ditunjukkan dalam contoh skema berikut.
Untuk memastikan bahwa semua nama tabel elemen unik, contoh memberikan nilai tepi
tabel yang mendefinisikan alias Owns
.
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, mengupdate, atau melepas skema Grafik Spanner.
- Menyisipkan, memperbarui, atau menghapus data Grafik Spanner.