Каков наилучший способ реализации разбивки на вложенные курсоры с помощью базы данных SQL на сервере GraphQL? - PullRequest
1 голос
/ 11 июля 2019

Как вы управляете эффективной выборкой данных с помощью вложенных курсоров в схеме relay-esk (с источником данных SQL)?

  1. Вы пытаетесь сделать один сложный запрос SQL, чтобы решить проблему N + 1 с помощью «LIMIT args_first», «ORDER BY args_orderby» и «WHERE cursor>: args_after»
  2. Вы запускаете 2 запроса к БД и используете загрузчик данных facebook?

Например, у меня есть схема, структурированная как показано ниже:

enum BookSortKeys {
    ID,
    TITLE,
    PRICE,
    UPDATED_AT,
    CREATED_AT
}
enum ReviewSortKeys {
    ID,
    REVIEW,
    UPDATED_AT,
    CREATED_AT
}
type Book {
  id: ID!
  title: String!
  description: String
  price: Float!
  updatedAt: String!
  createdAt: String!
  reviews("""
    Returns the elements that come after the specified cursor.
    """
    after: String
    """
    Returns the elements that come before the specified cursor.
    """
    before: String
    """
    Returns up to the first `n` elements from the list.
    """
    first: Int
    """
    Returns up to the last `n` elements from the list.
    """
    last: Int
    """
    Reverse the order of the underlying list.
    """
    reverse: Boolean = false
    """
    Sort the underlying list by the given key.
    """
    sortKey: ReviewSortKeys = ID): ReviewConnection!
}
type Query {
  books("""
    Returns the elements that come after the specified cursor.
    """
    after: String
    """
    Returns the elements that come before the specified cursor.
    """
    before: String
    """
    Returns up to the first `n` elements from the list.
    """
    first: Int
    """
    Returns up to the last `n` elements from the list.
    """
    last: Int
    """
    Supported filter parameters:
     - `title`
     - `id`
     - `price`
     - `description`
     - `created_at`
     - `updated_at`
    """
    query: String
    """
    Reverse the order of the underlying list.
    """
    reverse: Boolean = false
    """
    Sort the underlying list by the given key.
    """
    sortKey: BookSortKeys = ID): BookConnection!
}
type ReviewConnection {
    pageInfo: PageInfo!
    edges: [ReviewEdge!]!
}
type ReviewEdge {
    cursor: String!
    node: Review!
}
type BookConnection {
    pageInfo: PageInfo!
    edges: [BookEdge!]!
}
type BookEdge {
    cursor: String!
    node: Book!
}
type PageInfo {
    hasNextPage: Boolean!
    hasPreviousPage: Boolean!
}
type Review {
    review: String!
    id: ID!
    updatedAt: String!
    createdAt: String!
}
type Mutation {
}
schema {
  query: Query
  mutation: Mutation
}

И я хотел бы выполнить запрос, подобный приведенному ниже, и извлечь данные наиболее эффективным способом.

query GET_BOOKS {
  books(first:10, sortKey: PRICE, reverse: true) {
       pageInfo {
      hasNextPage
      hasPreviousPage
    } 
    edges {
      cursor
      node {
        id
        title
        description
        reviews(after:"base64-cursor" first: 5, sortKey: CREATED_AT) {
          edges {
            node{
              review
            }
          }
        }
      }
    }
  }
}

Я могу очень легко преобразовать все параметры разбивки на страницы для верхнего запроса (книги) в оператор SQL, но с помощью вложенного курсора я вижу только 2 варианта (упомянутых выше) ... текущие проблемы, с которыми я сталкивался раньше Реализация этих вариантов:

  1. Если я использую подход, основанный на чистом SQL, - существует ли хотя бы чистый способ выполнить один запрос и применить LIMIT и WHERE createdAt > :after_cursor_val на уровне вложенности (JOIN)
  2. Если вышеприведенное возможно, является ли оно более производительным, чем загрузчик данных в масштабе? Поскольку запрос кажется достаточно подробным и сложным, если он будет реализован.
  3. Что произойдет, если вложенное дерево нумерации страниц будет расти (то есть запросы с 4 вложенными нумерациями страниц)? Будет ли здесь достаточной команда sql на уровне объекта Query? или более масштабируемым является добавление преобразователей в каждое отношение (т. е. книга -> обзоры имеет запрос sql для извлечения всех рецензий этой книги, обзоры -> публикации имеет запрос для извлечения всех конкретных публикаций рецензии, в которых она находилась, и т. д., и пакетируйте их в загрузчик данных)
  4. если вы идете по маршруту загрузчика данных, пакетная обработка, похоже, использует предложение "WHERE IN" (т. Е. SELECT * FROM reviews "reviews" WHERE "reviews".bookId IN (...list of book ids batched) - добавление LIMIT, ORDER BY и WHERE createdAt > :cursor даст неожиданные результаты, так как мой набор результатов является сочетание записей в нескольких «идентификаторах книг»?
  5. В долгосрочной перспективе, мое личное мнение таково, что чистый SQL-подход будет беспорядочным с точки зрения кода, мысли об этом?
...