在資料量超大的情形下,任何資料庫系統在建立索引時都是一個耗時的大工程。MongoDB也不例外。是以,MongoDB索引的建立有兩個選擇,一個是前台方式,一個是背景方式。那這兩種方式有什麼差異呢,在建立索引是是否能觀察到索引完成的進度呢。本文将是基于此的描述,同時也描述了索引建立相關的注意事項。
一、索引建立方式
-
前台方式
-
預設情況下,當為一個集合建立索引時,這個操作将阻塞其他的所有操作。即該集合上的無法正常讀寫,直到索引建立完畢
-
任意基于所有資料庫申請讀或寫鎖都将等待直到前台完成索引建立操作
-
背景方式
-
将索引建立置于到背景,适用于那些需要長時間建立索引的情形
-
這樣子在建立索引期間,MongoDB依舊可以正常的為提供讀寫操作服務
-
等同于關系型資料庫在建立索引的時候指定online,而MongoDB則是指定background
-
其目的都是相同的,即在索引建立期間,盡可能的以一種占用較少的資源占用方式來實作,同時又可以提供讀寫服務
-
背景建立方式的代價:索引建立時間變長
-
背景建立索引的示例
-
db.people.createIndex( { zipcode: 1}, {background: true} )
-
db.people.createIndex( { city: 1}, {background: true, sparse: true } )
-
預設情況下background選項的值為false
二、索引建立期間注意事項
-
如前所述,基于背景建立索引時,其他的資料庫操作能被完成。但是對于mongo shell會話或者你正在建立索引的這個連接配接
-
将不可用,直到所有建立完畢。如果需要做一些其它的操作。則需要再建立其它的連接配接。
-
在索引建立期間,即使完成了部分索引的建立,索引依舊不可用,但是一旦建立完成即可使用。
-
基于背景建立索引期間不能完成涉及該集合的相關管理操作
-
repairDatabase
-
db.collection.drop()
-
compact
-
意外中斷索引建立
-
如果在背景建立索引期間,mongod執行個體異常終止,當mongod執行個體重新啟動後,未完成的索引建立将作為前台程序來執行
-
如果索引建立失敗,比如由于重複的鍵等,mongod将提示錯誤并退出
-
在一個索引建立失敗後啟動mongod,可以使用storage.indexBuildRetry or --noIndexBuildRetry跳過索引建立來啟動
三、索引建立期間性能
-
背景建立索引比前台慢,如果索引大于實際可用記憶體,則需要更長的時間來完成索引建立
-
所有涉及到該集合的相關操作在背景期間其執行效能會下降,應在合理的維護空擋期完成索引的建立
四、索引的命名規則
-
預設情況下,索引名以鍵名加上其建立順序(1或者-1)組合而成。
-
db.products.createIndex( { item: 1, quantity: -1 } )
-
比如上面的索引建立後,其索引名為item_1_quantity_-1
-
可以指定自定義的索引名稱
-
db.products.createIndex( { item: 1, quantity: -1 } , { name: "inventory_idx" } )
-
如上方式,我們指定了了索引名稱為inventory_idx
五、檢視索引建立進度
-
可使用 db.currentOp() 指令觀察索引建立的完成進度
-
> db.currentOp(
-
{
-
$or: [
-
{ op: "command", "query.createIndexes": { $exists: true } },
-
{ op: "insert", ns: /\.system\.indexes\b/ }
-
]
-
}
-
)
-
//下面通過一個索引建立示例來檢視索引完成進度
-
//首選建立一個500w文檔的集合
-
> db.version() // Author : Leshami
-
3.2.10 //
-
> for (var i=1;i<=5000000;i++){
-
db.inventory.insert({id:i,item:"item"+i,stock:Math.floor(i*Math.random())})
-
}
-
WriteResult({ "nInserted" : 1 })
-
> db.inventory.find().limit(3)
-
{ "_id" : ObjectId("581bfc674b0d633653f4427e"), "id" : 1, "item" : "item1", "stock" : 0 }
-
{ "_id" : ObjectId("581bfc674b0d633653f4427f"), "id" : 2, "item" : "item2", "stock" : 0 }
-
{ "_id" : ObjectId("581bfc674b0d633653f44280"), "id" : 3, "item" : "item3", "stock" : 1 }
-
> db.inventory.find().count()
-
5000000
-
//下面開始建立索引
-
> db.inventory.createIndex({item:1,unique:true})
-
//使用下面的指令檢視索引完成進度
-
> db.currentOp(
-
{
-
$or: [
-
{ op: "command", "query.createIndexes": { $exists: true } },
-
{ op: "insert", ns: /\.system\.indexes\b/ }
-
]
-
}
-
)
-
//結果如下
-
{
-
"inprog" : [
-
{
-
"desc" : "conn1", //連接配接描述
-
"threadId" : "139911670933248", //線程id
-
"connectionId" : 1,
-
"client" : "127.0.0.1:37524", //ip及端口
-
"active" : true, //活動狀态
-
"opid" : 5014925,
-
"secs_running" : 21, //已執行的時間
-
"microsecs_running" : NumberLong(21800738),
-
"op" : "command",
-
"ns" : "test.$cmd",
-
"query" : {
-
"createIndexes" : "inventory", //這裡描述了基于inventory正在建立索引
-
"indexes" : [
-
{
-
"ns" : "test.inventory",
-
"key" : {
-
"item" : 1,
-
"unique" : true
-
},
-
"name" : "item_1_unique_true"
-
}
-
]
-
},
-
"msg" : "Index Build Index Build: 3103284/5000000 62%", //這裡是完成的百分比
-
"progress" : {
-
"done" : 3103722,
-
"total" : 5000000
-
},
-
"numYields" : 0,
-
"locks" : { //目前持有的鎖
-
"Global" : "w",
-
"Database" : "W",
-
"Collection" : "w"
-
},
-
"waitingForLock" : false,
-
"lockStats" : { //鎖的狀态資訊
-
"Global" : {
-
"acquireCount" : {
-
"r" : NumberLong(1),
-
"w" : NumberLong(1)
-
}
-
},
-
"Database" : {
-
"acquireCount" : {
-
"W" : NumberLong(1)
-
}
-
},
-
"Collection" : {
-
"acquireCount" : {
-
"w" : NumberLong(1)
-
}
-
}
-
}
-
}
-
],
-
"ok" : 1
六、終止索引的建立
db.killOp()
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsAjMfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsQTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cGcq5CMyMGM1IzMhJDZiFjN3czNiRjM1IWOjVWNlJmMiBjM08CX1EzLchDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL5M3Lc9CX6MHc0RHaiojIsJye.jpg)