【问题标题】:Pagination in Prisma with Cursor is Slow使用光标在 Prisma 中分页很慢
【发布时间】:2021-12-31 14:24:19
【问题描述】:

我已经尝试了两种方法(光标和偏移)来对我的 ~1000 文档数据库进行分页,但是,我无法让光标比偏移快。

// cursor method
    const allDocs = []
    let queryResults = await prismaClient.obsidian.findMany({
        take: 100
    })
    while (queryResults.length > 0) {
        allDocs.push(...queryResults)
        queryResults = await prismaClient.obsidian.findMany({
            take: 100,
            skip: 1,
            cursor: {
                id: queryResults[queryResults.length - 1]!.id
            }
        })
    }
    return allDocs

需要 ~25 秒才能完成(注意:它似乎也在使用 OFFSET,我认为它不应该这样做?)

Query: SELECT "public"."obsidian"."id", "public"."obsidian"."doc", "public"."obsidian"."createdAt", "public"."obsidian"."updatedAt", "public"."obsidian"."filename" FROM "public"."obsidian", (SELECT "public"."obsidian"."id" AS "obsidian_id_0" FROM "public"."obsidian" WHERE ("public"."obsidian"."id") = ($1)) AS "order_cmp" WHERE "public"."obsidian"."id" >= "order_cmp"."obsidian_id_0" ORDER BY "public"."obsidian"."id" ASC LIMIT $2 **OFFSET** $3
    // offset method
    const count = await prismaClient.obsidian.count()
    const pages = Math.ceil(count / 100)
    const allDocsPromises = []
    for (let i = 0; i < pages; i++) {
        const page = prismaClient.obsidian.findMany({
            skip: i * 100,
            take: 100
        })
        allDocsPromises.push(page)
    }
    const allDocs = await Promise.all(allDocsPromises)
    return _.flatten(allDocs)

需要 ~14 秒才能完成。我的想法是 offset 方法由于 Promise.all() 而运行得更快,但是有没有办法让光标分页以超快的速度返回所有文档?

【问题讨论】:

    标签: node.js postgresql prisma


    【解决方案1】:

    首先,基于光标的分页不使用OFFSET,在doc 中提到了这一点。

    其次,您对Promise.all 的想法是可以的。使用Promise.all进行并行处理,使用for进行顺序处理(我认为问题在于顺序处理)。

    最后,你来post 了解基于光标的分页的好处,尽情享受吧:)

    【讨论】:

      【解决方案2】:

      Prisma 称之为光标分页,其他人称之为“键集”分页。不涉及实际的游标。但是这将是多么有效取决于查询的其余部分,以及是否拥有正确的索引,我们都无法使用提供的信息进行评估。既然您无论如何都是在一个紧密的循环中将所有数据读入内存,为什么不直接读取它并省略分页呢?

      【讨论】:

      • 感谢您的回答!这可能是我的模型的结构方式(我在 JSON 中存储了非常大的 2D 向量),但是使用 findMany() 会因 GenericError 而超时。所以我添加了分页来一次获取位发送到内存。
      猜你喜欢
      • 2018-11-30
      • 2015-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多