搜尋

首頁  >  問答  >  主體

mongodb - 百萬資料aggregate group sum 統計超耗時的問題,求解決方案

1、文檔結構範例

{
    _id: xxxx,
    user: 'xiaoming',
    level: 5,
    from: 'iPhone',
    info: 'something wrong'
}

2、場景:user為'xiaoming'的文檔有六、七百萬條

3、問題:怎麼提升aggregate+group+sum速度

aggregate([
    {$match:{user: 'xiaoming', info:{$regex:'wrong'}}},
    {$group:{_id:null, count:{$sum:1}}}
])

用上面這個來統計xiaoming帶有wrong的文檔數量,結果

{"_id": null, "count": 2299999 }

耗時30s-40s。 user、info、user+info三種索引都嘗試過,速度都沒有提升
baidu、google查到‘帶條件計數慢無解’
怎麼提升效率,10s以內能實現嗎

PHPzPHPz2757 天前1885

全部回覆(3)我來回復

  • PHP中文网

    PHP中文网2017-05-02 09:22:16

    首先要說明的一個問題是,對於OLAP型的操作,期望不應該太高。畢竟是對於大量資料的操作,光從IO就已經遠超通常的OLTP操作,所以要求達到OLTP操作的速度和並發是不切實際的,也是沒有意義的。但並不是說一點優化空間也沒有。
    我們先從索引入手。在沒有索引的前提下,找出600萬條{user: "xiaoming"}需要多少時間?全表掃描COLLSCAN從700w條資料找出600w條,跟隨1億條資料找出600w條顯然是兩個概念。命中索引IXSCAN,這個差異就會小很多,幾乎可以忽略。所以你說{user: 1}這個索引沒有作用是不對的,可能只是因為集合資料量太少看不出差異而已。順便應該提一下看效率是否有差異應該看執行計劃,不要看執行時間,時間是不準確的。 {user: "xiaoming"}需要多少时间?全表扫描COLLSCAN从700w条数据中找出600w条,跟从1亿条数据中找出600w条显然是两个概念。命中索引IXSCAN,这个差异就会小很多,几乎可以忽略。所以你说{user: 1}这个索引没有作用是不对的,可能只是因为集合数据量太少看不出差异而已。顺便应该提一下看效率是否有差异应该看执行计划,不要看执行时间,时间是不准确的。
    在有user索引的前提下,结果仍然有600w条,剩下的部分是个regexregex无法命中索引,所以不管有没有对info的索引都没有意义。在找到600w条数据之后还有一个对600w数据的filter操作。唯一对这个操作可能有帮助的只有全文索引在有user索引的前提下,結果仍然有600w條,剩下的部分是個regexregex無法命中索引,所以不管有沒有對

    的索引都沒有意義。在找到600w條資料之後還有一個對600w資料的filter操作。唯一對這個操作可能有幫助的只有全文索引,但全文索引並不能完全取代正規則,具體問題需要讀一下文件。考慮全文索引可行的情況下,可以建立複合索引:

    db.coll.createIndex({
      user: 1,
      info: "text"
    });

    對應地查詢應該改為:

    db.coll.aggregate([
      {$match:{user: 'xiaoming', $text: { $search: "wrong" }}},
      {$group:{_id:null, count:{$sum:1}}}
    ])

    關於複合全文索引的介紹參考這裡,仍然是有些限制需要注意。這樣優化之後預計在同樣的硬體下能降到20s以內,跟你要的10s內還有一段距離。原因開頭說了,對OLAP就不能期待這麼高。如果你真有這方面的需求,就應該從源頭開始,考慮:
    1. info每次
      欄位有更新或插入時就做好計數

    2. 每隔一段時間做一次完整的統計,快取統計結果,查詢的時候直接展現給使用者
    🎜

    回覆
    0
  • 某草草

    某草草2017-05-02 09:22:16

    不了解,不過能不能分成兩個match會不會好一點呢。 。

    類似

    aggregate([
        {$match:{user: 'xiaoming'}},
        {$match:{info: /wrong/}},
        {$group:{_id:null, count:{$sum:1}}}
    ])

    主要我認為正規花時間。
    有index的話,index一下user。

    回覆
    0
  • 给我你的怀抱

    给我你的怀抱2017-05-02 09:22:16

    實時性要求不高 可以定時統計 + 快取

    回覆
    0
  • 取消回覆