1. 程式人生 > >MongoDB 線上實踐指南-基礎篇之支撐百億級訪問(三)

MongoDB 線上實踐指南-基礎篇之支撐百億級訪問(三)

MongoDB 線上實踐指南-基礎篇之支撐百億級訪問

索引

  • MongoDB 的組合索引使用策略與 MySQL 一致,遵循“最左原則”

  • 索引名稱長度不要超過128字元

  • 應儘量綜合評估查詢場景,通過評估儘可能的將單列索引併入組合索引以降低所以數量,結合1,2點

【案例8】MongoDB的組合索引規則和MySQL一樣,都遵循最左原理,假設一個組合索引為:{a:1,b:1,c:1},那麼以下條件的查詢是可以被用到的:
{a:1}
{a:1,b:2}
{a:1,b:2,c:3}
{}
以下條件的查詢是不能用到索引的:
{b:1}
{b:1:c:2}
{c:2}
另外在設計索引的時候可以通過該原理減少索引的數目,如果需要通過{a:xxx}或{a:xxx,b:xxx}來進行查詢,那麼建立索引:
{a:1,b:1}
即可同時滿足這兩個查詢場景而無需再單獨建立{a:1}索引。

  • 在建立組合索引的時候,應評估索引中包含的欄位,儘量將資料基數大的欄位放在組合索引的前面

【案例9】某業務某場景下的查詢十分緩慢,大概需要1.7秒左右,需要進行調優,該場景的查詢和對應索引如下:
查詢:{name:baidu,status:0}
索引:{status:1,name:1}
乍一看沒什麼問題,因為查詢和索引十分匹配,但對該集合分析後發現該集合一共有150萬文件,而status=0的有1499930由於這基本上佔了99%的文件數目(資料基數很小),所以導致雖然使用了索引,但依然需要從149萬行資料中找到name=baidu的資料但name欄位則有大量不同的資料(資料基數很大),所以如果將該組合索引調整為name在前,該查詢即可先通過name欄位抽出較少的資料,再通過status進行過濾,就快了:
{name:1.status:1}調整後查詢耗時降低到3~5毫秒。

  • 在資料量較大的時候,MongoDB 索引的建立是一個緩慢的過程,所以應當在上前線或資料量變得很大前儘量評估,按需建立會用到的索引

  • MongoDB 的索引建立是庫級鎖,在索引建立時該集合所在庫不可讀寫,所以如需新增索引,請聯絡 DBA

【案例10】某業務MongoDB突然報警, DBA緊急排查發現業務自行在一個較大的集合(300萬行資料)上建立了一個索引導致該集合所在的庫整個鎖死這是因為MongoDB的鎖為庫級鎖,而索引的調整也會鎖住整個庫直到索引調整完畢,此時與該庫有關的讀寫操作以及與該例項有關的整體的狀態查詢操作均會被阻塞,所以對於讀寫較大的例項這樣建立索引是十分危險的,在MongoDB2.4中可以用一個引數來規避主庫的索引建立 導致的阻塞:{‘background’:’true’},但當這一操作同步到從庫後,從庫將會前臺執行,此時從庫的讀寫會被阻塞,而在MongoDB2.6中, 該操作在從庫也會同樣被放入後臺執行以達到同樣不影響讀寫的目的,但是這個引數帶來的新問題是:如果一個集合非常非常大,那麼後臺建立索引會變得很慢很慢,對於一些較為急迫的索引調整需求這是無法滿足的。而DBA可以採用rolling的方式,通過迴圈切主,下線從庫新增索引的方式為整個叢集新增索引,所以為了業務的穩定、安全,開發切勿自行新增索引,以防阻塞口。

  • MongoDB 支援 TTL 索引,該索引能夠按你的需要自動刪除XXX秒之前的資料並會盡量選擇在業務低峰期執行刪除操作
  • 如果你存放的資料是地理位置資訊,比如:經緯度資料。那麼可以在該欄位上新增 MongoDB 支援的地理索引:2d 及 2dsphere,但他們是不同的,混用會導致結果不準確

2d:只能用於點對點索引,適用於平面地圖和時間連續的資料,比如非常適用於遊戲地圖【2dsphere:允許指定點、線和多邊形。適用於地球表面型別的地圖(球體) 】如果在球體表面建立2d索引,則會導致極點附近出現大量扭曲變形,最終導致結果不準確


  • MongoDB 的全文索引目前仍然處於“實驗”階段,效能並不夠理想,當前不建議使用
  • 從 MongoDB2.4開始,支援索引的 ICP 功能,可以通過其合理減少索引數量

從 MongoDB2.4開始,組合索引能夠被更有效的利用,如:
索引{x:1,y:1,z:1}可以被查詢{x:1,z:1}所利用如果x欄位的資料基數很大,而該條件匹配到的資料有很少,在這種情況下無需專門新增{x:1,z:1}索引,索引{x:1,y:1,z:1}即可帶來理想的效能但需要注意的是,ICP 效能並沒有原生的連續的組合索引效率好,如果發現效率不佳那麼還是需要新增單獨的{x:1,z:1}索引