Joystream / pioneer

Governance app for Joystream DAO
https://pioneerapp.xyz/
GNU General Public License v3.0
44 stars 70 forks source link

Check breadcrumbs queries performance #1158

Open jodator opened 3 years ago

jodator commented 3 years ago

So, the runtime depth is 6. However, I wonder if we should do this query with every request for the category (to double-check with the wireframes and where we need breadcrumbs).

The question here is whether to query like that or try to take advantage of the Apollo query caching. Apollo client will cache the categories that were previously fetched IIRC it will cache based on the query/response fields.

So if we have a category tree 1 -> 2 -> 3 -> 4 -> 5 we could fetch one by one in the reverse order ( 5 then 4 then 3, etc). This might be challenging using react hooks as we can't use hooks in loops.

A simple solution would be a multi-category query, that expands while getting more parents:

However, this might re-query those for every category, as the starting query will always query the initial category (5). So, we'd need to investigate how Apollo's cache works. To see if my assumptions are correct or not.

_Originally posted by @jodator in https://github.com/Joystream/pioneer/pull/1157#discussion_r680931523_

traumschule commented 2 years ago

However, this might re-query those for every category, as the starting query will always query the initial category (5).

The currently merged solution queries all 6 levels in one go so maybe there's no need to clarify anymore.

IIUIC 5 would be served from cache for consecutive requests and possibly even parts of 4 if they were part of the first response.

Apollo Client's InMemoryCache stores data as a flat lookup table of objects that can reference each other. These objects correspond to the objects that are returned by your GraphQL queries. A single cached object might include fields returned by multiple queries, if those queries fetch different fields of the same object. First, the cache identifies all of the distinct objects included in a query response. Next, the cache takes each field that contains an object and replaces its value with a reference to the appropriate object. Later, if you query for another Person who has the same homeworld, that normalized Person object will contain a reference to the same cached object!

Request 1

query GetForumCategoryBreadcrumbs($id: ID!) { forumCategories(where:{id_eq: 5}) {
  ...ForumSubCategoryFields
  parent {
    ...ForumSubCategoryFields
    parent {
      ...ForumSubCategoryFields
      parent {
        ...ForumSubCategoryFields
        parent {
          ...ForumSubCategoryFields
          parent {
            ...ForumSubCategoryFields
            parent {
              ...ForumSubCategoryFields

Response

{
  "id": "5",
  "title": "",
  "parent": {
    "id": "4",
    "title": "",
    "parent": {
      "id": "3",
      "title": "",
      "parent": {
        "id": "2",
        "title": "",
        "parent": {
          "id": "1",
          "title": ""
        }
      }
    }
  }
}

Request 2

query GetForumCategoryBreadcrumbs($id: ID!) { forumCategories(where:{id_eq: 4}) {
  ...ForumSubCategoryFields
  parent { ... // again 5 more levels

In theory id, title and parent will be served from cache for 4, 3, 2, including id and title for 1. The resulting query would only ask for parent of 1 (returning null):

query GetForumCategoryBreadcrumbs($id: ID!) { forumCategories(where:{id_eq: 1}) {
  parent { ...ForumSubCategoryFields }

Response

  "data": {
    "forumCategories": [
      {
        "parent": null
      }

Example

query { forumCategories(where:{id_eq: 5}) {
 id title parent { id title parent { id title } parent { id title } parent { id title } parent { id title } parent { id title }}
}}

Actual response:

  "data": {
    "forumCategories": [
      {
        "id": "5",
        "title": "Budgets",
        "parent": {
          "id": "3",
          "title": "Governance",
          "parent": null
        }

There's no need for further queries.