4 dakika
Subgraph Örnek Uygulama 3 - Değişmez Varlıklar ve Byte'ları Kimlik Olarak Kullanarak Endeksleme ve Sorgu Performansını İyileştirin
Özet
schema.graphql
dosyamızda Kimlikler için Değişmez Varlıklar ve Byte’lar kullanmak endeksleme hızını ve sorgu performansını önemli ölçüde arttırır.
Değişmez Varlıklar
Bir varlığı değişmez hale getirmek için, varlığa (immutable: true)
ekleriz.
1type Transfer @entity(immutable: true) {2 id: Bytes!3 from: Bytes!4 to: Bytes!5 value: BigInt!6}
Transfer
varlığını değişmez hale getirerek, graph-node’un varlığı daha verimli bir şekilde işlemesini sağlayabiliriz. Bu da endeksleme hızını ve sorgu yanıt verebilirliğini artırır.
Değişmez Varlıkların yapıları gelecekte değişmeyecektir. “Değişmez Varlık” haline getirilecek ideal bir varlık, doğrudan zincir üstü olay verilerini kaydeden bir varlık, (örneğin bir Transfer
olayının Transfer
varlığı olarak kaydedilmesi) gibi olabilir.
Detaylı İnceleme
Değişebilir varlıkların geçerliliklerini belirten bir ‘blok aralığı’ bulunur. Bu varlıkları güncellemek, Graph Düğümü’nün önceki versiyonların blok aralığını ayarlamasını gerektirir. Bu da veritabanı iş yükünü artırır. Sorguların da yalnızca canlı ögeleri bulmak için filtrelenmesi gerekir. Değişmez ögeler daha hızlıdır. Çünkü hepsi canlıdır ve değişmeyeceklerinden dolayı, yazma sırasında herhangi bir kontrol veya güncellemeye gerek yoktur. Ayrıca, sorgular sırasında herhangi bir filtrelemeye de gerek kalmaz.
Değişmez Varlıklar ne zaman kullanmamalı
Eğer zamanla değiştirilmesi gereken status
gibi bir alanınız varsa, varlığı değişmez yapmamalısınız. Bunun dışında mümkünse değişmez varlıklar kullanmalısınız.
ID (Kimlik Numarası) Olarak Bytes
Her varlığın bir ID’si olmalıdır. Önceki örnekte, ID’nin zaten Bytes türünde olduğunu görebiliriz.
1type Transfer @entity(immutable: true) {2 id: Bytes!3 from: Bytes!4 to: Bytes!5 value: BigInt!6}
ID’ler için String ve Int8 gibi başka türler kullanmak mümkün olsa da, tüm ID’ler için Bytes türünün kullanılması önerilir. Çünkü karakter dizileri ikili (binary) verileri saklamak için Bayt dizilerinden iki kat fazla yer kaplar. Ayrıca, UTF-8 karakter dizilerinin karşılaştırmaları, yerel ayarı hesaba katması gerekliliğinden ötürü, Bayt dizilerinin karşılaştırmalarında kullanılan bayt temelli (bytewise) karşılaştırmalardan çok daha maliyetlidir.
ID Olarak Bytes Kullanmama Nedenleri
- Eğer varlık ID’leri otomatik artırılan sayısal ID’ler veya okunabilir dizeler gibi insan tarafından okunabilir olmalıysa, ID için Bytes kullanılmamalıdır.
- If integrating a Subgraph’s data with another data model that does not use Bytes as IDs, Bytes as IDs should not be used.
- Endeksleme ve sorgulama gibi performans iyileştirmeleri istenmiyorsa.
ID Olarak Bytes’ı Başka Bir Özellikle Birleştirme
It is a common practice in many Subgraphs to use string concatenation to combine two properties of an event into a single ID, such as using event.transaction.hash.toHex() + "-" + event.logIndex.toString()
. However, as this returns a string, this significantly impedes Subgraph indexing and querying performance.
Bunun yerine, olay özelliklerini birleştirmek için concatI32()
metodunu kullanmalıyız. Bu strateji, çok daha iyi çalışan bir Bytes
ID ile sonuçlanır.
1export function handleTransfer(event: TransferEvent): void {2 let entity = new Transfer(event.transaction.hash.concatI32(event.logIndex.toI32()))3 entity.from = event.params.from4 entity.to = event.params.to5 entity.value = event.params.value67 entity.blockNumber = event.block.number8 entity.blockTimestamp = event.block.timestamp9 entity.transactionHash = event.transaction.hash1011 entity.save()12}
Bytes’ı ID Olarak Kullanarak Sıralama
Bytes’ı ID olarak kullanarak sıralama yapmak, bu örnek sorgu ve yanıtında gördüğümüz gibi ideal değildir.
Sorgu:
1{2 transfers(first: 3, orderBy: id) {3 id4 from5 to6 value7 }8}
Sorgu yanıtı:
1{2 "data": {3 "transfers": [4 {5 "id": "0x00010000",6 "from": "0xabcd...",7 "to": "0x1234...",8 "value": "256"9 },10 {11 "id": "0x00020000",12 "from": "0xefgh...",13 "to": "0x5678...",14 "value": "512"15 },16 {17 "id": "0x01000000",18 "from": "0xijkl...",19 "to": "0x9abc...",20 "value": "1"21 }22 ]23 }24}
ID’ler onaltılık (hex) olarak döndürülür.
Sıralamayı geliştirmek için varlık üzerinde BigInt türünde başka bir alan oluşturmalıyız.
1type Transfer @entity {2 id: Bytes!3 from: Bytes! # address4 to: Bytes! # address5 value: BigInt! # unit2566 tokenId: BigInt! # uint2567}
Bu alanı oluşturmak, sıralamanın ardışık olarak optimize edilmesine olanak tanıyacaktır.
Sorgu:
1{2 transfers(first: 3, orderBy: tokenId) {3 id4 tokenId5 }6}
Sorgu Yanıtı:
1{2 "data": {3 "transfers": [4 {5 "id": "0x…",6 "tokenId": "1"7 },8 {9 "id": "0x…",10 "tokenId": "2"11 },12 {13 "id": "0x…",14 "tokenId": "3"15 }16 ]17 }18}
Sonuç
Using both Immutable Entities and Bytes as IDs has been shown to markedly improve Subgraph efficiency. Specifically, tests have highlighted up to a 28% increase in query performance and up to a 48% acceleration in indexing speeds.
Değişmez Varlıkları ve ID olarak Bytes kullanmak hakkında daha fazla bilgiyi Edge & Node’da Yazılım Mühendisi olan David Lutterkort’un bu blog yazısında bulabilirsiniz: İki Basit Subgraph Performans İyileştirmesi.