Оптимизация запроса mongoDB - PullRequest
       1

Оптимизация запроса mongoDB

0 голосов
/ 25 сентября 2018

У меня есть огромная коллекция документов, которая, вообще говоря, предназначена для хранения миллионов документов.

В общем, типичный документ может быть довольно сложным и динамичным, но есть несколько постоянных полей, которыедолжен присутствовать в каждом из них.Эти поля включают в себя: GlobalDeviceStatus, ManualTests, SemiAutomaticTests, AutomaticTests.Все три типа тестов представлены массивами объектов.Каждый такой объект может содержать довольно много полей, но опять же есть несколько постоянных.Это componentName и componentTestStatus.

{
    "data": {
        "globalDeviceStatus": false,
        "qaOfficerID": 12121,
        "ManualTests": [{
                "componentName": "camera",
                "componentTestStatus": true,
                "x": 10
            },
            {
                "componentName": "wifi",
                "componentTestStatus": false,
                "mnum": 711
            }
        ],
        "SemiAutomaticTests": [{
                "componentName": "someComponent",
                "componentTestStatus": true,
                "someParameter": true
            },
            {
                "componentName": "oneMoreComponent",
                "componentTestStatus": false
            }
        ],
        "AutomaticTests": [{
                "componentName": "anotherComponent",
                "componentTestStatus": true
            },
            {
                "componentName": "someVeryImportantComponent",
                "componentTestStatus": false
            }
        ]
    },
    "userID": 1
}

Каждый документ представляет собой тест.Если значение GlobalDeviceStatus окажется равным false, то проверка не пройдена.Это также означает, что его json должен содержать как минимум один отказавший компонент (тесты с GlobalDeviceStatus, равным true, наоборот, не содержат отказавших компонентов, что вполне логично).Что мне нужно, так это рассчитать количество сбоев для каждого компонента, поэтому в качестве выходных данных мне нужно что-то вроде этого:

{
    "componentName": 120,
    "someOtherComponentName": 31
}

Каждое componentName может принадлежать только одному типу теста.То есть, если в одном документе он находится в SemiAutomaticTests тестах, он не может перейти на AutomaticTests в другом.

Для таких вычислений я использую следующий канал Монго:

COUNT_CRASHES = [
            {
                "$match": {
                    "$or": [{
                        "data.ManualTests.componentTestStatus": false
                    }, {
                        "data.AutomaticTests.componentTestStatus": false
                    }, {
                        "data.SemiAutomaticTests.componentTestStatus": false
                    }]
                }
            }, {
                "$project": {
                    "tests": {
                        "$concatArrays": [{
                            "$filter": {
                                "input": "$data.ManualTests",
                                "as": "mt",
                                "cond": {
                                    "$eq": ["$$mt.componentTestStatus", false]
                                }
                            }
                        }, {
                            "$filter": {
                                "input": "$data.AutomaticTests",
                                "as": "at",
                                "cond": {
                                    "$eq": ["$$at.componentTestStatus", false]
                                }
                            }
                        }, {
                            "$filter": {
                                "input": "$data.SemiAutomaticTests",
                                "as": "st",
                                "cond": {
                                    "$eq": ["$$st.componentTestStatus", false]
                                }
                            }
                        }]
                    }
                }
            }, {
                "$unwind": "$tests"
            }, {
                "$group": {
                    "_id": "$tests.componentName",
                    "count": {
                        "$sum": 1
                    }
                }
            }
        ]

Он возвращает данные в формате, отличном от указанного выше, но это не так важно, что действительно важно сейчас, это то, что для возврата требуется около 7 секунд, а иногда и в два раза больше (~ 14 секунд).Это с 350 тыс. Документов в БД.

Я бы хотел максимально сократить время.

1 Ответ

0 голосов
/ 26 сентября 2018

Если вы не реструктурируете свои документы во что-то, где "ManualTests", "AutomaticTests" и "SemiAutomaticTests" станут значениями полей, а не самими полями (что, вероятно, позволит более узкий конвейер), вам, вероятно, потребуется создать три индекса, напримерэто для ускорения $match:

db.collection.createIndex({ "data.ManualTests.componentTestStatus": 1 })
db.collection.createIndex({ "data.AutomaticTests.componentTestStatus": 1 })
db.collection.createIndex({ "data.SemiautomaticTests.componentTestStatus": 1 })

Также обратите внимание, что ваша проекция может быть сокращена до:

"$project": {
    "tests": {
        "$filter": {
            "input": { "$concatArrays": [ "$data.ManualTests", "$data.AutomaticTests", "$data.SemiAutomaticTests" ] },
            "as": "t",
            "cond": {
                "$eq": ["$$t.componentTestStatus", false]
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...