Cookbook > Subgraph Best Practice 3: Using Immutable Entities and Bytes as IDs

Boas Práticas de Subgraph 3 - Como Melhorar o Desempenho da Indexação e de Queries com Entidades Imutáveis e Bytes como IDs

Reading time: 4 min

TLDR

Link para esta seção

Usar Entidades Imutáveis e Bytes como IDs no nosso arquivo schema.graphql acelera muito a indexação e o desempenho das queries.

Entidades Imutáveis

Link para esta seção

Para fazer uma entidade imutável, basta adicionar (immutable: true) a uma entidade.

type Transfer @entity(immutable: true) {
id: Bytes!
from: Bytes!
to: Bytes!
value: BigInt!
}

Ao tornar a entidade Transfer imutável, o graph-node pode processá-la com mais eficácia, o que melhora as velocidades de indexação e a capacidade de resposta das queries.

Estruturas de Entidades Imutáveis não mudarão no futuro. Uma entidade ideal para se tornar Imutável seria uma que grava diretamente dados de eventos on-chain; por exemplo, um evento Transfer gravado como uma entidade Transfer.

De dentro da casca

Link para esta seção

Entidades mutáveis tem um block range (alcance de bloco) que indica a sua validade. Atualizar estas entidades exige que o graph-node ajuste o alcance de bloco de versões anteriores, o que aumenta a carga de trabalho do banco de dados. Queries também precisam de filtragem para encontrar apenas entidades vivas. Entidades imutáveis são mais rápidas por serem todas vivas, e como não mudam, nenhuma verificação ou atualização é necessária durante a escrita, e nenhuma filtragem é necessária durante queries.

Quando não usar Entidades Imutáveis

Link para esta seção

Se tiver um campo como status que precise ser gradualmente modificado, então esta entidade não deve ser imutável. Fora isto, é recomendado usar entidades imutáveis sempre que possível.

Bytes como IDs

Link para esta seção

Toda entidade requer uma ID. No exemplo anterior, vemos que a ID já é do tipo Bytes.

type Transfer @entity(immutable: true) {
id: Bytes!
from: Bytes!
to: Bytes!
value: BigInt!
}

Enquanto outros tipos de IDs são possíveis, como String e Int8, recomendamos usar o tipo Bytes para todas as IDs porque strings de caracteres ocupam o dobro do espaço ocupado por strings de Byte para armazenar dados, e comparações de strings de caracteres em UTF-8 devem levar em conta o local, que é muito mais caro que a comparação em byte usada para comparar strings em Byte.

Razões para Não Usar Bytes como IDs

Link para esta seção
  1. Se IDs de entidade devem ser legíveis para humanos, como IDs numéricas automaticamente incrementadas ou strings legíveis, então Bytes como IDs não devem ser usados.
  2. Em caso de integração dos dados de um subgraph com outro modelo de dados que não usa Bytes como IDs, então Bytes como IDs não devem ser usados.
  3. Melhorias no desempenho de indexação e queries não são desejáveis.

Concatenação com Bytes como IDs

Link para esta seção

É comum em vários subgraphs usar a concatenação de strings para combinar duas propriedades de um evento em uma ID única, como o uso de event.transaction.hash.toHex() + "-" + event.logIndex.toString(). Mas como isto retorna um string, isto impede muito o desempenho da indexação e queries de subgraphs.

Em vez disto, devemos usar o método concatI32() para concatenar propriedades de evento. Esta estratégia resulta numa ID Bytes que tem um desempenho muito melhor.

export function handleTransfer(event: TransferEvent): void {
let entity = new Transfer(event.transaction.hash.concatI32(event.logIndex.toI32()))
entity.from = event.params.from
entity.to = event.params.to
entity.value = event.params.value
entity.blockNumber = event.block.number
entity.blockTimestamp = event.block.timestamp
entity.transactionHash = event.transaction.hash
entity.save()
}

Organização com Bytes como IDs

Link para esta seção

A organização com Bytes como IDs não é o melhor recurso, como visto neste exemplo de query e resposta.

Query:

{
transfers(first: 3, orderBy: id) {
id
from
to
value
}
}

Resposta de query:

{
"data": {
"transfers": [
{
"id": "0x00010000",
"from": "0xabcd...",
"to": "0x1234...",
"value": "256"
},
{
"id": "0x00020000",
"from": "0xefgh...",
"to": "0x5678...",
"value": "512"
},
{
"id": "0x01000000",
"from": "0xijkl...",
"to": "0x9abc...",
"value": "1"
}
]
}
}

As IDs são retornadas como hex.

Para melhorar a organização, devemos criar outro campo na entidade que seja um BigInt.

type Transfer @entity {
id: Bytes!
from: Bytes! # address
to: Bytes! # address
value: BigInt! # unit256
tokenId: BigInt! # uint256
}

Isto otimizará sequencialmente a organização.

Query:

{
transfers(first: 3, orderBy: tokenId) {
id
tokenId
}
}

Resposta de query:

{
"data": {
"transfers": [
{
"id": "0x…",
"tokenId": "1"
},
{
"id": "0x…",
"tokenId": "2"
},
{
"id": "0x…",
"tokenId": "3"
}
]
}
}

É comprovado que usar Entidades Imutáveis e Bytes como IDs aumenta muito a eficiência de subgraphs. Especificamente, segundo testes, houve um aumento de até 28% no desempenho de queries e uma aceleração de até 48% em velocidades de indexação.

Leia mais sobre o uso de Entidades Imutáveis e Bytes como IDs nesta publicação por David Lutterkort, Engenheiro de Software na Edge & Node: Duas Melhorias Simples no Desempenho de Subgraphs.

Editar página

Anterior
Subgraph Best Practice 2: Manage Arrays with @derivedFrom
Próximo
Subgraph Best Practice 4: Avoid eth_calls
Editar página