了解 explain() 以优化复杂查询

Understanding explain() to optimize complex queries

我有一个聚合管道需要超过 5 秒才能 return 200 行。 我正在尝试使用 explain("executionStats").

优化我当前的管道

这是我的管道:

db.getCollection("content_topics").explain("executionStats").aggregate([{
    "$lookup": {
      from: "users",
      localField: "creator",
      foreignField: "_id",
      as: "user"
    }
  },
  {
    $unwind: "$user"
  },
  {
    "$match": {
      created_at: {
        "$gte": 1528914600,
        "$lte": 1534271400
      },
      dash_status: 3,
      language: "hi",
      parent_topic_id: {
        "$eq": null
      },
      status: 1,
      "user.device_os": {
        "$ne": "BOT"
      }
    }
  },
  {
    "$sort": {
      created_at: -1
    }
  },
  {
    "$addFields": {
      user_handle: "$user.handle",
      user_phone: "$user.phone",
      user_status: "$user.status"
    }
  },
  {
    "$project": {
      topic_id: 1,
      n_vokes: 1,
      message: 1,
      title: 1,
      language: 1,
      description: 1,
      voice_desc: 1,
      image: 1,
      image_share: 1,
      hashtag: 1,
      location: 1,
      default_text: 1,
      creator: 1,
      created_at: 1,
      status: 1,
      ref_id: 1,
      weightage: 1,
      username: 1,
      slug_generated: 1,
      user_handle: 1,
      user_phone: 1,
      user_status: 1
    }
  },
  {
    "$skip": 0
  },
  {
    "$limit": 200
  }
]);

这就是 mongo 解释的内容:

{ 
    "stages" : [
        {
            "$cursor" : {
                "query" : {
                    "$and" : [
                        {
                            "created_at" : {
                                "$gte" : 1528914600.0
                            }
                        }, 
                        {
                            "created_at" : {
                                "$lte" : 1534271400.0
                            }
                        }, 
                        {
                            "dash_status" : {
                                "$eq" : 3.0
                            }
                        }, 
                        {
                            "language" : {
                                "$eq" : "hi"
                            }
                        }, 
                        {
                            "parent_topic_id" : {
                                "$eq" : null
                            }
                        }, 
                        {
                            "status" : {
                                "$eq" : 1.0
                            }
                        }
                    ]
                }, 
                "fields" : {
                    "created_at" : 1.0, 
                    "creator" : 1.0, 
                    "default_text" : 1.0, 
                    "description" : 1.0, 
                    "hashtag" : 1.0, 
                    "image" : 1.0, 
                    "image_share" : 1.0, 
                    "language" : 1.0, 
                    "location" : 1.0, 
                    "message" : 1.0, 
                    "n_vokes" : 1.0, 
                    "ref_id" : 1.0, 
                    "slug_generated" : 1.0, 
                    "status" : 1.0, 
                    "title" : 1.0, 
                    "topic_id" : 1.0, 
                    "user.handle" : 1.0, 
                    "user.phone" : 1.0, 
                    "user.status" : 1.0, 
                    "user_handle" : 1.0, 
                    "user_phone" : 1.0, 
                    "user_status" : 1.0, 
                    "username" : 1.0, 
                    "voice_desc" : 1.0, 
                    "weightage" : 1.0, 
                    "_id" : 1.0
                }, 
                "queryPlanner" : {
                    "plannerVersion" : 1.0, 
                    "namespace" : "vokalapp.content_topics", 
                    "indexFilterSet" : false, 
                    "parsedQuery" : {
                        "$and" : [
                            {
                                "dash_status" : {
                                    "$eq" : 3.0
                                }
                            }, 
                            {
                                "language" : {
                                    "$eq" : "hi"
                                }
                            }, 
                            {
                                "parent_topic_id" : {
                                    "$eq" : null
                                }
                            }, 
                            {
                                "status" : {
                                    "$eq" : 1.0
                                }
                            }, 
                            {
                                "created_at" : {
                                    "$lte" : 1534271400.0
                                }
                            }, 
                            {
                                "created_at" : {
                                    "$gte" : 1528914600.0
                                }
                            }
                        ]
                    }, 
                    "winningPlan" : {
                        "stage" : "FETCH", 
                        "filter" : {
                            "parent_topic_id" : {
                                "$eq" : null
                            }
                        }, 
                        "inputStage" : {
                            "stage" : "IXSCAN", 
                            "keyPattern" : {
                                "dash_status" : 1.0, 
                                "status" : 1.0, 
                                "language" : 1.0, 
                                "parent_topic_id" : 1.0, 
                                "created_at" : 1.0
                            }, 
                            "indexName" : "index_for_dashboard", 
                            "isMultiKey" : false, 
                            "multiKeyPaths" : {
                                "dash_status" : [

                                ], 
                                "status" : [

                                ], 
                                "language" : [

                                ], 
                                "parent_topic_id" : [

                                ], 
                                "created_at" : [

                                ]
                            }, 
                            "isUnique" : false, 
                            "isSparse" : false, 
                            "isPartial" : false, 
                            "indexVersion" : 2.0, 
                            "direction" : "forward", 
                            "indexBounds" : {
                                "dash_status" : [
                                    "[3.0, 3.0]"
                                ], 
                                "status" : [
                                    "[1.0, 1.0]"
                                ], 
                                "language" : [
                                    "[\"hi\", \"hi\"]"
                                ], 
                                "parent_topic_id" : [
                                    "[null, null]"
                                ], 
                                "created_at" : [
                                    "[1528914600.0, 1534271400.0]"
                                ]
                            }
                        }
                    }, 
                    "rejectedPlans" : [
                        {
                            "stage" : "FETCH", 
                            "filter" : {
                                "$and" : [
                                    {
                                        "dash_status" : {
                                            "$eq" : 3.0
                                        }
                                    }, 
                                    {
                                        "language" : {
                                            "$eq" : "hi"
                                        }
                                    }, 
                                    {
                                        "parent_topic_id" : {
                                            "$eq" : null
                                        }
                                    }, 
                                    {
                                        "status" : {
                                            "$eq" : 1.0
                                        }
                                    }
                                ]
                            }, 
                            "inputStage" : {
                                "stage" : "IXSCAN", 
                                "keyPattern" : {
                                    "created_at" : 1.0
                                }, 
                                "indexName" : "created_at_index", 
                                "isMultiKey" : false, 
                                "multiKeyPaths" : {
                                    "created_at" : [

                                    ]
                                }, 
                                "isUnique" : false, 
                                "isSparse" : false, 
                                "isPartial" : false, 
                                "indexVersion" : 2.0, 
                                "direction" : "forward", 
                                "indexBounds" : {
                                    "created_at" : [
                                        "[1528914600.0, 1534271400.0]"
                                    ]
                                }
                            }
                        }, 
                        {
                            "stage" : "FETCH", 
                            "filter" : {
                                "$and" : [
                                    {
                                        "dash_status" : {
                                            "$eq" : 3.0
                                        }
                                    }, 
                                    {
                                        "parent_topic_id" : {
                                            "$eq" : null
                                        }
                                    }
                                ]
                            }, 
                            "inputStage" : {
                                "stage" : "IXSCAN", 
                                "keyPattern" : {
                                    "language" : 1.0, 
                                    "status" : 1.0, 
                                    "created_at" : 1.0, 
                                    "answers.type" : 1.0
                                }, 
                                "indexName" : "language_status_created_at_answer_type_index", 
                                "isMultiKey" : true, 
                                "multiKeyPaths" : {
                                    "language" : [

                                    ], 
                                    "status" : [

                                    ], 
                                    "created_at" : [

                                    ], 
                                    "answers.type" : [
                                        "answers"
                                    ]
                                }, 
                                "isUnique" : false, 
                                "isSparse" : false, 
                                "isPartial" : false, 
                                "indexVersion" : 2.0, 
                                "direction" : "forward", 
                                "indexBounds" : {
                                    "language" : [
                                        "[\"hi\", \"hi\"]"
                                    ], 
                                    "status" : [
                                        "[1.0, 1.0]"
                                    ], 
                                    "created_at" : [
                                        "[1528914600.0, 1534271400.0]"
                                    ], 
                                    "answers.type" : [
                                        "[MinKey, MaxKey]"
                                    ]
                                }
                            }
                        }, 
                        {
                            "stage" : "FETCH", 
                            "filter" : {
                                "$and" : [
                                    {
                                        "dash_status" : {
                                            "$eq" : 3.0
                                        }
                                    }, 
                                    {
                                        "parent_topic_id" : {
                                            "$eq" : null
                                        }
                                    }
                                ]
                            }, 
                            "inputStage" : {
                                "stage" : "IXSCAN", 
                                "keyPattern" : {
                                    "language" : -1.0, 
                                    "status" : -1.0, 
                                    "weightage" : -1.0, 
                                    "created_at" : -1.0
                                }, 
                                "indexName" : "language_status_weightage_created_at_index", 
                                "isMultiKey" : false, 
                                "multiKeyPaths" : {
                                    "language" : [

                                    ], 
                                    "status" : [

                                    ], 
                                    "weightage" : [

                                    ], 
                                    "created_at" : [

                                    ]
                                }, 
                                "isUnique" : false, 
                                "isSparse" : false, 
                                "isPartial" : false, 
                                "indexVersion" : 2.0, 
                                "direction" : "forward", 
                                "indexBounds" : {
                                    "language" : [
                                        "[\"hi\", \"hi\"]"
                                    ], 
                                    "status" : [
                                        "[1.0, 1.0]"
                                    ], 
                                    "weightage" : [
                                        "[MaxKey, MinKey]"
                                    ], 
                                    "created_at" : [
                                        "[1534271400.0, 1528914600.0]"
                                    ]
                                }
                            }
                        }
                    ]
                }, 
                "executionStats" : {
                    "executionSuccess" : true, 
                    "nReturned" : 7072.0, 
                    "executionTimeMillis" : 984.0, 
                    "totalKeysExamined" : 7072.0, 
                    "totalDocsExamined" : 7072.0, 
                    "executionStages" : {
                        "stage" : "FETCH", 
                        "filter" : {
                            "parent_topic_id" : {
                                "$eq" : null
                            }
                        }, 
                        "nReturned" : 7072.0, 
                        "executionTimeMillisEstimate" : 40.0, 
                        "works" : 7073.0, 
                        "advanced" : 7072.0, 
                        "needTime" : 0.0, 
                        "needYield" : 0.0, 
                        "saveState" : 63.0, 
                        "restoreState" : 63.0, 
                        "isEOF" : 1.0, 
                        "invalidates" : 0.0, 
                        "docsExamined" : 7072.0, 
                        "alreadyHasObj" : 0.0, 
                        "inputStage" : {
                            "stage" : "IXSCAN", 
                            "nReturned" : 7072.0, 
                            "executionTimeMillisEstimate" : 0.0, 
                            "works" : 7073.0, 
                            "advanced" : 7072.0, 
                            "needTime" : 0.0, 
                            "needYield" : 0.0, 
                            "saveState" : 63.0, 
                            "restoreState" : 63.0, 
                            "isEOF" : 1.0, 
                            "invalidates" : 0.0, 
                            "keyPattern" : {
                                "dash_status" : 1.0, 
                                "status" : 1.0, 
                                "language" : 1.0, 
                                "parent_topic_id" : 1.0, 
                                "created_at" : 1.0
                            }, 
                            "indexName" : "index_for_dashboard", 
                            "isMultiKey" : false, 
                            "multiKeyPaths" : {
                                "dash_status" : [

                                ], 
                                "status" : [

                                ], 
                                "language" : [

                                ], 
                                "parent_topic_id" : [

                                ], 
                                "created_at" : [

                                ]
                            }, 
                            "isUnique" : false, 
                            "isSparse" : false, 
                            "isPartial" : false, 
                            "indexVersion" : 2.0, 
                            "direction" : "forward", 
                            "indexBounds" : {
                                "dash_status" : [
                                    "[3.0, 3.0]"
                                ], 
                                "status" : [
                                    "[1.0, 1.0]"
                                ], 
                                "language" : [
                                    "[\"hi\", \"hi\"]"
                                ], 
                                "parent_topic_id" : [
                                    "[null, null]"
                                ], 
                                "created_at" : [
                                    "[1528914600.0, 1534271400.0]"
                                ]
                            }, 
                            "keysExamined" : 7072.0, 
                            "seeks" : 1.0, 
                            "dupsTested" : 0.0, 
                            "dupsDropped" : 0.0, 
                            "seenInvalidated" : 0.0
                        }
                    }
                }
            }
        }, 
        {
            "$lookup" : {
                "from" : "users", 
                "as" : "user", 
                "localField" : "creator", 
                "foreignField" : "_id", 
                "unwinding" : {
                    "preserveNullAndEmptyArrays" : false
                }, 
                "matching" : {
                    "$nor" : [
                        {
                            "device_os" : {
                                "$eq" : "BOT"
                            }
                        }
                    ]
                }
            }
        }, 
        {
            "$sort" : {
                "sortKey" : {
                    "created_at" : -1.0
                }, 
                "limit" : NumberLong(200)
            }
        }, 
        {
            "$addFields" : {
                "user_handle" : "$user.handle", 
                "user_phone" : "$user.phone", 
                "user_status" : "$user.status"
            }
        }, 
        {
            "$project" : {
                "_id" : true, 
                "hashtag" : true, 
                "voice_desc" : true, 
                "description" : true, 
                "location" : true, 
                "language" : true, 
                "topic_id" : true, 
                "image" : true, 
                "slug_generated" : true, 
                "n_vokes" : true, 
                "ref_id" : true, 
                "image_share" : true, 
                "message" : true, 
                "created_at" : true, 
                "default_text" : true, 
                "weightage" : true, 
                "user_handle" : true, 
                "title" : true, 
                "status" : true, 
                "creator" : true, 
                "user_status" : true, 
                "username" : true, 
                "user_phone" : true
            }
        }
    ], 
    "ok" : 1.0
}

这是在我使用“$match”中使用的键创建索引 "index_for_dashboard" 之后。我还从用户集合中为 "device_os" 创建了一个索引。但没有骰子,响应时间没有改善。

可能的罪魁祸首:

我应该如何使用解释结果进行故障排除(和理解)以帮助自己优化查询? 我不能在这里打电话,需要一些指导。

首先,您要确保您 运行 至少是 MongoDB 的 v3.6.3,因为在 v3.6 中有一个允许 $lookup to specify sub-pipelines. Those pipelines can actually use indexes, however, there was a bug 的新功能已在上述版本中修复。

以下内容应该尽可能快地到达这里:

db.getCollection("content_topics").createIndex({ created_at: -1, dash_status: 1, language: 1, parent_topic_id: 1, status: 1 }); // this index will get used by the main $match and the $sort stage

db.getCollection("users").createIndex({ device_os: 1 }); // this index will get used by the sub-pipeline in $lookup

db.getCollection("content_topics").aggregate([{
    "$match": { // filter at the start in order to be able to use indexes
      created_at: {
        "$gte": 1528914600,
        "$lte": 1534271400
      },
      dash_status: 3,
      language: "hi",
      parent_topic_id: {
        "$eq": null
      },
      status: 1
      // see the below $lookup stage in case you're wondering where the user filter went
    }
  },
  {
    "$sort": {
      created_at: -1 // sort straight away so the index can be used
    }
  },
  {
    "$lookup": {
      from: "users",
      let: { "creator": "$creator" },
      pipeline: [{ // use new v3.6 pipeline syntax to be able to leverage indexes
          $match: {
              $expr: {
                  $and: [
                      { $eq: [ "$_id", "$$creator" ] },
                      { $ne: [ "$device_os", "BOT" ] } // here is the "device_os" filter inside the pipeline so index can be used
                  ]
              }
          }
      }, {
          $project: {
              _id: 0, // "_id" field is not needed
              user_handle: 1, // only those fields are of interest
              user_phone: 1,
              user_status: 1
          }
      }],
      as: "user"
    }
  },
  {
    $unwind: "$user"
  },
  {
    "$project": {
      topic_id: 1,
      n_vokes: 1,
      message: 1,
      title: 1,
      language: 1,
      description: 1,
      voice_desc: 1,
      image: 1,
      image_share: 1,
      hashtag: 1,
      location: 1,
      default_text: 1,
      creator: 1,
      created_at: 1,
      status: 1,
      ref_id: 1,
      weightage: 1,
      username: 1,
      slug_generated: 1,
      user_handle: "$user.handle", // no extra $addFields stage needed
      user_phone: "$user.phone",   // same here
      user_status: "$user.status"  // and here
    }
  },
  {
    "$skip": 0
  },
  {
    "$limit": 200
  }
]);