0
votes

MongoDB - Compte () prend trop de temps malgré l'utilisation d'un index

J'ai une collection avec des documents de 62K. La même collection a également une série d'index, la plupart d'entre eux simples, célibataires. Ce que je suis observé, c'est que la requête suivante prend extrêmement long pour revenir: xxx pré>

Les exécutions de la requête ci-dessus sont les suivantes P>

{
"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "xxxxxx.jobs",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "$and" : [
            {
                "$or" : [
                    {
                        "groups" : {
                            "$size" : 0
                        }
                    },
                    {
                        "groups" : {
                            "$eq" : "5e65ffc2a1e6ef0007bc5fa8"
                        }
                    },
                    {
                        "$nor" : [
                            {
                                "groups" : {
                                    "$exists" : true
                                }
                            }
                        ]
                    }
                ]
            },
            {
                "status" : {
                    "$eq" : "complete"
                }
            }
        ]
    },
    "winningPlan" : {
        "stage" : "FETCH",
        "filter" : {
            "$or" : [
                {
                    "groups" : {
                        "$size" : 0
                    }
                },
                {
                    "groups" : {
                        "$eq" : "5e65ffc2a1e6ef0007bc5fa8"
                    }
                },
                {
                    "$nor" : [
                        {
                            "groups" : {
                                "$exists" : true
                            }
                        }
                    ]
                }
            ]
        },
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                "status" : 1,
                "groups" : 1
            },
            "indexName" : "status_1_groups_1",
            "isMultiKey" : true,
            "multiKeyPaths" : {
                "status" : [ ],
                "groups" : [
                    "groups"
                ]
            },
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                "status" : [
                    "[\"complete\", \"complete\"]"
                ],
                "groups" : [
                    "[MinKey, MaxKey]"
                ]
            }
        }
    },
    "rejectedPlans" : [
        {
            "stage" : "FETCH",
            "filter" : {
                "$or" : [
                    {
                        "groups" : {
                            "$size" : 0
                        }
                    },
                    {
                        "groups" : {
                            "$eq" : "5e65ffc2a1e6ef0007bc5fa8"
                        }
                    },
                    {
                        "$nor" : [
                            {
                                "groups" : {
                                    "$exists" : true
                                }
                            }
                        ]
                    }
                ]
            },
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "status" : 1
                },
                "indexName" : "status_1",
                "isMultiKey" : false,
                "multiKeyPaths" : {
                    "status" : [ ]
                },
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 2,
                "direction" : "forward",
                "indexBounds" : {
                    "status" : [
                        "[\"complete\", \"complete\"]"
                    ]
                }
            }
        }
    ]
},
"executionStats" : {
    "executionSuccess" : true,
    "nReturned" : 62092,
    "executionTimeMillis" : 9992,
    "totalKeysExamined" : 62092,
    "totalDocsExamined" : 62092,
    "executionStages" : {
        "stage" : "FETCH",
        "filter" : {
            "$or" : [
                {
                    "groups" : {
                        "$size" : 0
                    }
                },
                {
                    "groups" : {
                        "$eq" : "5e65ffc2a1e6ef0007bc5fa8"
                    }
                },
                {
                    "$nor" : [
                        {
                            "groups" : {
                                "$exists" : true
                            }
                        }
                    ]
                }
            ]
        },
        "nReturned" : 62092,
        "executionTimeMillisEstimate" : 9929,
        "works" : 62093,
        "advanced" : 62092,
        "needTime" : 0,
        "needYield" : 0,
        "saveState" : 682,
        "restoreState" : 682,
        "isEOF" : 1,
        "invalidates" : 0,
        "docsExamined" : 62092,
        "alreadyHasObj" : 0,
        "inputStage" : {
            "stage" : "IXSCAN",
            "nReturned" : 62092,
            "executionTimeMillisEstimate" : 60,
            "works" : 62093,
            "advanced" : 62092,
            "needTime" : 0,
            "needYield" : 0,
            "saveState" : 682,
            "restoreState" : 682,
            "isEOF" : 1,
            "invalidates" : 0,
            "keyPattern" : {
                "status" : 1,
                "groups" : 1
            },
            "indexName" : "status_1_groups_1",
            "isMultiKey" : true,
            "multiKeyPaths" : {
                "status" : [ ],
                "groups" : [
                    "groups"
                ]
            },
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                "status" : [
                    "[\"complete\", \"complete\"]"
                ],
                "groups" : [
                    "[MinKey, MaxKey]"
                ]
            },
            "keysExamined" : 62092,
            "seeks" : 1,
            "dupsTested" : 62092,
            "dupsDropped" : 0,
            "seenInvalidated" : 0
        }
    }
},
"serverInfo" : {
    "host" : "xxxxxxx",
    "port" : 27017,
    "version" : "3.6.15",
    "gitVersion" : "xxxxxx"
},
"ok" : 1}


0 commentaires

3 Réponses :


0
votes

La requête expliquée Il n'y avait pas de comptage, il est retourné assez de documents:

db.jobs.count({"status":"complete","groups":{"$size":0}})
db.jobs.count({"status":"complete","groups":{"$in":[false, "5e65ffc2a1e6ef0007bc5fa8"]}})
  • L'existence de la clé ne peut pas être complètement déterminée à partir de l'index de
    Le {"$ existe": faux} code> prédicat est également gênant. Lors de la construction d'un index, la valeur d'un document contient la valeur de chaque champ indexé. Il n'y a pas de valeur pour "inexistant", il utilise donc null code>. Depuis un document contenant un champ dont la valeur est explicitement définie sur null code> devrait pas em> match {"$ existe": false} code>, l'exécuteur exécutive de requête Doit charger chaque document du disque afin de déterminer si le champ était null code> ni inexistant. Cela signifie qu'une étape de chefscan ne peut pas être utilisée, ce qui signifie en outre que tous les em> des documents à compter doit être chargé à partir du disque. LI>
  • Le prédicat $ ou code> ne garantit pas l'exclusivité de
    L'exécuteur de requêtes ne peut pas savoir à l'avance que les clauses du $ ou code> sont mutuellement exclusives. Ils sont dans votre requête, mais dans le cas général, il est possible qu'un seul document correspondait à plus d'une clause dans le $ ou code>, de sorte que l'exécuteur de requête doit charger les documents pour assurer la déduplication. li> ul>

    alors comment éliminer la phase de récupération? h3>

    Si vous souhaitez interroger uniquement la clause $ dans code>, ou avec seulement la taille $ code> La clause Vous devez trouver que le nombre est dérivé de l'analyse d'index, sans avoir à charger aucun document. p>

    Ceci est, si vous devez exécuter ces requêtes séparément du client et résumer les résultats Vous devez constater que le temps d'exécution global est inférieur à la requête qui nécessite une récupération: p> xxx pré>

    pour le {"Groupes": {"$ existe": false }} code> prédicat, vous pouvez modifier légèrement les données, telles que vous assurez que le champ existe toujours, mais attribuez-lui une valeur qui signifie "indéfinie" qui peut être indexée et interrogée. P>

    en tant que Exemple, si vous souhaitez exécuter la mise à jour suivante, le champ Groupes existerait alors dans tous les documents: p> xxx pré>

    et vous pourriez obtenir l'équivalent du nombre ci-dessus en exécutant ces 2 des requêtes qui devraient tous deux être couvertes par une analyse d'index et devraient fonctionner plus rapidement que la requête requise Documents de chargement RES: P>

    db.jobs.update({"groups":{"$exists":false}},{"$set":{"groups":false}})
    


4 commentaires

Oh mec, j'avais des espoirs aussi élevés pour votre réponse! Malheureusement, j'ai essayé de supprimer les prédicats gênants en vain. Exécution db.jobs.find ({"Statut": "Terminer", "Groupes": {"$ Taille": 0}}). Exp lain ("Executionstats") m'a donné InputStage .Executiontimemillisest: 50 Mais la phase de récupération du nœud parent a toujours pris> 6Secondes. Une idée de la raison pour laquelle il n'a pas utilisé de scène de compte?


Regarder de plus près, "groupes": {"$ taille": 0} ne peut pas être réparé correctement par l'index, car MongoDB ne stocke pas la matrice elle-même de la valeur d'index, elle stocke une séparation Valeur d'index pour chacun des éléments de matrice. Je soupçonne que la façon de l'obtenir est de combiner [] et manquant dans la mise à jour, comme db.jobs.update ({$ ou: {ou: "Groupes": {"$ existe": faux}}, {"Groupes": []}], {"$ Set": {"groupe s": faux}}) , puis le Deuxième requête Il pourrait obtenir le comptage dont vous avez besoin sans chargement de documents.


Une idée de la façon dont MongoDB traitera des documents qui disposent d'un tableau de hachage dans le champ "Groupes"? La recherche renvoie-t-elle le document si le document a Groupes: ["FOO", "BAR", "ABC"] et le filtre de requête est {Groupes: {$ in: ["ABC "," def "]}} ? L'indice sera-t-il utilisé ici correctement? Si c'est le cas, je pourrais en réalité avoir la réponse dont j'ai besoin!


EDIT: Répondre à ma propre question - Plusieurs valeurs de la condition "$ in" rendent la requête aussi lente que c'était. Il est intéressant de noter que la valeur de la valeur false de la liste facilite le retour de la requête immédiatement.



0
votes

Si vous pouvez en quelque sorte éviter le cas de tableau vide, la requête suivante peut être utilisée: db.jobs.count ({"Statut": "Terminer", "Groupes": {$ in: [null, "5E65FFC2A1E6EF0007BC5FA8"]}})

null est équivalent à $ exist: faux .

Pour utiliser ObjectID au lieu de la chaîne en tant que type pour le champ GROUPES .

MISE À JOUR N'ajoutez jamais d'index! / p>

Vous pouvez utiliser la requête suivante: xxx


2 commentaires

Malheureusement, la plupart des documents de la DB ont [] pour la valeur des groupes, je ne peux donc pas vraiment l'éviter. À propos de la suggestion ObjectId - quelles implications cela apportent-il? Est-ce plus sûr ou plus rapide de l'utiliser ObjectId au lieu d'une chaîne simple?


Les objectifs sont plus petits et ont un meilleur comportement d'index.



0
votes

` xxx


5 commentaires

Veuillez faire un meilleur format de votre texte et expliquer ce que vous faites différentes pour les autres solutions. Merci.


Outre des erreurs de syntaxe mineures, ce pipeline pose un problème - vous ne pouvez pas utiliser $ compter de cette manière. Selon Mongodb Docs: $ Count a le formulaire de prototype suivant: {$ Count: } est le nom du champ de sortie qui a le compte comme valeur


Bien que ce code puisse fournir une solution à la question, il est préférable d'ajouter du contexte pourquoi / comment cela fonctionne. Cela peut aider les futurs utilisateurs à apprendre et à appliquer cette connaissance à leur propre code. Vous êtes également susceptible d'avoir des commentaires positifs des utilisateurs sous forme de prospects, lorsque le code est expliqué.


relooking à mon code d'air; Il n'est pas nécessaire de ne pas avoir besoin de $ dans la mesure où $ existe des critères plus larges ... en plain anglais: Count Statut = Complete de tous les enregistrements / documents qui ont le groupe de terrain .... Oui? Oui? Oui?


Pas exactement, la condition parent est $ ou, soit donc sans groupe de groupes, le tableau vide ou l'un des $