mongo之 前後臺創建索引 --noIndexBuildRetry
在數據量超大的情形下,任何數據庫系統在創建索引時都是一個耗時的大工程。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 // Blog : http://blog.csdn.net/leshami
-
> 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.inventory.createIndex({item:1,unique:true},{background: true})
六、終止索引的創建
db.killOp()
mongo之 前後臺創建索引 --noIndexBuildRetry