1. 程式人生 > >Mongodb 索引優化建議

Mongodb 索引優化建議

業務背景

偶然的一次機會,聽到我們專案的API 呼叫方說請求超時,server 返回500,經查驗說是交易的collection資料量太大(超過100GB),而且每天通過spring batch新增80w資料量,目前表的資料量已經過億,有同事分析了查詢說是通過索引會掃描大量的無效資料(此處預設通過id 排序分頁),然後只能強制刪除了大部分資料(目前是30GB)。

索引優化

原先的查詢語句如下(涉及保密資料用xxxx代替):

db.Trade.find( {_id:{$lte:ObjectId("xxxxxxxx")},"startDate":{"$lte":ISODate("2018-12-08T23:59:59.000Z")},"endDate":{"$not":{"$lte":ISODate("2018-12-08T23:59:59.000Z")}},"source":"XXXX"}).hint('_id_1_startDate_1_endDate_1').sort({ '_id': -1 }).limit(100000)

 

db.Trade.find( {_id:{$lte:ObjectId("XXXXXXXX")}, "startDate":{"$lte":ISODate("2018-12-08T23:59:59.000Z")},"endDate":{"$not":{"$lte":ISODate("2018-12-08T23:59:59.000Z")}}, markingSystems: { $in: ['XXX'] }}).sort({ '_id': -1 }).limit(100000)

經分析建立如下索引:

db.Trade.createIndex({'source':1,'_id':-1,startDate:1,endDate:1},{background:true})

db.Trade.createIndex({'markingSystem':1,'_id':-1,startDate:1,endDate:1},{background:true})

優化後的performance : from 100sec to 2sec

原因:

原先的索引'_id_1_startDate_1_endDate_1'有明顯的缺點,它是先根據_id排序再過濾的,所以Iindexscan的時候會過濾大量的無效資料,而新的索引{'markingSystem':1,'_id':-1,startDate:1,endDate:1} or {'source':1,'_id':-1,startDate:1,endDate:1}會根據markingSystem or source過濾掉大量無效資料,接下來再根據其他過濾條件來過濾的範圍會小很多。

優化建議

組合索引第一個欄位應該是查詢頻率較高的欄位,第二個是你要排序的欄位,其餘放後面。

第一個欄位需要特別注意,最好放等值查詢的欄位,不要放範圍查詢的欄位,如 $gt, $gte, $lt等。

 

ps:如果你還有更好的建議,歡迎留言一起探討