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以內能實現嗎
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条,剩下的部分是个regex
,regex
无法命中索引,所以不管有没有对info
的索引都没有意义。在找到600w条数据之后还有一个对600w数据的filter
操作。唯一对这个操作可能有帮助的只有全文索引
在有user
索引的前提下,結果仍然有600w條,剩下的部分是個regex
,regex
無法命中索引,所以不管有沒有對
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就不能期待這麼高。如果你真有這方面的需求,就應該從源頭開始,考慮:info
每次
欄位有更新或插入時就做好計數
某草草2017-05-02 09:22:16
不了解,不過能不能分成兩個match會不會好一點呢。 。
類似
aggregate([
{$match:{user: 'xiaoming'}},
{$match:{info: /wrong/}},
{$group:{_id:null, count:{$sum:1}}}
])
主要我認為正規花時間。
有index的話,index一下user。