Mongodb Index 最佳實踐

Posted by Alan Zhan on Sunday, April 10, 2022

自上一篇在實際的 Porduction 發生了 sorted operation oom 的問題之後,才意識到自己對於 mongodb Index 的掌握度沒有那麼高,於是開始餵關鍵字給 google 查了好久才終於整理出一些重點,有一些重點在上一篇,可以到上一篇複習一下 MongoDB Sorted Operation OOM

什麼情況建議使用 Index

  • 如果你有需要排序的場景,當記憶體排序超過 32 MB 的時候。
  • 特定欄位有 unique 的需求。
  • Document 數量較大時。
  • 針對 High-Cardinality Field 建立 Index。

什麼情況下不建議使用 Index

  • Index 不能夠有效的過濾數據時,不建議使用 Index。
  • 會頻繁更新的 Field ,不要設置 Index 。

Index 該如何設計與使用

使用 Compound Index 取代 Single Field Index

在 MongoDB 內,使用 find 查詢資料時,一次只能使用一個 Index (在大部分場景下),所以如果你的使用場景經常是針對多個 field 做過濾條件的話,可以使用 Compound Index 是由許多不同 Field 組合而成,來匹配你的查詢條件。

遵循 ESR 規則

ESR 分別代表 Equality 、 Sort 、 Range , 也就是說 Index 的 Field 順序,必須要按照這個順序設置 Index ,才能達到最高效率。

  • Equality : 針對等值查詢的 Field。
  • Sort : 要排序的 Field。
  • Range : 要訪問的數據範圍的 Field。

讓 Index 覆蓋查詢

Covered Queries,可以直接從 Index 中返回結果,因此非常高效。

在使用的同時,需要滿足以下條件:

  • 所有查詢條件的 Fields,都需要是 Index 的一部分。
  • 所有返回的 Fileds,都必須是 Index 的一部分。
  • 在查詢條件中,不包含等於 null,譬如: (i.e. {"field" : null} or {"field" : {$eq : null}} )

在 Low-Cardinality Fields 上要小心進行 Index

對於較少量唯一值得 Field 進行查詢會返回較大的結果。

在 Compound Index 中可以包含 Low-Cardinality Field ,但是組合的 Index 需要包含較 High-Cardinality Field 。

移除不必要的 Index

過多的 Index 會導致系統在 CUD 的時候性能下降,所以 Index 最好是適量就好,不要建立太多 Index。

不要使用通配符 Index 來代替

對於特殊查詢模式或處理多態的 Document 的工作負載,通配符 Index 確實提供了許多額外的靈活性,但是以其他的 Index 一樣,他也需要存儲以及維護,因此他會給 MongoDB 增加開銷。

如果預先可以先知道應用程式的查詢模式,那麼應該對查詢所訪問的特定 Field 使用更有選擇性的 Index 。

使用 Partial Index

可以通過在特定的 Field 上建立 Partial Indexes 的方式來減少 Index 大小以及性能開銷。譬如: 在訂單狀態的 Field 上,只要狀態為"處理中"的,成為 index。

為排序建立合適的 Index

因為 MongoDB 在排序的過程中,最多只能使用 32 MB 的記憶體來排序,所以如果要避免此問題發生,需要在對應的欄位上建立 Index 。

小心以下操作符的使用

  1. $where 和 $exists: 這兩個操作符,完全吃不到 Index 。
  2. $ne 和 $not: 通常還是可以使用 Index ,但是效率極低,甚至可能會變成 COLLSCAN 。
  3. 如果你的查詢語句有 $or 的話,要注意是否 or 的兩置多個條件,是否每個條件都可以使用不同的 Index (在 or 底下,是支援多個 Index 引用的),但是如果 $or + $sort 的話,就一定不會使用 Index ,可以的話使用使用的範圍查詢的方式,進而避開 $or + $sort。
  4. $nin: 不包含,這個操作也很容易變成 COLLSCAN 。
  5. 對於 pipeline 內的 Index ,也很容易出意外,一旦經過 $project 、 $group 、 $lookup$ 、 $unwind 等操作之後,就會完全無法使用 Index 。

不要在頻繁寫入的 Field 上建立 Index

因為在頻繁會更新的欄位上建立 Index 的話,會導致每次在寫入或者更新的時候,都還需要去更新 Index 的 Btree,進而會導致性能下降, Index 在讀取操作較為重的情境下,比較能發揮出效能。

自動化 Index 建議

如果真的不知道該怎麼設計以及使用時,這時候可以以不變應萬變,通過 Performance Advisor 讓他監控執行超過 100 ms 的查詢,並且自動對新的 Index 提出建議來提高性能,不過這個是不太建議的做法。

較好的做法是事前就先做好規劃,並且透過 Performance Advisor 去幫助自己看系統是不是還有哪邊是需要再做額外的調整的。

總結

上述只有列出比較常見的場景,要如何設計以及使用 Index ,如果你其他常見的場景以及對應的 Index 使用方式,也歡迎到我的 Facebook 留言一起討論。

歡迎到我的 Facebook Alan 的筆記本 留言,順手給我個讚吧!你的讚將成為我持續更新的動力,感謝你的閱讀,讓我們一起學習成為更好的自己。

參考