简体   繁体   中英

MongoDb Node.js slow concurrent queries

When I run concurrent MongoDb queries using Node.js, the second query always takes ~2 seconds to return. Using explain() , executionTimeMillis always returns 0ms, which is absolutely normal as my test collection has only 2 entries. Here's my reduced testcase:

'use strict'

const { MongoClient } = require('mongodb')

const main = async () => {
    const client = new MongoClient('mongodb://admin:123456@localhost:27017/', {
        useNewUrlParser: true,
        useUnifiedTopology: true,
    })

    await client.connect()

    const db = client.db('test')
    const numbers = db.collection('numbers')

    const promises = []

    console.time()

    for (let i = 0; i < 3; i++) {
        promises.push(numbers.find({ number: i }).explain())
    }

    for (const promise of promises) {
        console.log(await promise)
        console.timeLog()
    }

    console.timeEnd()

    await client.close()
}

main()

Output:

{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'test.numbers',
    indexFilterSet: false,
    parsedQuery: { number: [Object] },
    winningPlan: { stage: 'FETCH', inputStage: [Object] },
    rejectedPlans: []
  },
  executionStats: {
    executionSuccess: true,
    nReturned: 1,
    executionTimeMillis: 0,
    totalKeysExamined: 1,
    totalDocsExamined: 1,
    executionStages: {
      stage: 'FETCH',
      nReturned: 1,
      executionTimeMillisEstimate: 0,
      works: 2,
      advanced: 1,
      needTime: 0,
      needYield: 0,
      saveState: 0,
      restoreState: 0,
      isEOF: 1,
      invalidates: 0,
      docsExamined: 1,
      alreadyHasObj: 0,
      inputStage: [Object]
    },
    allPlansExecution: []
  },
  serverInfo: {
    host: 'DESKTOP-C7CAL9N',
    port: 27017,
    version: '4.0.10',
    gitVersion: 'c389e7f69f637f7a1ac3cc9fae843b635f20b766'
  },
  ok: 1
}
default: 32.252ms
{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'test.numbers',
    indexFilterSet: false,
    parsedQuery: { number: [Object] },
    winningPlan: { stage: 'FETCH', inputStage: [Object] },
    rejectedPlans: []
  },
  executionStats: {
    executionSuccess: true,
    nReturned: 1,
    executionTimeMillis: 0,
    totalKeysExamined: 1,
    totalDocsExamined: 1,
    executionStages: {
      stage: 'FETCH',
      nReturned: 1,
      executionTimeMillisEstimate: 0,
      works: 2,
      advanced: 1,
      needTime: 0,
      needYield: 0,
      saveState: 0,
      restoreState: 0,
      isEOF: 1,
      invalidates: 0,
      docsExamined: 1,
      alreadyHasObj: 0,
      inputStage: [Object]
    },
    allPlansExecution: []
  },
  serverInfo: {
    host: 'DESKTOP-C7CAL9N',
    port: 27017,
    version: '4.0.10',
    gitVersion: 'c389e7f69f637f7a1ac3cc9fae843b635f20b766'
  },
  ok: 1
}
default: 2042.929ms
{
  queryPlanner: {
    plannerVersion: 1,
    namespace: 'test.numbers',
    indexFilterSet: false,
    parsedQuery: { number: [Object] },
    winningPlan: { stage: 'FETCH', inputStage: [Object] },
    rejectedPlans: []
  },
  executionStats: {
    executionSuccess: true,
    nReturned: 0,
    executionTimeMillis: 0,
    totalKeysExamined: 0,
    totalDocsExamined: 0,
    executionStages: {
      stage: 'FETCH',
      nReturned: 0,
      executionTimeMillisEstimate: 0,
      works: 1,
      advanced: 0,
      needTime: 0,
      needYield: 0,
      saveState: 0,
      restoreState: 0,
      isEOF: 1,
      invalidates: 0,
      docsExamined: 0,
      alreadyHasObj: 0,
      inputStage: [Object]
    },
    allPlansExecution: []
  },
  serverInfo: {
    host: 'DESKTOP-C7CAL9N',
    port: 27017,
    version: '4.0.10',
    gitVersion: 'c389e7f69f637f7a1ac3cc9fae843b635f20b766'
  },
  ok: 1
}
default: 2062.851ms
default: 2063.513ms

If I run queries consequentially, each query takes only some milliseconds to return. Then why is the 2 seconds response time?

Edit:

In the first for loop, I made/ran "concurrent" queries promises.push(numbers.find({ number: i }).explain()) . In the second for loop, I wait for promises to resolve one after another but that doesn't mean that a promise must wait till the previous one resolved to begin its job.

To avoid misunderstandings, I've made a little changes to my code, replacing the two for loops with this:

    for (let i = 0; i < 3; i++) {
        promises.push(
            numbers
                .find({ number: i })
                .explain()
                .then(result => {
                    // console.log(result)
                    console.log('query index:', i)
                    console.timeLog()
                })
        )
    }

    await Promise.all(promises)

Output:

query index: 0
default: 22.040ms
query index: 2
default: 2032.921ms
query index: 1
default: 2034.682ms
default: 2035.260ms

Edit 2:

For further clarification, I use labels to denote timers.

    for (let i = 0; i < 3; i++) {
        console.time(`query index: ${ i }`)

        promises.push(
            numbers
                .find({ number: i })
                .explain()
                .then(result => {
                    // console.log(result)
                    console.timeEnd(`query index: ${ i }`)
                })
        )
    }

    await Promise.all(promises)

Output:

query index: 0: 12.692ms
query index: 1: 2015.143ms
query index: 2: 2015.310ms

Set MongoClient's poolSize to 1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM