💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ### 创建1 000 000个文档的集合 ***** ``` for (i=0; i<1000000; i++) {  db.users.insert(         {              "i" : i,              "username" : "user"+i,              "age" : Math.floor(Math.random()\*120),              "created" : new Date()          }      );  } ``` ### 不建立索引查询 ***** 执行查询语句 ```MongoDB db.users.find({username: "user101"}).explain() ``` 注意:`explain()`函数查看MongoDB在执行查询的过程中所做的事情; 这个集合中的每个文档都被扫描过了。也就是说,为了完成这个查询,MongoDB查看了每一个文档中的每一个字段. 为了优化查询,将查询结果限制为1,这样MongoDB在找到一个文档之后就会停止了: ``` db.users.find({username: "user101"}).limit(1).explain() ``` >现在,所扫描的文档数量极大地减少了,而且整个查询几乎是瞬间完成的。但是,这个方案是不现实的:如果要查找的是user999999呢?我们仍然不得不遍历整个集合,而且,随着用户的增加,查询会越来越慢。 ### 建立单个字段索引 ***** 给`username`字段建立正序索引 ``` > db.users.ensureIndex({"username" : 1}) //倒序索引 > db.users.ensureIndex({"username" : -1}) ``` 执行查询语句: ``` > db.users.find({"username" : "user101"}).explain() ``` 可以看到,这个查询现在几乎是瞬间完成的(甚至可以更好),而且对于任意username的查询,所耗费的时间基本一致。 ### 复合索引 ***** 在下面的排序里,"username"上的索引没什么作用: ``` db.users.find().sort({"age" : 1, "username" : 1}) ``` 先根据"age"排序再根据"username"排序,所以"username"在这里发挥的作用并不大。为了优化这个排序,可能需要在"age"和"username"上建立索引: ``` > db.users.ensureIndex({"age" : 1, "username" : 1}) ``` 这样就建立了一个**复合索引** 如果使用{"age" : 1, "username" : 1}建立索引,索引大致会是这个样子: ``` [0, "user100309"] -> 0x0c965148 [0, "user100334"] -> 0xf51f818e [0, "user100479"] -> 0x00fd7934 ... [0, "user99985" ] -> 0xd246648f [1, "user100156"] -> 0xf78d5bdd [1, "user100187"] -> 0x68ab28bd [1, "user100192"] -> 0x5c7fb621 ... [1, "user999920"] -> 0x67ded4b7 [2, "user100141"] -> 0x3996dd46 [2, "user100149"] -> 0xfce68412 [2, "user100223"] -> 0x91106e23 ... ``` MongoDB对这个索引的使用方式取决于查询的类型。下面是三种主要的方式: 1.查找单个值 ``` //MongoDB能够直接定位到正确的年龄,而且不需要对结果进行排序 > db.users.find({"age" : 21}).sort({"username" : -1}) ``` 2. 多值查询 ``` //查找到多个值相匹配的文档(在本例中,年龄必须介于21到30之间)。MongoDB会使用索引中的第一个键"age"得到匹配的文档 > db.users.find({"age" : {"$gte" : 21, "$lte" : 30}}) ``` 匹配的文档如下: ``` [21, "user100000"] -> 0x37555a81 [21, "user100069"] -> 0x6951d16f [21, "user1001"] -> 0x9a1f5e0c [21, "user100253"] -> 0xd54bd959 [21, "user100409"] -> 0x824fef6c [21, "user100469"] -> 0x5fba778b ... [30, "user999775"] -> 0x45182d8c [30, "user999850"] -> 0x1df279e9 [30, "user999936"] -> 0x525caa57 ``` 多值查询: ``` //与上一个类似,只是这次需要对查询结果进行排序。跟之前一样 > db.users.find({"age" : {"$gte" : 21, "$lte" : 30}}).sort({"username":1}) ``` 然而,使用这个索引得到的结果集中"username"是无序的,而查询要求结果以"username"升序排列,所以MongoDB需要先在内存中对结果进行排序,然后才能返回。因此,这个查询通常不如上一个高效。 >注意:如果结果集的大小超过32 MB,MongoDB就会出错,拒绝对如此多的数据进行排序: #### 选择键的方向 1. 如果应用程序同时需要按照{"age" : 1, "username" : 1}优化排序,我们还需要创建一个这个方向上的索引。至于索引使用的方向,与排序方向相同。 2. 如果有一个基于{"age" : -1}的排序和一个基于{"age" : 1}的索引,MongoDB会在使用索引时进行优化,就如同存在一个{"age" : -1}索引一样。不要创建两个这样的索引。 3. 只有在基于多键排序时,方向才变得重要 #### 使用覆盖索引(covered index) ` ` ### 多键索引 ***** MongoDB使用`多键索引`来索引存储在数组中的内容.如果您对保存数组值的字段建立索引,则MongoDB将为数组的*每个*元素创建单独的索引条目,这些多键索引允许查询通过匹配数组的一个或多个元素来选择包含数组的文档. 如果索引字段包含数组值,MongoDB会自动确定是否创建多键索引. 您无需显式指定多键类型. ### 空间索引 ***** 为了支持对地理空间坐标数据的高效查询,MongoDB提供了两个特殊的索引:返回结果时使用平面几何的[2d索引](https://s0docs0mongodb0com.icopy.site/manual/core/2d/)和使用球面几何返回结果的[2dsphere索引](https://s0docs0mongodb0com.icopy.site/manual/core/2dsphere/). ### text索引 ***** MongoDB提供了一种`text`索引类型,该类型支持在集合中搜索字符串内容. 这些文本索引不存储特定于语言的*停用*词(例如" the"," a"," or"),并且在集合中*词干*仅存储根词. ### 散列索引(Hashed Indexes) ***** 为了支持[基于散列的分片](https://s0docs0mongodb0com.icopy.site/manual/core/hashed-sharding/#sharding-hashed-sharding),MongoDB提供了一种[散列索引](https://s0docs0mongodb0com.icopy.site/manual/core/index-hashed/)类型,该索引类型对字段值的散列进行索引. 这些索引在其范围内具有更随机的值分布,但*仅*支持相等匹配,而不能支持基于范围的查询. ### 唯一索引 ***** 索引的[unique](https://s0docs0mongodb0com.icopy.site/manual/core/index-unique/)属性使MongoDB拒绝索引字段的重复值. 除了唯一约束之外,唯一索引在功能上可以与其他MongoDB索引互换. ### 部分索引 ***** [部分索引](https://s0docs0mongodb0com.icopy.site/manual/core/index-partial/)仅索引集合中符合指定过滤器表达式的文档. 通过索引集合中文档的子集,部分索引具有较低的存储需求,并降低了索引创建和维护的性能成本. 部分索引提供了稀疏索引功能的超集,应优先于稀疏索引. ### 稀疏索引 ***** 索引的[稀疏](https://s0docs0mongodb0com.icopy.site/manual/core/index-sparse/)属性可确保索引仅包含具有索引字段的文档的条目. 索引会跳过*没有*索引字段的文档. 您可以将`稀疏索引`选项与`唯一索引`选项`结合使用`,以防止插入索引字段具有重复值的文档,并跳过缺少索引字段的索引文档. ### TTL 索引 ***** [TTL索引](https://s0docs0mongodb0com.icopy.site/manual/core/index-ttl/)是MongoDB可以使用的特殊索引,可以`在一定时间后自动从集合中删除文档`. 对于某些类型的信息(例如机器生成的事件数据,日志和会话信息),它们仅需要在数据库中保留有限的时间,这是理想的选择. ### 索引限制 ***** 内存RAM使用: ``` 由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。 如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。 ``` 最大范围 ``` * 集合中索引不能超过64个 * 索引名的长度不能超过125个字符 * 一个复合索引最多可以有31个字段 ``` ### **索引最左前缀原则** *****