如果我在一次更新中使用多个“$set”,是否存在性能问题

问题描述 投票:0回答:1

mongodb中的数据是这样的

{
    "_id": "1",
    "a": 1,
    "b": 2,
    "c": 3
    "d": 4
}

我可以使用单个“$set”运算符更新文档。

db.collection.update({"_id": "1"}, {
        "$set": {
            "a": 100,
            "b": 200,
            "c": 300,
            "d": 400
        }
    })

我还可以使用多个“$set”更新文档(每个字段都有一个“$set”)。

db.collection.update({"_id": "1"}, [
        {
            "$set": { "a": 100 }
        },
        {
            "$set": { "b": 200 }
        },
        {
            "$set": { "c": 300 }
        },
        {
            "$set": { "d": 400 }
        }
    ])

我想知道使用“多集”版本对mongodb端是否有任何性能问题。如果在某些情况下我需要的话,可以使用“多集”版本吗?

mongodb mongodb-query
1个回答
0
投票

对于您的情况,我认为性能差异即使不是没有,也会微不足道。他们的

explain
计划几乎相同。

explain
单个
$set
输出:

{
  "$clusterTime": {
    "clusterTime": Timestamp(1734276869, 3),
    "signature": {
      "hash": BinData(0, "tRv1PQVgmouDxOtttOdSk2z0O1U="),
      "keyId": NumberLong(7394893876424605697)
    }
  },
  "command": {
    "$db": "75f38391413d12711811639fd9b97e4f",
    "filter": {},
    "find": "collection",
    "maxTimeMS": NumberLong(20000)
  },
  "executionStats": {
    "allPlansExecution": [],
    "executionStages": {
      "advanced": 1,
      "direction": "forward",
      "docsExamined": 1,
      "executionTimeMillisEstimate": 0,
      "isEOF": 1,
      "nReturned": 1,
      "needTime": 0,
      "needYield": 0,
      "restoreState": 0,
      "saveState": 0,
      "stage": "COLLSCAN",
      "works": 2
    },
    "executionSuccess": true,
    "executionTimeMillis": 0,
    "nReturned": 1,
    "totalDocsExamined": 1,
    "totalKeysExamined": 0
  },
  "explainVersion": "1",
  "operationTime": Timestamp(1734276869, 3),
  "queryPlanner": {
    "indexFilterSet": false,
    "maxIndexedAndSolutionsReached": false,
    "maxIndexedOrSolutionsReached": false,
    "maxScansToExplodeReached": false,
    "namespace": "75f38391413d12711811639fd9b97e4f.collection",
    "parsedQuery": {},
    "planCacheKey": "5F5FC979",
    "queryHash": "5F5FC979",
    "rejectedPlans": [],
    "winningPlan": {
      "direction": "forward",
      "stage": "COLLSCAN"
    }
  },
  "serverParameters": {
    "internalDocumentSourceGroupMaxMemoryBytes": 104857600,
    "internalDocumentSourceSetWindowFieldsMaxMemoryBytes": 104857600,
    "internalLookupStageIntermediateDocumentMaxSizeBytes": 104857600,
    "internalQueryFacetBufferSizeBytes": 104857600,
    "internalQueryFacetMaxOutputDocSizeBytes": 104857600,
    "internalQueryMaxAddToSetBytes": 104857600,
    "internalQueryMaxBlockingSortMemoryUsageBytes": 104857600,
    "internalQueryProhibitBlockingMergeOnMongoS": 0
  }
}

蒙戈游乐场

explain
多个
$set
输出:

{
  "$clusterTime": {
    "clusterTime": Timestamp(1734276224, 3),
    "signature": {
      "hash": BinData(0, "QUsSlU1zBAvtbFAgbv3/fA7RENU="),
      "keyId": NumberLong(7394893876424605697)
    }
  },
  "command": {
    "$db": "3d58f286ab6b7455181163098d794665",
    "filter": {},
    "find": "collection",
    "maxTimeMS": NumberLong(20000)
  },
  "executionStats": {
    "allPlansExecution": [],
    "executionStages": {
      "advanced": 1,
      "direction": "forward",
      "docsExamined": 1,
      "executionTimeMillisEstimate": 0,
      "isEOF": 1,
      "nReturned": 1,
      "needTime": 0,
      "needYield": 0,
      "restoreState": 0,
      "saveState": 0,
      "stage": "COLLSCAN",
      "works": 2
    },
    "executionSuccess": true,
    "executionTimeMillis": 0,
    "nReturned": 1,
    "totalDocsExamined": 1,
    "totalKeysExamined": 0
  },
  "explainVersion": "1",
  "operationTime": Timestamp(1734276224, 3),
  "queryPlanner": {
    "indexFilterSet": false,
    "maxIndexedAndSolutionsReached": false,
    "maxIndexedOrSolutionsReached": false,
    "maxScansToExplodeReached": false,
    "namespace": "3d58f286ab6b7455181163098d794665.collection",
    "parsedQuery": {},
    "planCacheKey": "5F5FC979",
    "queryHash": "5F5FC979",
    "rejectedPlans": [],
    "winningPlan": {
      "direction": "forward",
      "stage": "COLLSCAN"
    }
  },
  "serverParameters": {
    "internalDocumentSourceGroupMaxMemoryBytes": 104857600,
    "internalDocumentSourceSetWindowFieldsMaxMemoryBytes": 104857600,
    "internalLookupStageIntermediateDocumentMaxSizeBytes": 104857600,
    "internalQueryFacetBufferSizeBytes": 104857600,
    "internalQueryFacetMaxOutputDocSizeBytes": 104857600,
    "internalQueryMaxAddToSetBytes": 104857600,
    "internalQueryMaxBlockingSortMemoryUsageBytes": 104857600,
    "internalQueryProhibitBlockingMergeOnMongoS": 0
  }
}

蒙戈游乐场

考虑到示例中仅更新 1 个文档的查询模式,并且您通过

_id
获取,我认为不会有任何可观察到的性能差异。

除了性能之外,还有 2 个注意事项:

  1. 如果在您的实际用例中,您依赖于
    $set
    操作,则需要将它们分成不同的阶段

例如你

$set
a 为 c * d = 12,b 为 a + 1 = 12 + 1 = 13。你需要做:

db.collection.update({
  "_id": "1"
},
[
  {
    "$set": {
      "a": {
        "$multiply": [
          "$c",
          "$d"
        ]
      }
    }
  },
  {
    "$set": {
      "b": {
        "$add": [
          "$a",
          1
        ]
      }
    }
  }
])

蒙戈游乐场

单个

$set
不会给你预期的结果 b = 13,而是 2,因为 a 尚未被评估为 12(保留 1 作为值)

db.collection.update({
  "_id": "1"
},
[
  {
    "$set": {
      "a": {
        "$multiply": [
          "$c",
          "$d"
        ]
      },
      "b": {
        "$add": [
          "$a",
          1
        ]
      }
    }
  }
])

蒙戈游乐场

  1. 可读性:在现实生活和更复杂的管道中,您可能会发现分解
    $set
    语句更具可读性或易于管理。但我承认这是相当主观的,你可以反过来考虑。
© www.soinside.com 2019 - 2024. All rights reserved.