MongoDB 计数非常慢

Posted

技术标签:

【中文标题】MongoDB 计数非常慢【英文标题】:MongoDB count is very slow 【发布时间】:2018-01-09 15:01:37 【问题描述】:

我有一个收藏产品,里面有 ~7.000.000 本书,总共有 ~40GB mongodb 3.4 数据库。以下是一本书文档的示例:

 
    "_id" : ObjectId("597f17d22be7925d9a056e82"), 
    "ean13" : "9783891491904", 
    "price" : NumberInt(2100), 
    "name" : "My cool title", 
    "author_name" : "Doe, John", 
    "warengruppe" : "HC", 
    "book_category_key" : "728",
    "keywords": ["fairy tale", "magic", "fantasy"]
    ...

当我用limit查询数据库时,时机还可以。但是如果我计算查询(用于分页),那么它需要很长时间:

2017-08-02T13:03:16.088+0200 I COMMAND [conn74] command mydb.products command: count count: "products", query: book_category_key: $in: [ "120", "130" , "180", "111", "112", "140", "150", "160", "170", "190", "1AA" ] , readConcern: planSummary: IXSCAN book_category_key : 1 keysExamined:1129826 docsExamined:1129825 numYields:8851 reslen:44 locks: Global: acquireCount: r: 17704 , Database: acquireCount: r: 8852 , Collection: acquireCount: r: 8852 协议:op_query 7008ms

这是一个很好的查询:


    count: "products",
    query: 
        book_category_key: 
            $in: ["120",
            "130",
            "180",
            "111",
            "112",
            "140",
            "150",
            "160",
            "170",
            "190",
            "1AA"]
        

这需要 7 秒,有时甚至更长(最多 20 秒)。我在 book_category_key 上有一个索引:

 
    "v" : 2, 
    "name" : "book_category_key_1", 
    "ns" : "mydb.products", 
    "background" : true

【问题讨论】:

嗨,您是否尝试过对单个字段进行计数(所以如果 SQL 不是 count(*) 而是 count(key) .. 这是什么意思?如何在 mongodb 中做到这一点? 好像是在使用磁盘,或者后台有一些繁重的操作。您能否在运行查询时检查currentOp 中的timeAcquiringMicros 它是我自己的服务器,没有人在上面,没有其他服务在运行(只有 apache 和 mongodb),它有 32gb ram 和一个 ssd 作为磁盘。 find-query 设置相同,但限制为 9,skip 仅需 300ms。 如果您只对匹配的数量感兴趣,将其设为covered query 可能会有所帮助:db.products.find('book_category_key':$in:<yourArray>,'_id':0,'book_categoryfkey':1).count() 【参考方案1】:

问题在于planSummary: IXSCAN。当 count 使用 IXSCAN 时,它也使用 FETCH。像这样的:

"planSummary" : "IXSCAN  book_category_key: 1 ",
"execStats" : 
    "stage" : "COUNT",
    ..... 
    "inputStage" : 
        "stage" : "FETCH",
        ....
        "inputStage" : 
            "stage" : "IXSCAN",
            .....

在您的情况下,加载大约 1/7 的整个集合。

您可以为https://jira.mongodb.org/browse/SERVER-17266 和相关问题投票,并使用建议的解决方法强制 COUNT_SCAN:

let cnt = 0;
for(let category of ["120",
    "130",
    "180",
    "111",
    "112",
    "140",
    "150",
    "160",
    "170",
    "190",
    "1AA"])  cnt += db.g.count(book_category_key: category);
print(cnt);

是什么

"planSummary" : "COUNT_SCAN  book_category_key: 1 ",
"execStats" : 
    "stage" : "COUNT",
    ...
    "inputStage" : 
        "stage" : "COUNT_SCAN"
        ....

对于每个类别,如果索引适合内存,则应该快约 10 倍。

【讨论】:

这种编程解决方案比单个数据库请求解决方案快得多,这真的很奇怪,但在这种特定情况下,它可以工作。在其他情况下(比如***.com/questions/45461015/… 算这个)它不会起作用:( 这是一个公认的计数问题。它与全文搜索无关。作为另一个问题的旁注,请阅读***.com/a/21871569/1110423,这是我迄今为止阅读的功能当前状态的最佳解释之一。

以上是关于MongoDB 计数非常慢的主要内容,如果未能解决你的问题,请参考以下文章

用mongodb作为数据库服务器访问时非常慢?

Mongodb 聚合 $lookup 和 group 非常非常慢

MongoDB摄取非常慢

MongoDB 获取总数,因为使用聚合的结果非常慢

即使有索引,MongoDB 也发现查询非常慢

[Node.js, MongoDB/Mongoose]:使用 indexOf 生成唯一的标签列表非常慢