mongo 索引解析

摘要

mongo 的索引很是強大,和關係型數據庫索引沒什麼區別。這裏主要介紹mongo索引基本知識和mongo本人在索引上的犯的錯。mongodb

索引種類

  1. 單字段索引數據庫

  2. 複合索引 複合索引各個字段的順序應該是精確匹配字段(=xxx),排序字段(避免在內存中排序,使用index排序),範圍查詢字段數組

    如db.book.find({company: 'xxx', age:{$lt:30}).sort({name:1}) db.book.find().explain("executionStats")能夠很好的列出查詢執行計劃。 總共有四個重要參數: executionTimeMills:查詢執行的時間 nReturned: 返回的文檔數 totalKeysExamined: 索引掃描數 totalDocsExamined: 文檔掃描數bash

    固然但願nReturned數目=totalKeysExamined 不掃描文檔。(後面不掛着數據,index及數據)性能

    或者nReturned = totalKeysExamined = totalDocsExamined 若是有排序,爲了避免讓排序在內存中進入,在nReturned = totalDocsExamined的基礎上,totalKeysExamined能夠大於nReturned。對於大數據量的內存排序會很是消耗性能大數據

    若是咱們建立一個複合索引是db.book.ensureIndex({company:1,age:1,name:1}) 這時候nReturned = totalKeysExamined = totalDocsExamined 。由於查詢會用到index,不須要額外的文檔掃描。可是會有SORT stage,即在內存中排序,在大數據量的狀況下內存排序是很慢的。spa

    嘗試加一個index,在排序字段放在掃描字段前面 db.book.ensureIndex({company:1,name:1,age:1}) 這時候發現mongo選擇了新的indexscala

    "indexBounds" : {
             "company" : [
                     "[\"a\", \"a\"]"
             ],
             "name" : [
                     "[MinKey, MaxKey]"
             ],
             "age" : [
                     "[-1.#INF, 30.0)"
             ]
     },
    複製代碼

    且執行計劃中有reject SORT排序設計

    "rejectedPlans" : [
             {
                     "stage" : "SORT",
                     "sortPattern" : {
                             "name" : 1
                     },
    複製代碼

    這時候nReturned = totalDocsExamined < totalKeysExamined 多掃描了index,可是是值得的。這也是爲何在開始的時候時候說聯合index的字段排序順序是精確匹配字段(=xxx),排序字段(避免在內存中排序,使用index排序),範圍查詢字段 如{name:1,address:1},包含的是兩個查詢code

    db.book.find({name:"xxx"})
    db.book.find({name:"xxx",address:"xxx"})
    複製代碼

    可是若是你的查詢不是範圍查詢。而是精確匹配字段。那仍是使用原來的index。由於這時候排序字段用到了index查詢,不須要SORT階段了

    db.book.find({company:'a',age:30}).sort({name:1}).explain("executionStats")
      "indexBounds" : {
              "company" : [
                      "[\"a\", \"a\"]"
              ],
              "age" : [
                      "[30.0, 30.0]"
              ],
              "name" : [
                      "[MinKey, MaxKey]"
              ]
      },
    複製代碼
  3. 多鍵索引 如array索引 docs.mongodb.com/manual/core…

  • 多鍵索引是無法查一個數組所有匹配的,會先查第一個元素,後面的會使用filter

  • $elemMatch

    son:{ $elemMatch:{$gt:9,$lt:11}} 這個查詢和son:{$gt:9,$lt:11}的區別, 後者是隻要數組中任意一個字段知足其餘一個條件便可,好比第一個字段知足gt:9,第二個字段知足lt:11那麼也認爲是知足條件。因此使用索引時,只能使用到一個邊界條件。

  • 在聯合索引中只容許有一個array字段。可是由於mongo是free schema的。能夠是不一樣的字段,只要一個document中只有一個array就好了,在不一樣的document中能夠是不一樣字段

  1. 惟一索引 db.book.createIndex({"name":1},{"unique":true}) mongo 默認建立的不是惟一索引,須要顯示指定。惟一索引會對數據進行校驗,不容許重複數據。

  2. sharding cluster 索引 索引是在各個shard上面單獨創建的,不是全局的。 sharding cluster 環境,只容許_id,和shard key創建unique index.由於unique index 須要shard 之間通訊,違背了shard 設計理念。因此須要避免

注意

  1. 當一個collection上面有多個index 某個查詢可能命中多個index,這時候mongo是如何選擇索引的呢。

    首先mongo會對某類相似查詢語句在可能命中的index都執行一遍,並行執行的,最先返回100個結果找出最優的index,而後記住這類查詢所用到的索引。之後查詢操做就使用這個索引。當有index更改時,再去更改這個值。
    複製代碼
  2. 當有一個複合索引 {name:1,address:1,email:1}

    這時候有一個新的查詢{name:xxx,address:xxx,phone:xxx} 能夠用到已經建立的複合索引。這時候你會不會單獨在建立一個索引呢。 優點是這個查詢也很快,缺點是多了一個index,減弱了插入性能。

    這個可能須要衡量前兩個字段過濾掉了多少數據,phone這個字段佔剩下數據量的多少來決定須要建立什麼樣的index.

  3. mongo 中有一個名字叫scalar(標量字段)就是非array,非embedded document這樣的字段。針對這些字段的索引與關係型數據庫並沒有差異,無需特殊處理 以爲這篇分享就有點過於強調閱讀mongo源碼來解決的問題的重要性,由於這個就能夠經過上述分析找到root cause yq.aliyun.com/articles/74… #array index# mongo 能夠對array創建index,注意是將index中的每一個元素都做爲index key,進行索引。因此對array創建index必定要十分當心,很容易致使index size 很大。另外mongo支持指定array某一列進行查詢。

test.book
{
	_id:1,
	name:english,
	address:[addr1,addr2]
}
複製代碼

db.book.find({"address.0":"addr1"}) 當對address建立index,這樣的查詢是用不到index的。只有基於array的查詢,index纔能有效。 mongo並無那麼神奇的在建立index的同時還保留列數。

#shard key index#

  • 表中有數據 表中有數據再建立shard key,須要首先建立對應的index,才能去建立shard key
  • 表中無數據 表中無數據,建立shard key的同時,mongo會自動建立一個對應字段的index
sh.shardCollection("test.book",{name:1,address:1})
複製代碼

會自動建立index

{name:1,address:1}
複製代碼

mongo index VS cassandra secondary index

1.query 過程 cassandra query,首先根據partitioner key去找對應partition,partition中的數據是按照clustering key排序的。注意是按照clustering key排序的,clustering key這個字段 不是index。

mongo(sharding cluster) query,首先根據給定的shard key去找在哪一個節點上,而後將請求發送到此節點。進行查找。 若是你的query case是

db.book.find({name:"xxx",address:"xxx"})
複製代碼

而shard key是name。此外再單獨爲address創建一個index。這時候你的query實際上是命中的address 的單字段index。而不是預想的已經將name數據過濾了。這點和cassandra有很大的不一樣

2.範圍 cassandra secondary index 是local的,在每一個節點上。 mongo 的index是全局的。 mongo sharding cluster 環境,index也是在各個shard上獨立建立的。

參考

www.mongoing.com/eshu_explai…

相關文章
相關標籤/搜索