2. n+1 问题
10m

概述

我们的API 已准备好提供一些基本列表数据。我们可以运行 查找特色列表,也可以专门查找某个列表。

此外,对于每个列表,我们还可以 获取有关每个 Amenity它必须提供的详细信息。但现在,我们在实现过程中遇到了一个重大的性能问题。

在此课程中,我们将

  • 了解 n+1 问题
  • 讨论如何解决此问题

列表和便利设施

为了了解我们性能瓶颈的实际情况,我们针对 API 运行一个测试 。它会查询一个特色列表,以及每个列表的便利设施的一些基本详细信息。

A mock-up for Airlock, showing a row of featured listings and their amenities

确保应用的运行方式是在项目的根目录中运行以下命令。

npm run dev

现在,让我们导航至Apollo Sandbox Explorer. 默认情况下,我们的服务器应该在 https://127.0.0.1:4000上运行。

https://127.0.0.1:4000
https://studio.apollographql.com/sandbox/explorer

A screenshot of the Apollo Sandbox Explorer, highlighting the connection input with the locally running server's address

让我们通过从 Query 类型中的 文档 面板中选择 featuredListings 来开始我们的 。对于我们 的每个特色房源,我们将请求基本信息:仅 idtitle,以及其 amenities 列表。

对于房源享有的每个 Amenity,我们将返回 idnamecategory

以下是我们的 的样子。

一个查询特色房源及其便利设施
query GetFeaturedListingsAmenities {
featuredListings {
id
title
amenities {
id
name
category
}
}
}

让我们尝试一下这个 ,然后... 我们得到了数据!太棒了。那么问题究竟出在哪里?

为了找出原因,我们将仔细查看服务器正在运行的终端。再次运行 ,然后... 你注意到了吗?终端被记录语句填满:

我们每次调用 REST API 的输出
Calling for featured listings
Calling for amenities for listing listing-1
Calling for amenities for listing listing-2
Calling for amenities for listing listing-3

首先,我们看到一行日志记录显示我们对特色列表发起了调用。然后,我们看到为每个列表 ID 打印出一行;并且每行代表一个单个请求,该请求通过网络发送到我们的。我们精简而准确的 产生的请求数量可能多于我们的预期!我们深入了解一下这里发生的情况。

对于每个列表,都是一个新的请求

这里的问题在于,我们针对特色列表列表发出一个请求,并针对每个列表的便利设施列表发出一个其他请求。

以下是关于如何解决精选房源及其便利设施的的细分。

要获取精选房源列表,我们的首先调用ListingAPI方法,该方法向GET /featured-listings端点发出请求。这会返回包含我们的基本房源详细信息的 JSON 对象。

A diagram showing the data that is returned when we query for featured listings

但此响应实际上并不包含有关房源便利设施的任何信息。这意味着我们会对每个房源发出另一个请求GET /listings/{listing_id}/amenities,并传入其 ID 作为{listing_id}参数。

A diagram showing the followup request needed for each listing's amenities

这个额外的请求会获取我们需要的便利设施数据,但它有一个隐藏的成本:每次执行Listing.amenities 时,我们会针对便利设施数据向 REST API 发出新的请求。

n+1 问题

这就是n+1 问题正在执行中。我们从一个初始请求(1n+1等式中)开始,而这个初始请求确定了需要多少个后续请求(nn+1等式中)。必需的后续请求数量n在执行我们的第一个请求之前是未知的。

我们看到这个问题:我们的第一个请求会给我们精选列表(有三个),但我们随后需要每个列表的后续请求来获得列表的便利设施数据。

只有 1 到 2 个附加请求看起来不是太糟糕,但随着查询的扩展,这会导致一些令人担忧的情况。假设一个列表包含二十五个列表(“25 大零下夏季目的地”!),填充这样的列表数据意味着我们需要发送总计 26 个请求!请求获取列表数据,以及 25 个附加请求来获取每个列表的便利设施信息!

实践

以下哪些情况说明了 n+1 问题?

关键要点

  • 当我们发出一个初始请求,随后是未知数量的后续请求时,就会发生 n+1 问题。

接下来是

让我们深入研究数据加载器以及它们如何帮助我们解决这个讨厌的问题。

上一个

分享您对这节课的问题和意见

此课程当前采用

beta
.您的反馈有助于我们的提升!如果您遇到问题或感到困惑,请告诉我们,我们会帮助您的。所有评论都是公开的,必须遵循 Apollo 行为准则。请注意,已解决或已处理的评论可能会被删除。

您需要一个 GitHub 帐户才能发布以下内容。没有一个帐户? 改为在我们的 Odyssey 论坛中发帖。