【问题标题】:MongoDB query with 300k documents takes more than 30 seconds300k 文档的 MongoDB 查询耗时超过 30 秒
【发布时间】:2021-07-18 15:19:05
【问题描述】:

好的,正如标题中所说,我有“性能问题”,我需要从集合中获取所有文档,但这需要太长时间。玩家集合包含大约 300k 个小文件,服务中的查询如下:

async getAllPlayers() {
  const players = await this.playersCollection.find({}, {projection: { playerId: 1, name: 1, surname: 1, shirtNumber: 1, position: 1 }}).toArray();

  return players;
}

总大小为 6.4MB。我正在使用 Fastify 适配器、fastify-compress 和 mongodb 本机驱动程序。如果我删除投影,大约需要一分钟。

知道如何改进吗?

【问题讨论】:

  • 尽量不要一次获取所有数据,使用limit并从mongodb中分块跳过读取数据
  • 您是否尝试过调整批量大小?
  • 你能分页你的端点吗?
  • 谢谢大家,最终将限制为 10k 并在滚动上加载更多内容。 10k 需要 980 毫秒,非常完美。

标签: mongodb nestjs fastify


【解决方案1】:

我得到的最佳时间是 8 秒,其中 fast-json-stringify 给我超过 10 秒的提升超过 30 万条记录:

'use strict'
// run fresh mongo
// docker run --name temp --rm -p 27017:27017 mongo

const fastify = require('fastify')({ logger: true })
const fjs = require('fast-json-stringify')

const toString = fjs({
  type: 'object',
  properties: {
    playerId: { type: 'integer' },
    name: { type: 'string' },
    surname: { type: 'string' },
    shirtNumber: { type: 'integer' },
  }
})

fastify.register(require('fastify-mongodb'), {
  forceClose: true,
  url: 'mongodb://localhost/mydb'
})


fastify.get('/', (request, reply) => {
  const dataStream = fastify.mongo.db.collection('foo')
    .find({}, {
      limit: 300000,
      projection: { playerId: 1, name: 1, surname: 1, shirtNumber: 1, position: 1 }
    })
    .stream({
      transform(doc) {
        return toString(doc) + '\n'
      }
    })

  reply.type('application/jsonl')
  reply.send(dataStream)
})

fastify.get('/insert', async (request, reply) => {
  const collection = fastify.mongo.db.collection('foo')

  const batch = collection.initializeOrderedBulkOp();

  for (let i = 0; i < 300000; i++) {
    const player = {
      playerId: i,
      name: `Name ${i}`,
      surname: `surname ${i}`,
      shirtNumber: i
    }
    batch.insert(player);
  }

  const { result } = await batch.execute()
  return result
})

fastify.listen(8080)

无论如何,您应该考虑:

  • 对输出进行分页
  • 或将数据推送到存储桶(如 S3)并返回给客户端一个 URL 以直接下载文件,这将大大加快进程并从该数据流中节省您的 node.js 进程

请注意,node.js 中的压缩是一个繁重的过程,因此会大大降低响应速度。 nginx 代理默认添加它,无需在您的业务逻辑服务器中实现它。

【讨论】:

  • 哇!一定会试试的!
猜你喜欢
  • 2014-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-14
相关资源
最近更新 更多