當使用以下語法對 Log 這個 Collection 依照 CreateTime 做倒序查詢
db.Log.find().sort({CreateTime: -1})
MongoDB 回傳了以下 Error Msg
Error: error: {
"ok" : 0,
"errmsg" : "Executor error during find command: OperationFailed: Sort operation used more than the maximum 33554432 bytes of RAM. Add an index, or specify a smaller limit.",
"code" : 96,
"codeName" : "OperationFailed"
}
發生原因
MongoDB 在排序時會將資料全部載入記憶體,之後在記憶體中進行排序,而預設開放給排序的記憶體只有 32 MB,因此在大量資料排序時就會引發該錯誤。
解決方案
建立索引 此範例為對 Log 這個 Collection 的 CreateTime 建立降冪排序的 Index
db.Log.createIndex({"CreateTime":-1})
可以用以下指令來查詢此 Collection 上有多少組 Index
db.Log.getIndexes()
增加索引會導致寫入資料速度變慢,且由於需要額外儲存 Index 資訊,會增加儲存資料所佔的空間,但對排序與搜尋有著正向的效能提升,若該欄位時常使用 where 與 sort 則建議可加上索引提高效能。
增加排序可用的記憶體空間 此範例為增加至 320 MB
db.adminCommand({setParameter:1,internalQueryExecMaxBlockingSortBytes:335544320})
若在不增加索引的狀況下修改預設記憶體大小,會導致排序時佔用更多記憶體空間進而影響到資料庫效能,不是一個治標的做法,建議僅在能確保使用量與不適合加入索引時謹慎使用此方案。
結論
在此案例裡,我採取的解決方案是雙管齊下,目的是確保指令可以正確執行,而增加記憶體上限是評估 MongoDB 主機記憶體總大小尚可負擔,可依照需求彈性決定是否對 Collection 上 Index 而同時確保可正常排序查詢
參考資料