Как я могу ускорить запросы mongo db, имеющие много логических полей? - PullRequest
0 голосов
/ 23 октября 2019

Давайте предположим, что моя коллекция 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,
   },
   ...
]

В этой коллекции 1 миллион документов. Я создаю два индекса:

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 во все запросы, что я не могу гарантировать.

Поскольку оба способа мне не подходят, мне интересно, есть ли другой способ ускорить запрос. Спасибо вам всем! :)

1 Ответ

0 голосов
/ 23 октября 2019

Похоже, это может быть хорошим использованием для шаблона атрибута. Подробнее см. 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 })

выполнение плана объяснения показывает хорошее соотношение (1:1) между ключами Examined и nReturned.

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
}

Хотя избирательность может быть плохой, это характер данных,и запрос все еще требует результатов. Если вам нужен этот запрос и вам нужна более высокая производительность, вы можете сначала рассмотреть вопрос о вертикальном масштабировании, а затем, если он все еще не соответствует вашим потребностям, рассмотрите горизонтальное масштабирование.

Если модель данных стабильна и используются имена полей,в соответствии вы могли бы использовать покрытый запрос для ваших нужд. Я подозреваю, что ваши реальные потребности не так тривиальны, как в приведенном примере.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...