首页 > 解决方案 > 300k 文档的 MongoDB 查询耗时超过 30 秒

问题描述

好的,如标题中所述,我有“性能问题”,我需要从集合中获取所有文档,但这需要很长时间。Players 集合包含大约 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 本机驱动程序。如果我删除投影,几乎需要一分钟。

知道如何改进吗?

标签: mongodbnestjsfastify

解决方案


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

促进

'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 代理默认添加它,而无需在业务逻辑服务器中实现它。


推荐阅读