Docs
搜索⌘ K
  • 主页
  • 关于 The Graph
  • 支持的网络
  • 协议合约
  • 子图
    • 子流
      • 代币 API
        • Hypergraph
          • AI Suite
            • 索引
              • 资源
                子图 > 最佳实践

                6 分钟

                子图最佳实践3-通过使用Immutable Entities和Bytes作为ID来提高索引和查询性能

                TLDR

                在schema.graphql文件中使用Immutable Entities和Bytes作为ID显著改进索引速度和查询性能。

                不可变实体

                为了使一个实体不可变,我们只需在实体中添加(immutable:true)。

                1type Transfer @entity(immutable: true) {2  id: Bytes!3  from: Bytes!4  to: Bytes!5  value: BigInt!6}

                通过使Transfer实体不可变,graph-node能够更有效地处理实体,提高索引速度和查询响应能力。

                Immutable Entities structures will not change in the future. An ideal entity to become an Immutable Entity would be an entity that is directly logging on-chain event data, such as a Transfer event being logged as a Transfer entity.

                在后台

                可变实体有一个块范围表示其有效性。更新这些实体需要graph节点调整以前版本的块范围,从而增加数据库工作负载。查询还需要筛选,以便只找到活动实体。不可变实体更快,因为都是活的,而且不会改变,在写入时不需要检查或更新,在查询时也不需要筛选。

                何时不使用不可变实体

                如果你有一个类似字段的状态需要随着时间的推移而修改,那么你不应该让实体不可变。否则,您应该尽可能使用不可变实体。

                字节作为ID

                每个实体都需要一个ID。在前面的示例中,我们可以看到ID已经是Bytes类型。

                1type Transfer @entity(immutable: true) {2  id: Bytes!3  from: Bytes!4  to: Bytes!5  value: BigInt!6}

                虽然其他类型的ID也是可能的,如String和Int8,但建议对所有ID使用Bytes类型,因为字符串存储二进制数据所需的空间是Byte字符串的两倍,并且UTF-8字符串的比较必须考虑到区域设置,这比用于比较Byte串的逐字节比较要昂贵得多。

                不使用字节作为ID的原因

                1. 如果实体ID必须是人类可读的,例如自动递增的数字ID或可读字符串,则不应使用Bytes 作为 ID。
                2. 如果将子图的数据与不使用Bytes作为ID的另一个数据模型集成,则不应使用Bytes 作为 ID。
                3. 索引和查询性能的改进是不可取的。

                以Bytes作为ID连接

                在许多子图中,使用字符串连接将事件的两个属性组合成一个ID是一种常见的做法,例如使用event.transaction.hash.toHex()+“-”+event.logIndex.toString()。然而,由于这会返回一个字符串,将严重阻碍子图索引和查询性能。

                相反,我们应该使用concatI32()方法来连接事件属性。此策略产生了性能更高的BytesID。

                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排序

                如本示例查询和响应所示,使用字节作为ID进行排序不是最佳选择。

                查询:

                1{2  transfers(first: 3, orderBy: id) {3    id4    from5    to6    value7  }8}

                查询响应:

                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以十六进制返回。

                为了改进排序,我们应该在BigInt实体上创建另一个字段。

                1type Transfer @entity {2  id: Bytes!3  from: Bytes! # address4  to: Bytes! # address5  value: BigInt! # unit2566  tokenId: BigInt! # uint2567}

                这将允许按顺序优化排序。

                查询:

                1{2  transfers(first: 3, orderBy: tokenId) {3    id4    tokenId5  }6}

                查询响应:

                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}

                结论

                使用Immutable Entities和Bytes作为ID已被证明可以显著提高子图效率。具体来说,测试表明查询性能提高了28%,索引速度提高了48%。

                在Edge&Node的软件工程师David Lutterkort的这篇博客文章中,可以阅读到更多关于使用Immutable Entities和字节作为ID的信息:两个简单的子图性能改进。

                子图最佳实践1-6

                1. 通过子图修剪提高查询速度

                2. 使用@derivedFrom提高索引和查询响应能力

                3. 通过使用不可变实体和字节作为ID来提高索引和查询性能

                4. 通过避免eth_calls提高索引速度

                5. 通过时间序列和聚合进行简化和优化

                6. 使用嫁接快速部署修补程序

                ⁠在GitHub上编辑⁠

                带有@derivedFrom的数组避免eth_calls
                在此页面上
                • TLDR
                • 不可变实体
                • 在后台
                • 何时不使用不可变实体
                • 字节作为ID
                • 不使用字节作为ID的原因
                • 以Bytes作为ID连接
                • 以Bytes作为ID排序
                • 结论
                • 子图最佳实践1-6
                The GraphStatusTestnetBrand AssetsForum安全Privacy PolicyTerms of Service