首页 > 运维 > linux运维 > 正文

玩转mongoDB(六):索引,速度的引领(普通索引篇)

爱谁谁
发布: 2025-07-16 09:18:45
原创
802人浏览过

数据库索引的概念类似于书籍的索引,拥有索引后无需翻阅整本书,数据库可以直接在索引中进行查找,找到条目后即可跳转到目标文档的位置,这可以显著提高查询速度,通常是几个数量级的提升。

一、创建索引

在person集合的age字段上创建索引,并比较创建索引前后查询语句的性能差异。

创建索引的命令为:db.person.ensureIndex({"age":1})。这里我们使用了ensureIndex在age字段上建立索引。值为“1”表示按照age进行升序排列,而“-1”表示按照age进行降序排列。

没有索引时的查询性能:

玩转mongoDB(六):索引,速度的引领(普通索引篇)

有索引时的查询性能:

玩转mongoDB(六):索引,速度的引领(普通索引篇)

我们主要关注几个关键参数(参数说明请参考上一篇文章):

  • executionTimeMillis(这次查询的总耗时):无索引时耗时962毫秒;有索引时耗时143毫秒。
  • totalDocsExamined(文档扫描条目):无索引时为200万条;有索引时为2000条。
  • stage(查询的类型):无索引时为COLLSCAN(全表扫描);有索引时为FETCH+IXSCAN(索引扫描+根据索引检索指定文档)。
  • executionStages.executionTimeMillisEstimate(检索文档获得数据的耗时):无索引时耗时910毫秒;有索引时耗时0毫秒。

建立索引后,该查询的整体速度提高了一个数量级(1个数量级即10倍)。根据查询语句的不同,索引可以使速度提高几个数量级。

二、复合索引

在多个字段上建立的索引称为复合索引。有时我们的查询不是单条件的,可能是多条件的,例如查找年龄在20至30岁之间且名字为‘ryan1’的同学,我们可以建立“age”和“name”的联合索引来加速查询。

为了演示索引的效果,我们重新生成并插入200万个文档的集合。

我们可以使用hint()方法来强制查询使用特定索引。

来看一下,当查询条件是多个时,复合索引相比单键索引的优势。

使用单键索引:

db.person.find({"age":{"$gte":20,"$lte":30},"name":"ryan1"}).hint({"age":1}).explain("executionStats");
登录后复制

结果如下:

卡奥斯智能交互引擎
卡奥斯智能交互引擎

聚焦工业领域的AI搜索引擎工具

卡奥斯智能交互引擎 36
查看详情 卡奥斯智能交互引擎
{    ...    "executionStats" : {        "executionSuccess" : true,        "nReturned" : 2000,        "executionTimeMillis" : 2031,        "totalKeysExamined" : 2000000,        "totalDocsExamined" : 2000000,    ...    }
登录后复制

使用复合索引:

db.person.find({"age":{"$gte":20,"$lte":30},"name":"ryan1"}).hint({"age":1,"name":1}).explain("executionStats");
登录后复制

结果如下:

{    ...    "executionStats" : {        "executionSuccess" : true,        "nReturned" : 2000,        "executionTimeMillis" : 8,        "totalKeysExamined" : 2010,        "totalDocsExamined" : 2000,    ...}
登录后复制

从executionTimeMillis的值上可以看出区别。单键索引耗费了2031毫秒,而复合索引仅用了8毫秒。因此,对于多条件的查询语句,建立正确的复合索引是非常重要的。

下面我们再介绍一种复合索引的重要应用场景:对一个字段排序并只获取前100个结果(实际项目中常见这种情况)。对于这种情况,索引应该这样建立{"sortKey":1,"queryCriteria":1},排序的字段应放在复合索引的第一位。

排序字段未放在复合索引的第一位:

db.person.find({"age":{"$gte":21.0,"$lte":30.0}}).sort({"name":1}).limit(100).hint({"age":1,"name":1}).explain("executionStats");
登录后复制

结果如下:

{    ...        "executionStats" : {        "executionSuccess" : true,        "nReturned" : 100,        "executionTimeMillis" : 6882,        "totalKeysExamined" : 1800000,        "totalDocsExamined" : 1800000,    ...  }
登录后复制

排序字段放在复合索引的第一位:

db.person.find({"age":{"$gte":21.0,"$lte":30.0}}).sort({"name":1}).limit(100).hint({"name":1,"age":1}).explain("executionStats");
登录后复制

结果如下:

{    ...    "executionStats" : {        "executionSuccess" : true,        "nReturned" : 100,        "executionTimeMillis" : 3,        "totalKeysExamined" : 2100,        "totalDocsExamined" : 2100,    ...}
登录后复制

从上面的结果可以看出,基于排序字段的索引效果非常好。

分析:第一种索引,需要找到所有符合复合查询条件的值(依据索引,字段和文档可以快速找到),但找到后,需要在内存中对文档进行排序,这个步骤消耗了大量时间。第二种索引效果非常好,因为无需在内存中对大量数据进行排序。然而,MongoDB仍需扫描整个索引以找到所有文档。因此,如果对查询结果的范围进行了限制,那么MongoDB在几次匹配后就可以停止扫描索引,在这种情况下,将排序字段放在第一位是一个非常好的策略。

三、唯一索引

唯一索引可以确保集合中每个文档的指定字段具有唯一值。如果想保证不同文档的“name”字段值不同,可以在“name”字段上创建唯一索引。

db.person.ensureIndex({"name":1},{"unique":true});
登录后复制

然后使用db.person.getIndexes()命令查看目前person集合的所有索引。

玩转mongoDB(六):索引,速度的引领(普通索引篇)

也可以创建复合的唯一索引。创建复合唯一索引时,单个字段的值可以相同,但所有字段的组合值必须是唯一的。

db.person.ensureIndex({"name":1,"age":1},{"unique":true}); 
登录后复制

然后使用db.person.getIndexes()命令查看目前person集合的所有索引。

玩转mongoDB(六):索引,速度的引领(普通索引篇)

四、稀疏索引

唯一索引会将null视为值,因此无法将多个缺少唯一索引中字段的文档插入到集合中。然而,在某些情况下,你可能希望唯一索引只对包含相应字段的文档生效。这时可以使用MongoDB中的稀疏索引。该索引与关系型数据库中的稀疏索引完全不同。MongoDB中的稀疏索引只是不需要将每个文档都作为索引条目。

例如,如果有一个可选的mobilephone字段,但如果提供了该字段,其值必须是唯一的:

db.person.ensureIndex({"mobilephone":1},{"unique":true,"sparse":true});
登录后复制

稀疏索引不必是唯一的。只要去掉unique选项,就可以创建一个非唯一的稀疏索引。

玩转mongoDB(六):索引,速度的引领(普通索引篇)

五、索引管理

如第一小节所述,可以使用ensureIndex方法创建新的索引,也可以使用createIndex方法。

创建索引后,可以使用getIndexes()方法查看给定集合上的所有索引信息。

db.person.getIndexes();//获取集合的索引信息
登录后复制

结果如下:

[    {        "v" : 1,        "key" : {            "_id" : 1        },        "name" : "_id_",        "ns" : "personmap.person"    },    {        "v" : 1,        "unique" : true,        "key" : {            "name" : 1.0        },        "name" : "name_1",        "ns" : "personmap.person"    },    {        "v" : 1,        "unique" : true,        "key" : {            "name" : 1.0,            "age" : 1.0        },        "name" : "name_1_age_1",        "ns" : "personmap.person"    },    {        "v" : 1,        "unique" : true,        "key" : {            "mobilephone" : 1.0        },        "name" : "mobilephone_1",        "ns" : "personmap.person",        "sparse" : true    }]
登录后复制

随着业务的不断变化,你可能会发现数据或查询已经发生了改变,原来的索引可能不再那么有效。这时可以使用dropIndex()方法删除不需要的索引:

db.person.dropIndex("name_1");//删除索引名为name_1的索引。
登录后复制

以上就是玩转mongoDB(六):索引,速度的引领(普通索引篇)的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号