MongoDB不专业指北(十二):索引操作(下)

432 阅读2分钟

前言

上一篇介绍了 MongoDB 的索引基本操作,包括了索引查看、创建、删除,具体可以参考:MongoDB不专业指北(十一):索引操作(上)。本篇接下来介绍MongoDB索引的其他操作。

稀疏索引(Sparse Index)

稀疏索引是只对有该字段的文档建立索引,对于没有该字段的文档会当做是 null 处理。拿前面的员工举例,我们给员工增加一个手机号字段 mobile,然后假设某些员工没有手机号且员工之间的手机号不能相同。

db.employees.update({name: 'Jenny'}, {$set: {mobile: '13800138000'}});
db.employees.update({name: '岛上码农'}, {$set: {mobile: '13800138001'}});
db.employees.update({name: 'Amy'}, {$set: {mobile: '13800138002'}});

使用的数据集如下:

{
	"_id" : ObjectId("60d734f0d8079507891982a8"),
	"name" : "岛上码农",
	"dept" : "研发部",
	"languages" : [
		"Dart",
		"Java",
		"Javascript"
	],
	"age" : 30,
	"totalExp" : 10,
	"mobile" : "13800138001"
}
{
	"_id" : ObjectId("60d734f0d8079507891982a9"),
	"name" : "Amy",
	"dept" : "研发部",
	"languages" : [
		"Java",
		"Go"
	],
	"age" : 35,
	"totalExp" : 11,
	"mobile" : "13800138002"
}
{
	"_id" : ObjectId("60d734f0d8079507891982aa"),
	"name" : "Bob",
	"dept" : "测试部",
	"languages" : [
		"Java",
		"Javascript"
	],
	"age" : 36,
	"totalExp" : 14
}
{
	"_id" : ObjectId("60d734f0d8079507891982ab"),
	"name" : "Cathy",
	"dept" : "研发部",
	"languages" : [
		"Javascript",
		"Python"
	],
	"age" : 31,
	"totalExp" : 4
}
{
	"_id" : ObjectId("60d734f0d8079507891982ac"),
	"name" : "Mike",
	"dept" : "测试部",
	"languages" : [
		"Java",
		"Python",
		"Go"
	],
	"age" : 26,
	"totalExp" : 3
}
{
	"_id" : ObjectId("60d734f0d8079507891982ad"),
	"name" : "Jenny",
	"dept" : "研发部",
	"languages" : [
		"Java",
		"Javascipt",
		"Dart"
	],
	"age" : 26,
	"totalExp" : 3,
	"mobile" : "13800138000"
}

这个时候,如果我们为了保证手机号的唯一性,直接创建手机号的唯一索引。

db.employees.createIndex({mobile: 1}, {unique: true});

这个时候会提示由于存在多个文档的 mobilenull,无法保证唯一性导致创建失败。此时可以利用稀疏索引解决这个问题。

db.employees.createIndex({mobile: 1}, {unique: true, sparse: true});

通过 getIndexes 可以看到创建后的稀疏索引:

{
		"v" : 2,
		"unique" : true,
		"key" : {
			"mobile" : 1
		},
		"name" : "mobile_1",
		"sparse" : true
	}

稀疏索引相比普通索引更为紧凑,如果一个数据集只有不到10%的文档指定了该字段,可以创建更小存储空间的索引,而且占用的内存资源更小,例如下面的查询:

db.employees.find({mobile: '13800138000'});

部分索引(Partial Indexes)

部分索引意思是可以对数据集的部分满足条件的文档建立索引,而不是全部数据。下面只对超过35岁的员工建立索引(35岁对程序员是道槛,你懂的)。

db.employees.createIndex(
	{age: 1},
  {partialFilterExpression: {age: {$gt: 35}}}
);

获取对应的索引如下:

{
		"v" : 2,
		"key" : {
			"age" : 1
		},
		"name" : "age_1",
		"partialFilterExpression" : {
			"age" : {
				"$gt" : 35
			}
		}
	}

对于说经常要对满足某些条件的查询来说,建立部分索引相比而言索引存储空间会更小。部分索引和稀疏索引是有不同的,稀疏索引是基于字段有没有来建立,而部分索引是基于过滤条件。而且,部分索引可以实现稀疏索引,通过判断字段是否存在的过滤条件即可完成。

db.employees.createIndex(
	{mobile: 1},
  {partialFilterExpression: {mobile: {$exists: true}}}
);

需要注意的是稀疏索引和部分索引对同一个字段不可同时存在。同时,当一个字段有索引时,也不可以建立部分索引。

复合索引

可以在创建索引的时候指定多个字段建立复合索引。这有点类似 SQL 的联合索引。

db.employees.createIndex({name: 1, age: -1});

需要注意的是,复合索引和联合索引类似,也存在次序的问题,当查询条件是 namenameage 的时候能够命中索引,而单独的 age 条件查询是无法使用索引的。同样的对于排序来说,也是需要匹配建立索引的次序。

独立索引

独立索引在创建索引的属性增加{unique: true}即可。

db.employees.createIndex({name: 1}, {unique: true});

如果数据集存在相同属性的字段时,建立索引会失败,包括未指定该字段的文档超过2个以上时。

总结

可以看到,MongoDB 的索引除了具备 SQL 常见的索引外,还支持了稀疏索引和部分索引,这应该也是 MongoDB 改进了关系型数据库的一些缺陷得到的改进。实际应用中可以根据需要来选择如何使用索引。