资讯专栏INFORMATION COLUMN

MongoDB指南---13、索引类型、索引管理

Enlightenment / 3656人阅读

摘要:复合唯一索引也可以创建复合的唯一索引。中的稀疏索引与关系型数据库中的稀疏索引是完全不同的概念。但是这里不会指明索引是否是多键索引。上一篇文章指南使用和何时不应该使用索引下一篇文章指南特殊的索引和集合固定集合索引全文本索引

上一篇文章:MongoDB指南---12、使用explain()和hint()、何时不应该使用索引
下一篇文章:MongoDB指南---14、特殊的索引和集合:固定集合、TTL索引、全文本索引

创建索引时可以指定一些选项,使用不同选项建立的索引会有不同的行为。接下来的小节会介绍常见的索引变种,更高级的索引类型和特殊选项会在下一章介绍。

唯一索引

唯一索引可以确保集合的每一个文档的指定键都有唯一值。例如,如果想保证同不文档的"username"键拥有不同的值,创建一个唯一索引就好了:

> db.users.ensureIndex({"username" : 1}, {"unique" : true})

如果试图向上面的集合中插入如下文档:

> db.users.insert({username: "bob"})
> db.users.insert({username: "bob"})
E11000 duplicate key error index: test.users.$username_1 dup key: { : "bob" }

如果检查这个集合,会发现只有第一个"bob"被保存进来了。发现有重复的键时抛出异常会影响效率,所以可以使用唯一索引来应对偶尔可能会出现的键重复问题,而不是在运行时对重复的键进行过滤。
有一个唯一索引可能你已经比较熟悉了,就是"_id"索引,这个索引会在创建集合时自动创建。这就是一个正常的唯一索引(但它不能被删除,而其他唯一索引是可以删除的)。

如果一个文档没有对应的键,索引会将其作为null存储。所以,如果对某个键建立了唯一索引,但插入了多个缺少该索引键的文档,由于集合已经存在一个该索引键的值为null的文档而导致插入失败。5.4.2节会详细介绍相关内容。

有些情况下,一个值可能无法被索引。索引储桶(index bucket)的大小是有限制的,如果某个索引条目超出了它的限制,那么这个条目就不会包含在索引里。这样会造成一些困惑,因为使用这个索引进行查询时会有一个文档凭空消失不见了。所有的字段都必须小于1024字节,才能包含到索引里。如果一个文档的字段由于太大不能包含在索引里,MongoDB不会返回任何错误或者警告。也就是说,超出8 KB大小的键不会受到唯一索引的约束:可以插入多个同样的8 KB长的字符串。

1. 复合唯一索引

也可以创建复合的唯一索引。创建复合唯一索引时,单个键的值可以相同,但所有键的组合值必须是唯一的。
例如,如果有一个{"username" : 1, "age" : 1}上的唯一索引,下面的插入是合法的:

db.users.insert({"username" : "bob"})
db.users.insert({"username" : "bob", "age" : 23})
db.users.insert({"username" : "fred", "age" : 23})
然而,如果试图再次插入这三个文档中的任意一个,都会导致键重复异常。
GirdFS是MongoDB中存储大文件的标准方式(详见6.5节),其中就用到了复合唯一索引。存储文件内容的集合有一个{"files_id" : 1, "n" : 1}上的复合唯一索引,因此文档的某一部分看起来可能会是下面这个样子:
{"files_id" : ObjectId("4b23c3ca7525f35f94b60a2d"), "n" : 1}
{"files_id" : ObjectId("4b23c3ca7525f35f94b60a2d"), "n" : 2}
{"files_id" : ObjectId("4b23c3ca7525f35f94b60a2d"), "n" : 3}
{"files_id" : ObjectId("4b23c3ca7525f35f94b60a2d"), "n" : 4}
注意,所有"files_id"的值都相同,但是"n"的值不同。
2. 去除重复

在已有的集合上创建唯一索引时可能会失败,因为集合中可能已经存在重复值了:

> db.users.ensureIndex({"age" : 1}, {"unique" : true})
E11000 duplicate key error index: test.users.$age_1 dup key: { : 12 }

通常需要先对已有的数据进行处理(可以使用聚合框架),找出重复的数据,想办法处理。
在极少数情况下,可能希望直接删除重复的值。创建索引时使用"dropDups"选项,如果遇到重复的值,第一个会被保留,之后的重复文档都会被删除。

> db.people.ensureIndex({"username" : 1}, {"unique" : true, "dropDups" : true})

"dropDups"会强制性建立唯一索引,但是这个方式太粗暴了:你无法控制哪些文档被保留哪些文档被删除(如果有文档被删除的话,MongoDB也不会给出提示说哪些文档被删除了)。对于比较重要的数据,千万不要使用"dropDups"。

 稀疏索引

前面的小节已经讲过,唯一索引会把null看做值,所以无法将多个缺少唯一索引中的键的文档插入到集合中。然而,在有些情况下,你可能希望唯一索引只对包含相应键的文档生效。如果有一个可能存在也可能不存在的字段,但是当它存在时,它必须是唯一的,这时就可以将unique和sparse选项组合在一起使用。

MongoDB中的稀疏索引(sparse index)与关系型数据库中的稀疏索引是完全不同的概念。基本上来说,MongoDB中的稀疏索引只是不需要将每个文档都作为索引条目。

使用sparse选项就可以创建稀疏索引。例如,如果有一个可选的email地址字段,但是,如果提供了这个字段,那么它的值必须是唯一的:

> db.ensureIndex({"email" : 1}, {"unique" : true, "sparse" : true})

稀疏索引不必是唯一的。只要去掉unique选项,就可以创建一个非唯一的稀疏索引。
根据是否使用稀疏索引,同一个查询的返回结果可能会不同。假如有这样一个集合,其中的大部分文档都有一个"x"字段,但是有些没有:

> db.foo.find()
{ "_id" : 0 }
{ "_id" : 1, "x" : 1 }
{ "_id" : 2, "x" : 2 }
{ "_id" : 3, "x" : 3 }

当在"x"上执行查询时,它会返回相匹配的文档:

> db.foo.find({"x" : {"$ne" : 2}})
{ "_id" : 0 }
{ "_id" : 1, "x" : 1 }
{ "_id" : 3, "x" : 3 }

如果在"x"上创建一个稀疏索引,"_id"为0的文档就不会包含在索引中。如果再次在"x"上查询,MongoDB就会使用这个稀疏索引,{"_id" : 0}的这个文档就不会被返回了:

> db.foo.find({"x" : {"$ne" : 2}})
{ "_id" : 1, "x" : 1 }
{ "_id" : 3, "x" : 3 }

如果需要得到那些不包含"x"字段的文档,可以使用hint()强制进行全表扫描。

索引管理

如前面的小节所述,可以使用ensuerIndex函数创建新的索引。对于一个集合,每个索引只需要创建一次。如果重复创建相同的索引,是没有任何作用的。
所有的数据库索引信息都存储在system.indexes集合中。这是一个保留集合,不能在其中插入或者删除文档。只能通过ensureIndex或者dropIndexes对其进行操作。
创建一个索引之后,就可以在system.indexes中看到它的元信息。可以执行db.collectionName.getIndexes()来查看给定集合上的所有索引信息:

> db.foo.getIndexes()
[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "ns" : "test.foo",
        "name" : "_id_"
    },
    {
        "v" : 1,
        "key" : {
            "y" : 1
        },
        "ns" : "test.foo",
        "name" : "y_1"
    },
    {
        "v" : 1,
        "key" : {
            "x" : 1,
            "y" : 1
        },
        "ns" : "test.foo",
        "name" : "x_1_y_1"
    }
]

这里面最重要的字段是"key"和"name"。这里的键可以用在hint、max、min以及其他所有需要指定索引的地方。在这里,索引的顺序很重要:{"x" : 1, "y" : 1}上的索引与{"y" : 1, "x" : 1}上的索引不同。对于很多的索引操作(比如dropIndex),这里的索引名称都可以被当作标识符使用。但是这里不会指明索引是否是多键索引。
"v"字段只在内部使用,用于标识索引版本。如果你的索引不包含"v" : 1这样的字段,说明你的索引是以一种效率比较低的旧方式存储的。将MongoDB升级到至少2.0版本,删除并重建这些索引,就可以把索引的存储方式升级到新的格式了。

 标识索引

集合中的每一个索引都有一个名称,用于唯一标识这个索引,也可以用于服务器端来删除或者操作索引。索引名称的默认形式是key name1_dir1_keyname2_dir2_..._keynameN_dirN,其中keynameX是索引的键,dirX是索引的方向(1或者-1)。如果索引中包含两个以上的键,这种命名方式就显得比较笨重了,好在可以在ensureIndex中指定索引的名称:

> db.foo.ensureIndex({"a" : 1, "b" : 1, "c" : 1, ..., "z" : 1},
... {"name" : "alphabet"})

索引名称的长度是有限制的,所以新建复杂索引时可能需要自定义索引名称。调用getLastError就可以知道索引是否成功创建,或者失败的原因。

 修改索引

随着应用不断增长变化,你会发现数据或者查询已经发生了改变,原来的索引也不那么好用了。这时可以使用dropIndex命令删除不再需要的索引:

> db.people.dropIndex("x_1_y_1")
{ "nIndexesWas" : 3, "ok" : 1 }

用索引描述信息里"name"字段的值来指定需要删除的索引。
新建索引是一件既费时又浪费资源的事情。默认情况下,MongoDB会尽可能快地创建索引,阻塞所有对数据库的读请求和写请求,一直到索引创建完成。如果希望数据库在创建索引的同时仍然能够处理读写请求,可以在创建索引时指定background选项。这样在创建索引时,如果有新的数据库请求需要处理,创建索引的过程就会暂停一下,但是仍然会对应用程序性能有比较大的影响。后台创建索引比前台创建索引慢得多。
在已有的文档上创建索引会比新创建索引再插入文档快一点。

上一篇文章:MongoDB指南---12、使用explain()和hint()、何时不应该使用索引
下一篇文章:MongoDB指南---14、特殊的索引和集合:固定集合、TTL索引、全文本索引

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/19578.html

相关文章

  • MongoDB指南---13索引类型索引管理

    摘要:复合唯一索引也可以创建复合的唯一索引。中的稀疏索引与关系型数据库中的稀疏索引是完全不同的概念。但是这里不会指明索引是否是多键索引。上一篇文章指南使用和何时不应该使用索引下一篇文章指南特殊的索引和集合固定集合索引全文本索引 上一篇文章:MongoDB指南---12、使用explain()和hint()、何时不应该使用索引下一篇文章:MongoDB指南---14、特殊的索引和集合:固定集合...

    seanHai 评论0 收藏0
  • MongoDB指南---12、使用explain()和hint()、何时不应该使用索引

    摘要:表示本次查询使用了索引,具体来说,是使用了和上的索引,。建立索引时,或者是每执行次查询之后,查询优化器都会重新评估查询计划。上一篇文章指南使用复合索引操作符如何使用索引索引对象和数组索引基数下一篇文章指南索引类型 上一篇文章:MongoDB指南---11、使用复合索引、$操作符如何使用索引、索引对象和数组、索引基数下一篇文章:MongoDB指南---13、索引类型 使用explain...

    LiangJ 评论0 收藏0
  • MongoDB指南---12、使用explain()和hint()、何时不应该使用索引

    摘要:表示本次查询使用了索引,具体来说,是使用了和上的索引,。建立索引时,或者是每执行次查询之后,查询优化器都会重新评估查询计划。上一篇文章指南使用复合索引操作符如何使用索引索引对象和数组索引基数下一篇文章指南索引类型 上一篇文章:MongoDB指南---11、使用复合索引、$操作符如何使用索引、索引对象和数组、索引基数下一篇文章:MongoDB指南---13、索引类型 使用explain...

    DTeam 评论0 收藏0
  • MongoDB指南---14、特殊的索引和集合:固定集合、TTL索引、全文本索引

    摘要:固定集合不能被分片。为固定集合指定文档数量限制时,必须同时指定固定集合的大小。没有索引的集合默认情况下,每个集合都有一个索引。 上一篇文章:MongoDB指南---13、索引类型、索引管理下一篇文章:MongoDB指南---15、特殊的索引和集合:地理空间索引、使用GridFS存储文件 本章介绍MongoDB中一些特殊的集合和索引类型,包括: 用于类队列数据的固定集合(capped...

    cikenerd 评论0 收藏0
  • MongoDB指南---14、特殊的索引和集合:固定集合、TTL索引、全文本索引

    摘要:固定集合不能被分片。为固定集合指定文档数量限制时,必须同时指定固定集合的大小。没有索引的集合默认情况下,每个集合都有一个索引。 上一篇文章:MongoDB指南---13、索引类型、索引管理下一篇文章:MongoDB指南---15、特殊的索引和集合:地理空间索引、使用GridFS存储文件 本章介绍MongoDB中一些特殊的集合和索引类型,包括: 用于类队列数据的固定集合(capped...

    QLQ 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<