索引创建¶
MongoDB提供了几个 只会 影响索引创建的选项。您可以在使用 db.collection.ensureIndex() 时,把这些选项设置在一个文档里传递给方法作为第二个参数。本节将会描述这些选项的使用和特性。
后台创建¶
默认情况下,创建索引会阻塞数据库中所有其他操作。当在一个集合上创建索引时,存储了这个集合的数据库变成不可读不可写的状态知道索引建立完毕。任何需要所有数据库中读或者写锁的操作(例如 listDatabases )将会等待,直到后台索引创建完成。
对于可能需要长时间运行的索引创建操作,可以考虑 background 选项,这样MongoDB数据库在索引创建期间仍然是可用的。例如,在 people 集合的 zipcode 键上创建一个索引,这个过程在后台运行,可以使用如下方式:
db.people.ensureIndex( { zipcode: 1}, {background: true} )
默认地,MongoDB索引创建的 background 是 false 。
您可以将background选项和其他选项组合在一起,如下:
db.people.ensureIndex( { zipcode: 1}, {background: true, sparse: true } )
特性¶
到了MongoDB版本2.4及之后,一个 mongod 实例可以在后台并发创建多个索引。
在 2.4 版更改: 在2.4以前,一个 mongod 实例同一时刻只能在后台为每个数据库创建一个索引。
在 2.2 版更改: 在版本2.2一起, 一个 mongod 实例一次只能创建一个索引。
在后台创建索引这样其他的数据库操作可以被执行。但是,执行这个索引创建操作的 mongo shell的会话或者连接 将会 阻塞直到索引创建完毕。如果希望继续对这个数据库操作,请重新开启一个连接或者 mongo shell实例。
查询将不会使用部分建立的索引:索引只有在建立完毕之后才是可用的。
注解
如果MongoDB在后台创建一个索引,您不能执行其他会涉及到该集合的管理操作,包括 repairDatabase 命令,删除集合(例如 db.collection.drop() ),和 compact 命令。当后台创建索引时,这些操作会返回一个错误。
性能¶
后台索引创建操作使用的是一种增量的方式,这会比普通的 “前台” 创建过程慢。如果索引大于现有的内存,那么这个增量处理过程将会比前台创建过程 久得多 。
如果您的应用中包含 ensureIndex() 操作,且出于其他操作上的考虑这个索引 不 存在,那么建立一个索引可能会对数据库的性能有严重影响。
为了避免性能问题,请确保您的应用在启动时就使用 getIndexes() 方法或者其他 equivalent method for your driver 检查索引是否存在,如果不存在请退出应用。或者在生产实例上使用不同的应用代码在指定的维护时间窗口期间创建索引。
在从节点上(Secondaries)建立索引¶
在 2.6 版更改: 从节点成员限制夜可以在后台创建索引了。之前的版本,所有在从节点上建立的索引都必须是在前台建立。
当 primary 完成索引创建后, replica set secondaries 开始在后台创建索引操作。如果MongoDB在主节点上后台创建索引,那么之后从节点也会在后台创建索引。
在从节点上建立大索引的最好方式是以 standalone 模式重启一个从节点并建立索引。 索引建立完成后,重启为复制集成员,这样它可以同步跟上其他成员,然后以同样方式在下一个从节点上建立索引。当所有从节点都有新索引了,让主节点下台并作为单机实例重启,然后创建索引。
在从节点上建立索引的时间应该小于 oplog 时间窗口,这样从节点可以同步跟上主节点。
当在 “recovering” 模式的从节点上索引时,索引创建过程总是在前台执行,这样它们可以尽可能快的同步跟上。
参见 在复制集上创建索引 对从节点上创建索引过程有一个完整了解。
删除重复¶
MongoDB无法在一个有重复值的键上创建 唯一索引 。因此,如果希望强制创建唯一索引,您可以指定 dropDups 选项,这会让MongoDB在键的值第一次出现时建立索引,并删除随后所有重复值。
重要
就像在所有唯一索引中一样,如果一篇文档中不包含被索引键,MongoDB会为这篇文档在键上保存一个 “null” 值。
如果后续的文档 也不包含 被索引键,且您还设置了 {dropDups: true} 选项,那么MongoDB将会在创建索引时从集合中移除这些文档。如果您组合使用 dropDups 和 sparse 选项,那么索引只会包括那些在被索引键上有值的文档,而那些没有键的文档会保留在数据库中。
可以使用如下命令,在 accounts 集合的 username 键上建立一个唯一索引并去重:
db.accounts.ensureIndex( { username: 1 }, { unique: true, dropDups: true } )
警告
指定 { dropDups: true } 会导致数据从数据库中删除。使用时请慎重考虑。
默认地, dropDups 是 false 。
索引名字¶
一个索引的默认名字是每个被索引键和键的方向如1,-1的拼接。
例子
Issue the following command to create an index on item and quantity:
db.products.ensureIndex( { item: 1, quantity: -1 } )
这个索引的名字是: item_1_quantity_-1 。
您可以为索引指定一个名字,代替默认名字。
例子
Issue the following command to create an index on item and quantity and specify inventory as the index name:
db.products.ensureIndex( { item: 1, quantity: -1 } , { name: "inventory" } )
最终这个索引的名字会是 inventory 。
您可以使用 getIndexes() 方法来查看一个索引的名字。