【问题标题】:MongoDB sort and limit performance issueMongoDB 排序和限制性能问题
【发布时间】:2021-09-08 12:38:53
【问题描述】:

我遇到了一个奇怪的问题。查询的解释显示在所有阶段都使用了具有快速执行时间的索引,但 LIMIT 的最后阶段打破了这一切。我的执行时间是 60 多秒!

数据库用于营销工具,我们收集有关活动活动的数据。我们在数据库中每小时有 100k+ 条记录,我想以 5k 的批次选择所有 100k 条记录(我也尝试将其减少到 1k 条),以便进行统计汇总。

只是为了测试,我会添加一个查询解释的例子。

  • 如果我将 created_at 日期范围减少到 10 分钟,并将 limit 设置为 1000,它会运行得很快。
  • 如果我将 created_at 日期范围设置为 30 分钟,并将 limit 设置为 1000,它会再次存货。
  • 我有 8 个 CPU 和 64 个内存
  • 存储容量为 6000 IOPS
  • 该表总共包含 9 亿条记录

我有以下索引:

  • created_at: 1
  • _id: 1
  • {created_at: 1, _id: 1} - 未在查询中使用

慢查询 30 分钟

> db.logs.explain('allPlansExecution').aggregate([{"$match":{"created_at":{"$gte":ISODate('2021-06-02T20:00:00.000+00:00'),"$lte":ISODate('2021-06-02T20:30:00.000+00:00')}}},{"$sort":{"_id":1}},{"$limit":1000}], { allowDiskUse: true });
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "webpush.campaign_action_logs",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "created_at" : {
                        "$lte" : ISODate("2021-06-02T20:30:00Z")
                    }
                },
                {
                    "created_at" : {
                        "$gte" : ISODate("2021-06-02T20:00:00Z")
                    }
                }
            ]
        },
        "optimizedPipeline" : true,
        "winningPlan" : {
            "stage" : "SORT",
            "sortPattern" : {
                "_id" : 1
            },
            "memLimit" : 104857600,
            "limitAmount" : 100,
            "type" : "simple",
            "inputStage" : {
                "stage" : "FETCH",
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "created_at" : 1
                    },
                    "indexName" : "created_at_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "created_at" : [ ]
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "created_at" : [
                            "[new Date(1622664000000), new Date(1622665800000)]"
                        ]
                    }
                }
            }
        },
        "rejectedPlans" : [
            {
                "stage" : "LIMIT",
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "FETCH",
                    "filter" : {
                        "$and" : [
                            {
                                "created_at" : {
                                    "$lte" : ISODate("2021-06-02T20:30:00Z")
                                }
                            },
                            {
                                "created_at" : {
                                    "$gte" : ISODate("2021-06-02T20:00:00Z")
                                }
                            }
                        ]
                    },
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "_id" : 1
                        },
                        "indexName" : "_id_",
                        "isMultiKey" : false,
                        "multiKeyPaths" : {
                            "_id" : [ ]
                        },
                        "isUnique" : true,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 2,
                        "direction" : "forward",
                        "indexBounds" : {
                            "_id" : [
                                "[MinKey, MaxKey]"
                            ]
                        }
                    }
                }
            }
        ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 100,
        "executionTimeMillis" : 183411,
        "totalKeysExamined" : 257959,
        "totalDocsExamined" : 257959,
        "executionStages" : {
            "stage" : "SORT",
            "nReturned" : 100,
            "executionTimeMillisEstimate" : 625,
            "works" : 258061,
            "advanced" : 100,
            "needTime" : 257960,
            "needYield" : 0,
            "saveState" : 9571,
            "restoreState" : 9571,
            "isEOF" : 1,
            "sortPattern" : {
                "_id" : 1
            },
            "memLimit" : 104857600,
            "limitAmount" : 100,
            "type" : "simple",
            "totalDataSizeSorted" : 187871472,
            "usedDisk" : false,
            "inputStage" : {
                "stage" : "FETCH",
                "nReturned" : 257959,
                "executionTimeMillisEstimate" : 533,
                "works" : 257960,
                "advanced" : 257959,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 9571,
                "restoreState" : 9571,
                "isEOF" : 1,
                "docsExamined" : 257959,
                "alreadyHasObj" : 0,
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "nReturned" : 257959,
                    "executionTimeMillisEstimate" : 265,
                    "works" : 257960,
                    "advanced" : 257959,
                    "needTime" : 0,
                    "needYield" : 0,
                    "saveState" : 9571,
                    "restoreState" : 9571,
                    "isEOF" : 1,
                    "keyPattern" : {
                        "created_at" : 1
                    },
                    "indexName" : "created_at_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "created_at" : [ ]
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "created_at" : [
                            "[new Date(1622664000000), new Date(1622665800000)]"
                        ]
                    },
                    "keysExamined" : 257959,
                    "seeks" : 1,
                    "dupsTested" : 0,
                    "dupsDropped" : 0
                }
            }
        },
        "allPlansExecution" : [
            {
                "nReturned" : 100,
                "executionTimeMillisEstimate" : 625,
                "totalKeysExamined" : 257959,
                "totalDocsExamined" : 257959,
                "executionStages" : {
                    "stage" : "SORT",
                    "nReturned" : 100,
                    "executionTimeMillisEstimate" : 625,
                    "works" : 258060,
                    "advanced" : 100,
                    "needTime" : 257960,
                    "needYield" : 0,
                    "saveState" : 9571,
                    "restoreState" : 9571,
                    "isEOF" : 0,
                    "sortPattern" : {
                        "_id" : 1
                    },
                    "memLimit" : 104857600,
                    "limitAmount" : 100,
                    "type" : "simple",
                    "totalDataSizeSorted" : 187871472,
                    "usedDisk" : false,
                    "inputStage" : {
                        "stage" : "FETCH",
                        "nReturned" : 257959,
                        "executionTimeMillisEstimate" : 533,
                        "works" : 257960,
                        "advanced" : 257959,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 9571,
                        "restoreState" : 9571,
                        "isEOF" : 1,
                        "docsExamined" : 257959,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "nReturned" : 257959,
                            "executionTimeMillisEstimate" : 265,
                            "works" : 257960,
                            "advanced" : 257959,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 9571,
                            "restoreState" : 9571,
                            "isEOF" : 1,
                            "keyPattern" : {
                                "created_at" : 1
                            },
                            "indexName" : "created_at_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "created_at" : [ ]
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "created_at" : [
                                    "[new Date(1622664000000), new Date(1622665800000)]"
                                ]
                            },
                            "keysExamined" : 257959,
                            "seeks" : 1,
                            "dupsTested" : 0,
                            "dupsDropped" : 0
                        }
                    }
                }
            },
            {
                "nReturned" : 70,
                "executionTimeMillisEstimate" : 178092,
                "totalKeysExamined" : 258060,
                "totalDocsExamined" : 258060,
                "executionStages" : {
                    "stage" : "LIMIT",
                    "nReturned" : 70,
                    "executionTimeMillisEstimate" : 178092,
                    "works" : 258060,
                    "advanced" : 70,
                    "needTime" : 257990,
                    "needYield" : 0,
                    "saveState" : 9571,
                    "restoreState" : 9571,
                    "isEOF" : 0,
                    "limitAmount" : 100,
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$and" : [
                                {
                                    "created_at" : {
                                        "$lte" : ISODate("2021-06-02T20:30:00Z")
                                    }
                                },
                                {
                                    "created_at" : {
                                        "$gte" : ISODate("2021-06-02T20:00:00Z")
                                    }
                                }
                            ]
                        },
                        "nReturned" : 70,
                        "executionTimeMillisEstimate" : 178057,
                        "works" : 258060,
                        "advanced" : 70,
                        "needTime" : 257990,
                        "needYield" : 0,
                        "saveState" : 9571,
                        "restoreState" : 9571,
                        "isEOF" : 0,
                        "docsExamined" : 258060,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "nReturned" : 258060,
                            "executionTimeMillisEstimate" : 645,
                            "works" : 258060,
                            "advanced" : 258060,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 9571,
                            "restoreState" : 9571,
                            "isEOF" : 0,
                            "keyPattern" : {
                                "_id" : 1
                            },
                            "indexName" : "_id_",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "_id" : [ ]
                            },
                            "isUnique" : true,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "_id" : [
                                    "[MinKey, MaxKey]"
                                ]
                            },
                            "keysExamined" : 258060,
                            "seeks" : 1,
                            "dupsTested" : 0,
                            "dupsDropped" : 0
                        }
                    }
                }
            }
        ]
    },
    "serverInfo" : {
        "host" : "ip-10-0-3-171",
        "port" : 27017,
        "version" : "4.4.6",
        "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
    },
    "ok" : 1
}

10 分钟的快速查询:

> db.logs.explain('allPlansExecution').aggregate([{"$match":{"created_at":{"$gte":ISODate('2021-06-02T20:00:00.000+00:00'),"$lte":ISODate('2021-06-02T20:10:00.000+00:00')}}},{"$sort":{"_id":1}},{"$limit":1000}], { allowDiskUse: true });
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "webpush.campaign_action_logs",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "created_at" : {
                        "$lte" : ISODate("2021-06-02T20:10:00Z")
                    }
                },
                {
                    "created_at" : {
                        "$gte" : ISODate("2021-06-02T20:00:00Z")
                    }
                }
            ]
        },
        "optimizedPipeline" : true,
        "winningPlan" : {
            "stage" : "SORT",
            "sortPattern" : {
                "_id" : 1
            },
            "memLimit" : 104857600,
            "limitAmount" : 1000,
            "type" : "simple",
            "inputStage" : {
                "stage" : "FETCH",
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "created_at" : 1
                    },
                    "indexName" : "created_at_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "created_at" : [ ]
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "created_at" : [
                            "[new Date(1622664000000), new Date(1622664600000)]"
                        ]
                    }
                }
            }
        },
        "rejectedPlans" : [
            {
                "stage" : "LIMIT",
                "limitAmount" : 1000,
                "inputStage" : {
                    "stage" : "FETCH",
                    "filter" : {
                        "$and" : [
                            {
                                "created_at" : {
                                    "$lte" : ISODate("2021-06-02T20:10:00Z")
                                }
                            },
                            {
                                "created_at" : {
                                    "$gte" : ISODate("2021-06-02T20:00:00Z")
                                }
                            }
                        ]
                    },
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "_id" : 1
                        },
                        "indexName" : "_id_",
                        "isMultiKey" : false,
                        "multiKeyPaths" : {
                            "_id" : [ ]
                        },
                        "isUnique" : true,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 2,
                        "direction" : "forward",
                        "indexBounds" : {
                            "_id" : [
                                "[MinKey, MaxKey]"
                            ]
                        }
                    }
                }
            }
        ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1000,
        "executionTimeMillis" : 1502,
        "totalKeysExamined" : 58027,
        "totalDocsExamined" : 58027,
        "executionStages" : {
            "stage" : "SORT",
            "nReturned" : 1000,
            "executionTimeMillisEstimate" : 122,
            "works" : 59029,
            "advanced" : 1000,
            "needTime" : 58028,
            "needYield" : 0,
            "saveState" : 122,
            "restoreState" : 122,
            "isEOF" : 1,
            "sortPattern" : {
                "_id" : 1
            },
            "memLimit" : 104857600,
            "limitAmount" : 1000,
            "type" : "simple",
            "totalDataSizeSorted" : 42213931,
            "usedDisk" : false,
            "inputStage" : {
                "stage" : "FETCH",
                "nReturned" : 58027,
                "executionTimeMillisEstimate" : 96,
                "works" : 58028,
                "advanced" : 58027,
                "needTime" : 0,
                "needYield" : 0,
                "saveState" : 122,
                "restoreState" : 122,
                "isEOF" : 1,
                "docsExamined" : 58027,
                "alreadyHasObj" : 0,
                "inputStage" : {
                    "stage" : "IXSCAN",
                    "nReturned" : 58027,
                    "executionTimeMillisEstimate" : 40,
                    "works" : 58028,
                    "advanced" : 58027,
                    "needTime" : 0,
                    "needYield" : 0,
                    "saveState" : 122,
                    "restoreState" : 122,
                    "isEOF" : 1,
                    "keyPattern" : {
                        "created_at" : 1
                    },
                    "indexName" : "created_at_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "created_at" : [ ]
                    },
                    "isUnique" : false,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "created_at" : [
                            "[new Date(1622664000000), new Date(1622664600000)]"
                        ]
                    },
                    "keysExamined" : 58027,
                    "seeks" : 1,
                    "dupsTested" : 0,
                    "dupsDropped" : 0
                }
            }
        },
        "allPlansExecution" : [
            {
                "nReturned" : 101,
                "executionTimeMillisEstimate" : 122,
                "totalKeysExamined" : 58027,
                "totalDocsExamined" : 58027,
                "executionStages" : {
                    "stage" : "SORT",
                    "nReturned" : 101,
                    "executionTimeMillisEstimate" : 122,
                    "works" : 58129,
                    "advanced" : 101,
                    "needTime" : 58028,
                    "needYield" : 0,
                    "saveState" : 121,
                    "restoreState" : 121,
                    "isEOF" : 0,
                    "sortPattern" : {
                        "_id" : 1
                    },
                    "memLimit" : 104857600,
                    "limitAmount" : 1000,
                    "type" : "simple",
                    "totalDataSizeSorted" : 42213931,
                    "usedDisk" : false,
                    "inputStage" : {
                        "stage" : "FETCH",
                        "nReturned" : 58027,
                        "executionTimeMillisEstimate" : 96,
                        "works" : 58028,
                        "advanced" : 58027,
                        "needTime" : 0,
                        "needYield" : 0,
                        "saveState" : 121,
                        "restoreState" : 121,
                        "isEOF" : 1,
                        "docsExamined" : 58027,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "nReturned" : 58027,
                            "executionTimeMillisEstimate" : 40,
                            "works" : 58028,
                            "advanced" : 58027,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 121,
                            "restoreState" : 121,
                            "isEOF" : 1,
                            "keyPattern" : {
                                "created_at" : 1
                            },
                            "indexName" : "created_at_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "created_at" : [ ]
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "created_at" : [
                                    "[new Date(1622664000000), new Date(1622664600000)]"
                                ]
                            },
                            "keysExamined" : 58027,
                            "seeks" : 1,
                            "dupsTested" : 0,
                            "dupsDropped" : 0
                        }
                    }
                }
            },
            {
                "nReturned" : 3,
                "executionTimeMillisEstimate" : 935,
                "totalKeysExamined" : 58129,
                "totalDocsExamined" : 58129,
                "executionStages" : {
                    "stage" : "LIMIT",
                    "nReturned" : 3,
                    "executionTimeMillisEstimate" : 935,
                    "works" : 58129,
                    "advanced" : 3,
                    "needTime" : 58126,
                    "needYield" : 0,
                    "saveState" : 122,
                    "restoreState" : 122,
                    "isEOF" : 0,
                    "limitAmount" : 1000,
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$and" : [
                                {
                                    "created_at" : {
                                        "$lte" : ISODate("2021-06-02T20:10:00Z")
                                    }
                                },
                                {
                                    "created_at" : {
                                        "$gte" : ISODate("2021-06-02T20:00:00Z")
                                    }
                                }
                            ]
                        },
                        "nReturned" : 3,
                        "executionTimeMillisEstimate" : 935,
                        "works" : 58129,
                        "advanced" : 3,
                        "needTime" : 58126,
                        "needYield" : 0,
                        "saveState" : 122,
                        "restoreState" : 122,
                        "isEOF" : 0,
                        "docsExamined" : 58129,
                        "alreadyHasObj" : 0,
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "nReturned" : 58129,
                            "executionTimeMillisEstimate" : 17,
                            "works" : 58129,
                            "advanced" : 58129,
                            "needTime" : 0,
                            "needYield" : 0,
                            "saveState" : 122,
                            "restoreState" : 122,
                            "isEOF" : 0,
                            "keyPattern" : {
                                "_id" : 1
                            },
                            "indexName" : "_id_",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "_id" : [ ]
                            },
                            "isUnique" : true,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "_id" : [
                                    "[MinKey, MaxKey]"
                                ]
                            },
                            "keysExamined" : 58129,
                            "seeks" : 1,
                            "dupsTested" : 0,
                            "dupsDropped" : 0
                        }
                    }
                }
            }
        ]
    },
    "serverInfo" : {
        "host" : "ip-10-0-3-171",
        "port" : 27017,
        "version" : "4.4.6",
        "gitVersion" : "72e66213c2c3eab37d9358d5e78ad7f5c1d0d0d7"
    },
    "ok" : 1
}

问题:

  • 如果问题是扫描的文档数量并且我们使用了索引,我该如何解决?我不认为循环超过 5000k 会导致 300k 文档中的排序顺序出现问题,但也许我错了。

  • 为什么 LIMIT 阶段(带有另一个 FETCH 阶段)会导致问题?

提前非常感谢各位专家!

【问题讨论】:

  • 如果没有 sort 阶段,您的查询如何执行(我会尝试这个来理解问题)。
  • @prasad_ 很好的问题,没有我们所说的几毫秒查询的排序。超级快。问题是我必须对结果进行排序,因为我需要在每 5000 个项目之间跳转,并且当您需要跳过 100k 个项目时使用“跳过”和“限制”不是一个好习惯。 sammaye.wordpress.com/2012/05/25/…
  • 您的查询的缺点是在 $match 阶段有一个范围过滤器。这不允许 $sort 使用索引。这是进行内存排序的排序阶段 - 它无法使用索引。在$match 阶段 之后返回了多少个文档? (注意:我没有阅读链接的文章)。
  • 嘿,这篇文章只是为了解释为什么我避免跳过/限制。 @prasad_the docs after match 你可以在我在消息中添加的第一个“解释”中看到,在比赛的第一阶段我们有“docsExamined”:257959,我想返回 5000 个项目的限制,然后按 ID 跳过下一个 5000。
  • 您可能会受益于在 $match 阶段(连同当前过滤器)添加另一个具有相等条件的过滤器 - 这样我们可以让排序阶段使用索引.

标签: mongodb performance indexing


【解决方案1】:

问题在于排序。因为您在排序集上使用跳过/限制,它必须从磁盘加载 整个 集,然后在内存中对其进行排序(可能溢出到磁盘)以应用跳过/限制。

这意味着如果您有 100k 个文档与时间范围匹配,则加载所有 100k 以获得第一批,然后再加载 100k 以获得第二批。

如果索引包含排序依据的字段,并且索引创建规范中该键之前的任何字段都与相等谓词匹配,则 mongodb 中的索引可以支持排序。

与不等式或范围匹配的字段可以列在排序键之后。

{ _id:1 } 上的现有索引效率低下,因为它是非选择性的,因此需要从 diks 读取整个集合。

{ created_at:1 } 上的索引只需要加载那些与查询匹配的文档,但它们必须在内存中进行排序。

要支持此查询,请在 { _id:1, created_at:1 } 上创建索引。这个索引应该会显着提高性能,因为它既可以消除内存中的排序,又只需要查询执行器从磁盘加载那些与查询匹配的文档。这还有一个好处是查询执行器可以在满足限制后立即终止。

【讨论】:

  • "在 { _id:1, created_at:1 } 上创建索引" 不想......它没有在查询中使用。结果相同。我也尝试刷单。
  • 您能否显示考虑了这些索引的 allPlansExecution 输出?
猜你喜欢
  • 2012-08-18
  • 1970-01-01
  • 2011-11-23
  • 1970-01-01
  • 2022-11-03
  • 2021-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-10-29
相关资源
最近更新 更多