`
eksliang
  • 浏览: 599049 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

MongoDB索引调优(2)——[十]

阅读更多

转载请出自出处:http://eksliang.iteye.com/blog/2178555

一、概述

      上一篇文档中也说明了,MongoDB的索引几乎与关系型数据库的索引一模一样,优化关系型数据库的技巧通用适合MongoDB,所有这里只讲MongoDB需要注意的地方

二、索引内嵌文档

    可以在嵌套文档的键上建立索引,方式与正常的键一样。如果有这样一个集合,如下所示:

db.emp.insert({
	"_id":"A001",
	"name":{
		"first":"Carey",
		"last":"Ickes"
	},
	"age":25
})

   现在我要在内嵌文档的first键上建立索引?如下所示

> db.emp.ensureIndex({"name.first":1})

      温馨提示:对嵌套文档本身“name”建立索引,与对嵌套文档的某个字段(name.first)建立索引是完全不相同的,对整个文档建立索引,只有在使用文档完整匹配时才会使用到这个索引,例如建立了这样一个索引db.emp.ensureIndex({"name":1}),那么只有使用db.emp.find({"name":{"first":"xxx","last":"xxx"}})这种完整匹配时才会使用到这个索引,使用db.emp.find({"name.first":"xxx"})是不会使用到该索引的。

 

三、索引数组

      MongoDB支持对数组建立索引,这样就可以高效的搜索数组中的特定元素。例如有一个博客文章集合,其中每个文档都表示一篇文章。每篇文章都有一个comments字段,这是一个数组,用来保存别人对这篇文章的评论信息。blog集合结构如下:

db.blog.insert({
	"_id":"B001",
	"title":"MongoDB查询",
	"comments":[
	  {"name":"ickes","score":3,"comment":"nice"},
	  {"name":"xl","score":4,"comment":"nice"},
	  {"name":"eksliang","score":5,"comment":"nice"},
	  {"name":"ickes","score":6,"comment":"nice"}
	]
})

   如果要找出comments.score大于5的所有文章,可以在comments.score键上面建立索引:

> db.blog.ensureIndex({"comments.score":1})

 

   对数组建立索引需要注意   

  • 对数组建立索引,实际上是对数组的每一个元素建立一个索引条目,如果一篇文章有20个评论,那么它就拥有20个索引条目。因此索引的代价比较单值索引的代价高。
  • 在数组上建立的索引并不包含任何位置信息:无法使用数组索引查找特定位置的数组元素,比如"comments.4".
  • 一个索引中数组字段最多只能有一个。这是为了避免在复合索引中索引条目爆炸性增长。
  • 对于某个索引的键,如果这个键在某个文档中是一个数组,那么这个索引就会标记为多键索引。可以从explain()的输出信息中看到一个索引是否为多键索引。如果是多键索引,那么"isMultikey"字段的值就会为true。索引只要被标记为多键索引,就无法再变成非多键索引,即使索引的键从文档中删除也不行。唯一的办法就是删除重建。

四、explain()和hint()

         explian()能够提供大量与查询相关的信息。对于速度比较慢的查询来说,这是最重要的诊断工具。通过查看explian()的输出信息,可以知道查询使用了那个索引,以及如果使用他的。对于任意查询来,都可以在最后添加一个explain()调用,但是调用explain()的时间必须是最后。

参考实例:

> db.users.find({"age":{"$gt":10}}).sort({"age":1}).limit(100).explain()
{
        "cursor" : "BtreeCursor age_1_name_1",
        "isMultiKey" : false,
        "n" : 100,
        "nscannedObjects" : 100,
        "nscanned" : 100,
        "nscannedObjectsAllPlans" : 100,
        "nscannedAllPlans" : 100,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "indexBounds" : {
                "age" : [
                        [
                                10,
                                Infinity
                        ]
                ],
                "name" : [
                        [
                                {
                                        "$minElement" : 1
                                },
                                {
                                        "$maxElement" : 1
                                }
                        ]
                ]
        },
        "server" : "localhost.localdomain:27017",
        "filterSet" : false
}

    explain()输出各个信息的含义如下表所示

 

"cursor" : "BtreeCursor age_1_name_1" 表示本次查询使用了索引,具体使用了age_1_name_1这个索引
"isMultiKey" : false 用于说明本次查询是否使用了多键索引
"n" : 100 本次查询返回的文档数量
"nscannedObjects" : 100 这是MongoDB使用索引指针去磁盘上查找文档的实际次数
"nscanned" : 100 如果有使用索引,那么这个数字就是检查过的索引个数,如果本次查询是全表扫描,那么这个数字就是检查过的文档个数
"scanAndOrder" : false MongoDB是否在内存中对结果集进行了排序
 "indexOnly" : false MongoDB是否只使用索引就可以完成本次查询("覆盖索引")
 "nYields" : 0 为了让写入请求能够顺利执行,本次查询暂停的次数。如果有写入请求需要处理,查询会周期性地释放他的锁,以便写人能够顺利执行。然而,在本次查询中没有写入请求,因为查询没有暂停过。
"millis" : 0 数据库执行本次查询所耗费的毫秒数。这个数字越小,说明查询效率越高
indexBounds:{...} 这个字段描述了索引的使用情况,给出了索引的遍历范围。因为本次查询只使用了age做为查询条件跟排序条件,没有指定第二个键,因此在name键上没有限制,数据库会把用户名介于负无穷("$minElement" : 1)到正无穷("$maxElement" : 1)之间进行搜索

hint()方法用于让MongoDB强制使用某个索引,或者查询使用了索引反而效率更低,这个时候可以使用hint()屏蔽索引让查询走全表扫描。

参考实例:强制本次查询使用{"name":1,"age":1}这个索引

> db.users.find({"age":{"$gt":10}}).sort({"age":1}).hint({"name":1,"age":1}).explain()

 参考实例:强制本次查询走全表扫描

> db.users.find({"age":{"$gt":10}}).sort({"age":1}).hint({"$natural":true}).explain()--使用{"$natural":1}--$natural 强制全表扫描

 

 

 五、MongoDB中低效率的操作符

"$where"和"$exists":这两个操作符,完全不能使用索引。

"$ne":通常来说取反的效率比较低。"$ne"查询可以使用索引,但并不是很有效。因为他必须查看所有的索引条目,而不是"$ne"指定的条目,这个时候他就不得不扫描整个索引。

"$not":有时候能够使用索引,但是他通常并不知道要如何使用索引。所以大多数情况"$not"会退化为全表扫描。

"$nin":这个操作符总是会全表扫描

 

六、OR查询

         MongoDB在一次查询中只能使用一个索引(至少我现在用的2.6是这样的),如果你在{"x":1}上有一个索引,在{"y":1}上也有一个索引,在{"x":1,"y":1}上执行查询时,MongoDB只会使用其中一个索引,而不是两个一起使用。"$or"是一个例外,"$or"可以对每个字句都使用索引,因为"$or"实际上是执行两次查询然后将结果合并。

         通常来说,使用or查询多次在合并结果,不如单次查询的效率高,对于单个字段,应该尽可能使用$in。

七、MongoDB的查询优化器

      MongoDB的查询优化器与其他数据库的稍微不同。基本来说,如果一个索引能够精确匹配一个查询,那么查询优化器就会使用这个索引,如果不能精确匹配,可能会有几个索引都适合你的查询。那MongoDB是怎样选择的呢?答:MongoDB的查询计划会将多个索引并行的去执行,最早返回100个结果的就是胜者,其他查询计划都会被终止。

      这个查询计划会被缓冲,接下来的这个查询都会使用他,下面几种情况会重新计划;

  1. 最初的计划评估之后集合发生了比较大的数据波动,查询优化器就会重新挑选可行的查询计划。
  2. 建立索引时。
  3. 每执行1000次查询之后,查询优化器就会重新评估查询计划

 

八、何时不应该使用索引

      提取较小的子数据集时,索引非常有效(所以才有了分页)。也有一些查询不使用索引会更快。结果集在原集合中所占的比例越大,查询效率越慢。因为使用索引需要进行两次查找:一次查找索引条目,一次根据索引指针去查找相应的文档。而全表扫描只需要进行一次查询。在最坏的情况,使用索引进行查找次数会是全表扫描的两倍。效率会明显比全表扫描低。

     可惜并没有一个严格的规则可以告诉我们,如果根据索引大小、文档大小来判断什么时候索引很有用,一般来说,如果查询需要返回集合内30%的文档(或者更多),那就应该测试全表扫描和走索引查询那个速度比较快。这个数字也会在2%~60%之间进行波动。

这个时候可以使用hint({"$natural":true})强制查询走全表扫描。

 

 

 

 

 

    

分享到:
评论

相关推荐

    MongoDB_two_MongoDB_

    2. 数据库与集合:介绍MongoDB中的数据库概念,如何创建和切换数据库,以及集合(类似于关系数据库中的表)的创建和操作。 3. 文档与插入:深入讲解文档的结构和组成,以及如何向集合中插入单个或多个文档。 4. ...

    Mongodb使用手册

    2. **数据存储**:详细解释MongoDB的数据存储机制,包括BSON(二进制JSON)格式,以及如何设计合适的文档结构以优化查询性能。 3. **查询语言**:深入解析MongoDB的查询语法,包括查询操作符、投影、排序、分页,...

    深入学习MongoDB及MongoDB权威指南(第2版)

    本篇文章将深入探讨MongoDB的核心概念、功能以及如何利用这两本书籍——《深入学习MongoDB》和《MongoDB权威指南(第2版)》来提升你的MongoDB技能。 首先,MongoDB的基础知识包括它的NoSQL数据模型。不同于传统的...

    mongodb-linux-x86_64-rhel62-4.4.1.tgz

    在学习MongoDB时,你需要掌握基本的CRUD操作、数据模型设计、索引使用、复制集的建立和维护、分片集群的搭建以及性能调优策略等。理解NoSQL数据库的核心理念,如灵活性、可伸缩性和高性能,将有助于你更好地应用...

    最新 MongoDB实战 典藏版

    - **监控与调优**:为了确保MongoDB的稳定运行,需要对其性能进行持续监控并根据需要进行调优。 - **备份与恢复**:制定合理的备份策略并在必要时进行数据恢复是MongoDB运维工作的重要组成部分。 综上所述,《最新...

    MongoDB Books

    最后,"大数据存储——MongoDB实战指南(迷你书)"可能会专注于MongoDB在大数据场景下的应用。这本书可能会讨论如何利用MongoDB处理大规模数据的挑战,如数据导入导出、性能调优、数据安全和合规性。它可能还会介绍...

    php-mongodb-redis手册

    3. MongoDB高级特性:如索引创建、聚合框架、地理空间索引等。 4. PHP Redis扩展的使用:安装、配置和基本操作命令的介绍。 5. Redis数据类型的应用:如何根据业务需求选择合适的数据类型,并进行操作。 6. Redis...

    720搜索——没有盗版,放心!

    5. **数据库技术**:可能采用了MySQL、MongoDB等数据库存储索引数据和用户信息,同时可能涉及SQL优化和NoSQL数据结构的选择。 6. **用户体验设计**:积分系统的存在,可能涉及到用户界面(UI)和用户体验(UX)设计...

    数据库知识了解——web数据库

    - **索引优化**:创建合适的数据索引,提高查询速度。 6. **Web数据库安全**: - **权限管理**:设置不同级别的用户权限,防止未授权访问。 - **加密存储**:敏感数据应加密存储,保护用户隐私。 - **SQL注入...

    2020-2021数据库课程设计——“英豪荟萃”网购平台.zip

    1. **数据库模型与设计**:在设计任何数据库之前,首先需要选择合适的数据库模型,如关系型数据库(如MySQL、Oracle)、非关系型数据库(如MongoDB、Cassandra)等。在这个网购平台中,关系型数据库可能更为适用,...

    数据库工程师知识点

    - 数据模型:理解并掌握三种主要的数据模型——关系型模型(如SQL)、层次模型和网络模型。 - 数据结构:了解B树、B+树、哈希表等数据结构及其在数据库中的应用。 - ACID特性:原子性(Atomicity)、一致性...

    陕西师范大学数据库考试题

    10. **数据库性能调优**:了解如何监控数据库性能,使用查询分析器找出性能瓶颈,并应用优化策略,如调整表分区、使用存储过程、合理设计索引等。 陕西师范大学的数据库考试可能会涵盖以上知识点的综合应用,考生需...

    大学经典数据库教程课件

    2. 数据模型:课程会深入讲解三种主要的数据模型——层次模型、网状模型和关系模型。其中,关系模型是最常见的,基于E-R(实体-关系)模型,使用表格来表示数据。 3. SQL语言:SQL(结构化查询语言)是用于管理和...

    软考数据库系统工程师04年至17年真题及答案

    同时,学习索引优化、查询优化和数据库性能调优策略。 4. **数据库安全与备份恢复**:掌握用户权限管理,数据库的备份策略(如完整备份、增量备份和差异备份),以及数据恢复技术,如日志恢复和前滚/后滚操作。 5....

    db基础

    2. **Sina App Engine架构——云计算时代的分布式Web服务解决方案.mht**:Sina App Engine可能是新浪公司提供的一个云计算平台,用于构建和运行分布式Web服务。这个文件可能探讨了如何在云环境中使用分布式数据库来...

    数据库原理PPT

    9. **性能优化**:数据库性能优化包括索引设计、查询优化、分区、缓存和数据库调优。索引可以加速查询,查询优化器选择最优执行计划,分区将大表分成小块,缓存提高数据访问速度,调优涉及参数调整和架构改进。 10....

    SQL数据库最新操作模块.rar

    2. **数据库设计**:理解数据库的概念模型,例如实体关系模型(ER模型),以及如何通过创建表来实现这些模型。了解主键、外键、唯一性约束和索引等数据库设计原则。 3. **SQL查询优化**:如何编写高效的SQL查询,...

    Java_Architect_Notes-John_H.rar_architect_java architect

    此外,事务处理、索引优化、查询性能调优也是必备技能。 5. **Web开发与框架**:深入理解HTTP协议,熟悉Servlet和JSP技术,掌握Spring Boot、Spring Cloud等主流Java Web框架。同时,需要了解MVC设计模式,以及...

    (互联网数据库)的大作业。网站从底层数据库,后端框架

    2. 数据库设计:包括概念设计(ER模型)、逻辑设计(表结构设计)和物理设计(索引、分区等)。良好的数据库设计能够提高查询效率,减少数据冗余,保证数据的一致性。 3. 数据库优化:涉及索引策略、查询优化、存储...

Global site tag (gtag.js) - Google Analytics