mongo 的索引很是強大,和關係型數據庫索引沒什麼區別。這裏主要介紹mongo索引基本知識和mongo本人在索引上的犯的錯。mongodb
單字段索引數據庫
複合索引 複合索引各個字段的順序應該是精確匹配字段(=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]"
]
},
複製代碼
多鍵索引 如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中能夠是不一樣字段
惟一索引 db.book.createIndex({"name":1},{"unique":true}) mongo 默認建立的不是惟一索引,須要顯示指定。惟一索引會對數據進行校驗,不容許重複數據。
sharding cluster 索引 索引是在各個shard上面單獨創建的,不是全局的。 sharding cluster 環境,只容許_id,和shard key創建unique index.由於unique index 須要shard 之間通訊,違背了shard 設計理念。因此須要避免
注意
當一個collection上面有多個index 某個查詢可能命中多個index,這時候mongo是如何選擇索引的呢。
首先mongo會對某類相似查詢語句在可能命中的index都執行一遍,並行執行的,最先返回100個結果找出最優的index,而後記住這類查詢所用到的索引。之後查詢操做就使用這個索引。當有index更改時,再去更改這個值。
複製代碼
當有一個複合索引 {name:1,address:1,email:1}
這時候有一個新的查詢{name:xxx,address:xxx,phone:xxx} 能夠用到已經建立的複合索引。這時候你會不會單獨在建立一個索引呢。 優點是這個查詢也很快,缺點是多了一個index,減弱了插入性能。
這個可能須要衡量前兩個字段過濾掉了多少數據,phone這個字段佔剩下數據量的多少來決定須要建立什麼樣的index.
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#
sh.shardCollection("test.book",{name:1,address:1})
複製代碼
會自動建立index
{name:1,address:1}
複製代碼
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上獨立建立的。