In the case of a large amount of data, any database system is a time-consuming project when creating an index. MongoDB is no exception. Therefore, the creation of MongoDB index has two choices, one is the foreground mode, and the other is the backstage mode. What is the difference between these two approaches, and is it possible to see the progress of indexing completion when creating an index? This article will be a description based on this and also describes the considerations related to index creation.
First, how to create the index
前台方式
缺省情况下,当为一个集合创建索引时,这个操作将阻塞其他的所有操作。即该集合上的无法正常读写,直到索引创建完毕
任意基于所有数据库申请读或写锁都将等待直到前台完成索引创建操作
后台方式
将索引创建置于到后台,适用于那些需要长时间创建索引的情形
这样子在创建索引期间,MongoDB依旧可以正常的为提供读写操作服务
等同于关系型数据库在创建索引的时候指定online,而MongoDB则是指定background
其目的都是相同的,即在索引创建期间,尽可能的以一种占用较少的资源占用方式来实现,同时又可以提供读写服务
后台创建方式的代价:索引创建时间变长
后台创建索引的示例
db.people.createIndex( { zipcode: 1}, {background: true} )
db.people.createIndex( { city: 1}, {background: true, sparse: true } )
缺省情况下background选项的值为false
Ii. Considerations during index creation
如前所述,基于后台创建索引时,其他的数据库操作能被完成。但是对于mongo shell会话或者你正在创建索引的这个连接
将不可用,直到所有创建完毕。如果需要做一些其它的操作。则需要再建立其它的连接。
在索引创建期间,即使完成了部分索引的创建,索引依旧不可用,但是一旦创建完成即可使用。
基于后台创建索引期间不能完成涉及该集合的相关管理操作
repairDatabase
db.collection.drop()
compact
意外中断索引创建
如果在后台创建索引期间,mongod实例异常终止,当mongod实例重新启动后,未完成的索引创建将作为前台进程来执行
如果索引创建失败,比如由于重复的键等,mongod将提示错误并退出
在一个索引创建失败后启动mongod,可以使用storage.indexBuildRetry or --noIndexBuildRetry跳过索引创建来启动
Iii. performance during index creation
后台创建索引比前台慢,如果索引大于实际可用内存,则需要更长的时间来完成索引创建
所有涉及到该集合的相关操作在后台期间其执行效能会下降,应在合理的维护空挡期完成索引的创建
Iv. naming rules for indexes
缺省情况下,索引名以键名加上其创建顺序(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
V. View index Creation Progress
可使用 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})
Vi. Creating a terminating Index
MONGO before background CREATE INDEX--noindexbuildretry