首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带游标的Prisma分页速度慢

带游标的Prisma分页速度慢
EN

Stack Overflow用户
提问于 2021-12-31 01:38:20
回答 3查看 1.7K关注 0票数 0

我尝试过这两种方法(游标和偏移量)通过我的~1000 doc分页,但是,我不能让游标比偏移量更快。

代码语言:javascript
复制
// 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,我以为它不应该这么做?)

代码语言:javascript
复制
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
代码语言:javascript
复制
    // 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()而运行得更快,但是是否有一种方法可以使光标分页以超快的速度返回所有文档?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-08-07 19:21:28

Prisma正在使用一些内部机制来缓冲数据,以加速和解决N+1问题。但在某些情况下,这会导致业绩不佳。

这是一个prisma中间件,可以绕过它的机制并加快速度。如果你认为你跑得慢,你可以试一试。

代码语言:javascript
复制
prisma.$use(async (params, next) => {
    if (params.args?.cursor) {
      const key = _.lowerFirst(params.model)
      const result = await prisma[key].findUniqueOrThrow({
        where: params.args.cursor,
        select: params.args.orderBy ? _(params.args.orderBy).mapValues(x => true).value() : undefined,
      })
      params.args.where = {
        ...params.args.where,
        ..._(params.args.cursor).mapValues((x, k) => ({
          [x === 'desc' ? 'lte' : 'gte']: result[k],
        })).value(),
        ..._(params.args.orderBy).mapValues((x, k) => ({
          [x === 'desc' ? 'lte' : 'gte']: result[k],
        })).value(),
      }
      delete params.args.cursor
    }
    return await next(params)
  })
票数 2
EN

Stack Overflow用户

发布于 2021-12-31 04:07:26

首先,基于光标的分页不使用偏移量,在文档中提到了这一点。

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

最后,这里来一个关于基于光标的分页的好处的帖子,请欣赏它:)

票数 2
EN

Stack Overflow用户

发布于 2021-12-31 06:24:19

Prisma所称的游标分页,其他人称之为“键集”分页。不涉及实际的游标。但是它的效率将取决于查询的其余部分,以及是否有正确的索引(Es),这两个索引我们都不能用提供的信息来评估。既然您正在将所有数据读入内存中,那么为什么不直接读取它并省略分页呢?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70538263

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档