【问题标题】:How do I speed up mongo db queries having many boolean fields?如何加快具有许多布尔字段的 mongo db 查询?
【发布时间】:2019-10-23 19:40:41
【问题描述】:

假设我的收藏user 是这样的:

[
   {
      "name":"user1",
      "u_id":"1",
      "is_happy":true,
      "like_baseball":false,
      "is_strong":true,
   },
   {
      "name":"user2",
      "u_id":"2",
      "is_happy":false,
      "like_baseball":false,
      "is_strong":true,
   },
   {
      "name":"user3",
      "u_id":"3",
      "is_happy":true,
      "like_baseball":false,
      "is_strong":false,
   },
   ...
]

此集合中有 100 万份文档。 我创建了两个索引:

1.

{
   "is_happy": 1,
   "like_baseball": 1,
   "is_strong": 1,
}

2.

{
   "u_id": 1,
}

我们都知道第一个索引不能帮助加快下面的查询,因为它的选择性很糟糕:

db.user.find({
   is_happy: true,
   like_baseball: true,
   is_strong: false,
})

MongoDB 文档提供了两种处理不良选择性的方法

  1. 将一个集合分成两个集合。 (在我的例子中,将快乐和不快乐的人分成两个集合。)但是,我有三个布尔字段,这使得分离任务变得困难。

  2. 创建字段和其他具有大量价值的字段的复合索引。 (在我的例子中,我可以创建三个布尔字段和u_id 的复合索引。)但是,这意味着我必须在所有查询中包含u_id,我不能保证。

由于这两种方式都不适合我,我想知道是否有另一种方法可以加快查询速度。谢谢你们! :)

【问题讨论】:

    标签: database mongodb indexing


    【解决方案1】:

    听起来像这样可能是属性模式的一个很好的用途。详情见https://www.mongodb.com/blog/post/building-with-patterns-the-attribute-pattern...

    顺便说一句,分成两个集合可能不会提供您所寻求的性能改进。

    如果你有以下索引:

    {
       "is_happy": 1,
       "like_baseball": 1,
       "is_strong": 1,
    }
    

    并发出以下查询...

    db.baseball.find({ is_happy: true, like_baseball: true, is_strong: false })
    

    运行解释计划显示 Keys Examined 和 nReturned 之间的比率很好 (1:1)。

    db.baseball.find({ is_happy: true, like_baseball: true, is_strong: false }).explain("allPlansExecution")
    

    所有计划执行结果:

    {
        "queryPlanner" : {
            "plannerVersion" : 1,
            "namespace" : "barrystuff.baseball",
            "indexFilterSet" : false,
            "parsedQuery" : {
                "$and" : [
                    {
                        "is_happy" : {
                            "$eq" : true
                        }
                    },
                    {
                        "is_strong" : {
                            "$eq" : false
                        }
                    },
                    {
                        "like_baseball" : {
                            "$eq" : true
                        }
                    }
                ]
            },
            "winningPlan" : {
                "stage" : "FETCH",
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "is_happy" : 1,
                        "like_baseball" : 1,
                        "is_strong" : 1
                    },
                    "indexName" : "is_happy_1_like_baseball_1_is_strong_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "is_happy" : [ ],
                        "like_baseball" : [ ],
                        "is_strong" : [ ]
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "is_happy" : [
                            "[true, true]"
                        ],
                        "like_baseball" : [
                            "[true, true]"
                        ],
                        "is_strong" : [
                            "[false, false]"
                        ]
                    }
                }
            },
            "rejectedPlans" : [ ]
        },
        "executionStats" : {
            "executionSuccess" : true,
            "nReturned" : 3,
            "executionTimeMillis" : 0,
            "totalKeysExamined" : 3,
            "totalDocsExamined" : 3,
            "executionStages" : {
                "stage" : "FETCH",
                "nReturned" : 3,
                "executionTimeMillisEstimate" : 0,
                "works" : 4,
                "advanced" : 3,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "docsExamined" : 3,
                "alreadyHasObj" : 0,
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "nReturned" : 3,
                    "executionTimeMillisEstimate" : 0,
                    "works" : 4,
                    "advanced" : 3,
                    "needTime" : 0,
                    "needYield" : 0,
                    "saveState" : 0,
                    "restoreState" : 0,
                    "isEOF" : 1,
                    "invalidates" : 0,
                    "keyPattern" : {
                        "is_happy" : 1,
                        "like_baseball" : 1,
                        "is_strong" : 1
                    },
                    "indexName" : "is_happy_1_like_baseball_1_is_strong_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "is_happy" : [ ],
                        "like_baseball" : [ ],
                        "is_strong" : [ ]
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "is_happy" : [
                            "[true, true]"
                        ],
                        "like_baseball" : [
                            "[true, true]"
                        ],
                        "is_strong" : [
                            "[false, false]"
                        ]
                    },
                    "keysExamined" : 3,
                    "seeks" : 1,
                    "dupsTested" : 0,
                    "dupsDropped" : 0,
                    "seenInvalidated" : 0
                }
            },
            "allPlansExecution" : [ ]
        },
        "serverInfo" : {
            "host" : "Barry-MacBook-Pro.local",
            "port" : 27017,
            "version" : "4.0.6",
            "gitVersion" : "caa42a1f75a56c7643d0b68d3880444375ec42e3"
        },
        "ok" : 1
    }
    

    虽然选择性可能不好,但这是数据的性质,查询仍然需要结果。如果您需要此查询并且希望获得更好的性能,您可能需要先考虑垂直缩放,然后如果仍然不能满足您的需求,请考虑水平缩放。

    如果数据模型稳定且使用的字段名称一致,您或许可以根据需要使用覆盖查询。我怀疑您的实际需求并不像提供的示例那么微不足道。

    【讨论】:

    • 非常感谢!我会调查的!
    • 谢谢先生。我从中学到了很多,但这可能无法解决我的问题。如果我错了,请纠正我,是的,我可以明智地索引这些布尔字段,但它们的值都是真假,所以索引仍然无助于加快查询速度。
    • @MarsLee - 索引有助于根据标准快速识别要获取的文档。如果您的条件已编入索引,但仍需要整个集合,则性能会很差。但是,如果您的条件需要 50% 的集合,则索引将有助于加快查询的识别部分。当结果集远小于集合时,识别记录的时间将占整个查询时间的大部分。当您有许多小型结果集时,索引在性能方面发挥着重要作用。关于您的具体情况,我不知道您希望返回多少文档。
    • @MarsLee - 另外,如果您只需要一些字段,而不是整个文档,您可能需要考虑覆盖查询 - docs.mongodb.com/manual/core/query-optimization/…
    猜你喜欢
    • 2017-06-15
    • 2011-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 2015-12-15
    • 2020-06-01
    相关资源
    最近更新 更多