共計 7411 個字符,預計需要花費 19 分鐘才能閱讀完成。
這篇文章主要介紹了 MongoDB 數據庫中索引和 explain 的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓丸趣 TV 小編帶著大家一起了解一下。
mongodb 索引使用
作用
索引通常能夠極大的提高查詢。
索引是一種數據結構,他搜集一個集合中文檔特定字段的值。
B-Tree 索引來實現。
創建索引
db.collection.createIndex(keys, options)
keys
keys 由文檔字段和索引類型組成。如 {name :1}
key 表示字段 value 1,-1 1 表示升序,- 1 降序
options
options 創建索引的選項。
參數類型描述 backgroundboolean 創建索引在后臺運行,不會阻止其他對數據庫操作 uniqueboolean 創建唯一索引,文檔的值不會重復 namestring 索引名稱,默認是:字段名_排序類型 開始排序 sparseboolean 過濾掉 null,不存在的字段
查看索引
db.collection.getIndexes()
{
v : 1,
key : {
_id : 1
},
name : _id_ ,
ns : leyue.userdatas
},
{
v : 1,
key : {
name : 1 // 索引字段
},
name : name_1 , // 索引名稱
ns : leyue.userdatas
}
刪除索引
db.collection.dropIndex(index) 刪除指定的索引。
db.collection.dropIndexes() 刪除除了_id 以外的所有索引。
index 是字符串 表示按照索引名稱 name 刪除字段。
index 是 {字段名稱:1} 表示按照 key 刪除索引。
創建 / 查看 / 刪除 示例
查看數據
db.userdatas.find()
{ _id : ObjectId( 597f357a09c84cf58880e412), name : u3 , age : 32 }
{ _id : ObjectId( 597f357a09c84cf58880e411), name : u4 , age : 30, score : [ 7, 4, 2, 0 ] }
{ _id : ObjectId( 597fcc0f411f2b2fd30d0b3f), age : 20, score : [ 7, 4, 2, 0, 10, 9, 8, 7 ], name : lihao }
{ _id : ObjectId( 597f357a09c84cf58880e413), name : u2 , age : 33, wendang : { yw : 80, xw : 90 } }
{ _id : ObjectId( 5983f5c88eec53fbcd56a7ca), date : ISODate(2017-08-04T04:19:20.693Z) }
{ _id : ObjectId( 597f357a09c84cf58880e40e), name : u1 , age : 26, address : 中國碭山 }
{ _id : ObjectId( 597f357a09c84cf58880e40f), name : u1 , age : 37, score : [ 10, 203, 12, 43, 56, 22 ] }
{ _id : ObjectId( 597f357a09c84cf58880e410), name : u5 , age : 78, address : china beijing chaoyang }
給字段 name 創建索引
// 創建索引
db.userdatas.createIndex({name :1})
{
createdCollectionAutomatically : false,
numIndexesBefore : 1,
numIndexesAfter : 2,
ok : 1
}
}
]
給字段 name 創建索引并命名為 myindex
db.userdatas.createIndex({name :1})
db.userdatas.createIndex({name :1},{name : myindex})
db.userdatas.getIndexes()
[
{
v : 1,
key : {
_id : 1
},
name : _id_ ,
ns : leyue.userdatas
},
{
v : 1,
key : {
name : 1
},
name : myindex ,
ns : leyue.userdatas
}
]
給字段 name 創建索引 創建的過程在后臺執行
當 mongodb 集合里面的數據過大時 創建索引很耗時,可以在放在后臺運行。
db.userdatas.dropIndex(myindex)
db.userdatas.createIndex({name :1},{name : myindex , background :true})
給 age 字段創建唯一索引
db.userdatas.createIndex({age :-1},{name : ageIndex , unique :true, sparse :true})
db.userdatas.getIndexes()
{
v : 1,
key : {
_id : 1
},
name : _id_ ,
ns : leyue.userdatas
},
{
v : 1,
key : {
name : 1
},
name : myindex ,
ns : leyue.userdatas ,
background : true
},
{
v : 1,
unique : true,
key : {
age : -1
},
name : ageIndex ,
ns : leyue.userdatas ,
sparse : true
}
// 插入一個已存在的 age
db.userdatas.insert({ name : u8 , age : 32})
code : 11000,
errmsg : E11000 duplicate key error index: leyue.userdatas.$ageIndex dup key: { : 32.0 }
}
})
創建復合索引
db.userdatas.createIndex({name :1, age :-1})
db.userdatas.getIndexes()
{
v : 1,
key : {
_id : 1
},
name : _id_ ,
ns : leyue.userdatas
},
{
v : 1,
key : {
name : 1,
age : -1
},
name : name_1_age_-1 ,
ns : leyue.userdatas
}
]
所有的字段都存在集合 system.indexes 中
db.system.indexes.find()
{ v : 1, key : { _id : 1 }, name : _id_ , ns : leyue.userdatas }
{ v : 1, key : { _id : 1 }, name : _id_ , ns : leyue.scores }
{ v : 1, key : { _id : 1 }, name : _id_ , ns : leyue.test }
{ v : 1, key : { user : 1, name : 1 }, name : myindex , ns : leyue.test }
{ v : 1, key : { _id : 1 }, name : _id_ , ns : leyue.mycapped }
{ v : 1, key : { user : 1 }, name : user_1 , ns : leyue.test }
{ v : 1, key : { name : 1 }, name : myindex , ns : leyue.userdatas }
索引總結
1: 創建索引時,1 表示按升序存儲,- 1 表示按降序存儲。
2: 可以創建復合索引, 如果想用到復合索引, 必須在查詢條件中包含復合索引中的前 N 個索引列
3: 如果查詢條件中的鍵值順序和復合索引中的創建順序不一致的話,
MongoDB 可以智能的幫助我們調整該順序, 以便使復合索引可以為查詢所用。
4: 可以為內嵌文檔創建索引, 其規則和普通文檔創建索引是一樣的。
5: 一次查詢中只能使用一個索引,$or 特殊, 可以在每個分支條件上使用一個索引。
6: $where,$exists 不能使用索引, 還有一些低效率的操作符, 比如:$ne,$not,$nin 等。
7: 設計多個字段的索引時, 應該盡量將用于精確匹配的字段放在索引的前面。
explain 使用
語法
db.collection.explain(). method(...)
explain() 可以設置參數:
queryPlanner。
executionStats。
allPlansExecution。
示例
for(var i=0;i 100000;i++) { db.test.insert({ user : user +i});
}
沒有使用索引
db.test.explain(executionStats).find({user : user200000})
queryPlanner : {
plannerVersion : 1,
namespace : leyue.test ,
indexFilterSet : false,
parsedQuery : {
user : {
$eq : user200000
}
},
winningPlan : {
stage : COLLSCAN ,
filter : {
user : {
$eq : user200000
}
},
direction : forward
},
rejectedPlans : [ ]
},
executionStats : {
executionSuccess : true,
nReturned : 2,
executionTimeMillis : 326,
totalKeysExamined : 0,
totalDocsExamined : 1006497,
executionStages : {
stage : COLLSCAN ,
filter : {
user : {
$eq : user200000
}
},
nReturned : 2,
executionTimeMillisEstimate : 270,
works : 1006499,
advanced : 2,
needTime : 1006496,
needYield : 0,
saveState : 7863,
restoreState : 7863,
isEOF : 1,
invalidates : 0,
direction : forward ,
docsExamined : 1006497
}
},
serverInfo : {
host : lihaodeMacBook-Pro.local ,
port : 27017,
version : 3.2.1 ,
gitVersion : a14d55980c2cdc565d4704a7e3ad37e4e535c1b2
},
ok : 1
}
executionStats.executionTimeMillis: query 的整體查詢時間。
executionStats.nReturned : 查詢返回的條目。
executionStats.totalKeysExamined:索引掃描條目。
executionStats.totalDocsExamined:文檔掃描條目。
executionTimeMillis = 326 query 執行時間
nReturned=2 返回兩條數據
totalKeysExamined=0 沒有用到索引
totalDocsExamined 全文檔掃描
理想狀態:
nReturned=totalKeysExamined totalDocsExamined=0
Stage 狀態分析
stage 描述 COLLSCAN 全表掃描 IXSCAN 掃描索引 FETCH 根據索引去檢索指定 documentSHARD_MERGE 將各個分片返回數據進行 mergeSORT 表明在內存中進行了排序 LIMIT 使用 limit 限制返回數 SKIP 使用 skip 進行跳過 IDHACK 針對_id 進行查詢 SHARDING_FILTER 通過 mongos 對分片數據進行查詢 COUNT 利用 db.coll.explain().count() 之類進行 count 運算 COUNTSCANcount 不使用 Index 進行 count 時的 stage 返回 COUNT_SCANcount 使用了 Index 進行 count 時的 stage 返回 SUBPLA 未使用到索引的 $or 查詢的 stage 返回 TEXT 使用全文索引進行查詢時候的 stage 返回 PROJECTION 限定返回字段時候 stage 的返回
對于普通查詢,我希望看到 stage 的組合 (查詢的時候盡可能用上索引):
Fetch+IDHACK
Fetch+ixscan
Limit+(Fetch+ixscan)
PROJECTION+ixscan
SHARDING_FITER+ixscan
COUNT_SCAN
不希望看到包含如下的 stage:
COLLSCAN(全表掃描),SORT(使用 sort 但是無 index), 不合理的 SKIP,SUBPLA(未用到 index 的 $or),COUNTSCAN(不使用 index 進行 count)
使用索引
db.test.createIndex({user :1},{name : myindex , background :true})
db.test.explain(executionStats).find({user : user200000})
queryPlanner : {
plannerVersion : 1,
namespace : leyue.test ,
indexFilterSet : false,
parsedQuery : {
user : {
$eq : user200000
}
},
winningPlan : {
stage : FETCH ,
inputStage : {
stage : IXSCAN ,
keyPattern : {
user : 1
},
indexName : myindex ,
isMultiKey : false,
isUnique : false,
isSparse : false,
isPartial : false,
indexVersion : 1,
direction : forward ,
indexBounds : {
user : [ [\ user200000\ , \ user200000\]
]
}
}
},
rejectedPlans : [ ]
},
executionStats : {
executionSuccess : true,
nReturned : 2,
executionTimeMillis : 0,
totalKeysExamined : 2,
totalDocsExamined : 2,
executionStages : {
stage : FETCH ,
nReturned : 2,
executionTimeMillisEstimate : 0,
works : 3,
advanced : 2,
needTime : 0,
needYield : 0,
saveState : 0,
restoreState : 0,
isEOF : 1,
invalidates : 0,
docsExamined : 2,
alreadyHasObj : 0,
inputStage : {
stage : IXSCAN ,
nReturned : 2,
executionTimeMillisEstimate : 0,
works : 3,
advanced : 2,
needTime : 0,
needYield : 0,
saveState : 0,
restoreState : 0,
isEOF : 1,
invalidates : 0,
keyPattern : {
user : 1
},
indexName : myindex ,
isMultiKey : false,
isUnique : false,
isSparse : false,
isPartial : false,
indexVersion : 1,
direction : forward ,
indexBounds : {
user : [ [\ user200000\ , \ user200000\]
]
},
keysExamined : 2,
dupsTested : 0,
dupsDropped : 0,
seenInvalidated : 0
}
}
},
serverInfo : {
host : lihaodeMacBook-Pro.local ,
port : 27017,
version : 3.2.1 ,
gitVersion : a14d55980c2cdc565d4704a7e3ad37e4e535c1b2
},
ok : 1
}
executionTimeMillis: 0
totalKeysExamined: 2
totalDocsExamined:2
nReturned:2
stage:IXSCAN
使用索引和不使用差距很大,合理使用索引,一個集合適合做 4-5 個索引。
感謝你能夠認真閱讀完這篇文章,希望丸趣 TV 小編分享的“MongoDB 數據庫中索引和 explain 的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持丸趣 TV,關注丸趣 TV 行業資訊頻道,更多相關知識等著你來學習!