iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0
自我挑戰組

被MongoDB用Aggregate暴打的後端小菜雞日記系列 第 25

被MongoDB用Index暴打的後端小菜雞日記-day25-建立index的順序 (ESR rule)

  • 分享至 

  • xImage
  •  

昨天介紹到建立單一個欄位索引的方式,今天我來介紹如何建立複合索引(Compound Index),以及它背後運行的規則ESR rule (equality-sort- range rule),另外搭配explain來觀察我們下的搜尋語法,是否有真的命中索引。

在開始之前先跟大家介紹一下,我目前很常用的應用程式mongodb compass,這是MongoDB提供的應用程式,除了用來顯示目前資料庫內的資料,這個軟體提供幾個蠻好用的功能。

有時候在撰寫程式碼不知道如何寫query,或是不確定自己設定的索引是否合適,就可以利用mongodb compass實際下query觀察看看。

例如:我們進到collection的頁面,點選Documents可以看到目前collection內的資料,同時也可以透過上方的filter,填入要搜尋資料的條件。

點選Aggregations可以使用之前我們有介紹過的aggregatem語法,實際跑跑看是否正確撈到想要的資料,也可以點選右上方的Explain去看跑起來的效率,或是是否用使用到index。

點選Indexs可以看到目前有建立的索引,在這裡可以看到我們建立索引的大小、類型,同時也可以在這裡直接新增或刪除索引。

以及我們今天主要會介紹到的Explain Plan,它會分析query是否命中索引、搜尋的效率並且回傳相關的資訊,可以作為改寫index或query的參考。


現在假設我們依舊有一個專門紀錄商品資料的collection,裡面的資料格式如下。

// 範例資料,collection裡面有100筆商品資料
{
  _id: "632fce925476003ff0d03743",
  name: "鍵盤",
  price: 3866,
  amount: 73,
  category: "3C"
}

這時我建立一個category_1_price_1_amount_1的索引,此時category、price、amount建立的順序是有意義的。

如果我們下這樣的query指令

find({ category: “3C”, amount: { $gte: 3 } }).sort({ price: 1 })

正好會符合我們上面建立好的索引,原因是因為我們使用索引第一個欄位category做相等(equality)的搜尋條件,使用第二個欄位price進行資料的排序(sort),第三個欄位amount進行範圍搜尋( range),剛好有符合MongoDB建立索引的ESR rule條件。

假設我們換一個query指令,改成

find({ category: “3C”, price: { $lt: 3000 } }).sort({ amount: -1 })

變成不符合原本category_1_price_1_amount_1索引的設定,再進行搜尋時,只會使用到一部分的索引category_1_price_1,排序的部分,會使用到記憶體進行排序,在Explain的結果也有特別寫到Sorted in Memory: yes。

按照官方文件的說法,當要進行資料排序時,如果沒有合適的索引,或是排序的欄位本身並沒有建立索引,這時候會進行blocking sort,它執行排序的效率,比使用索引進行排序還要差。

如果要進行排序的資料大小超過 100 MB,並且沒有透過allowDiskUse() 設定可以採用硬碟寫入暫時性的資料,MongoDB會回傳錯誤訊息,如果有開啟設定,則會採用硬碟寫入資料進行排序,但是執行query的效率就會變差。

因此還是建議在建立索引時,務必確保有遵守ESR rule

參考資料
The ESR (Equality, Sort, Range) Rule
Use Indexes to Sort Query Results
Sort and Index Use

本篇文章同步放在我的部落格,大家有空可以進來逛逛


上一篇
被MongoDB用Index暴打的後端小菜雞日記-day 24- index使用懶人包
下一篇
被MongoDB用Index暴打的後端小菜雞日記-day26-Index Property
系列文
被MongoDB用Aggregate暴打的後端小菜雞日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言