-背景:

鉴于我们使用mongo作为数据库,期间少不了需要添加索引和对业务表进行设计。因此以下我对mongo索引及表设计原则做了一些分享。希望对大家有用,如有错误还望指正~

MongDB的索引类型简介:

  -单键索引、复合索引、多键索引、地理空间索引、全文本索引和哈希索引

  1,单建索引 

    db.table.createIndex({"user_id":1})

    1:升序 -1:降序

    使用说明:只要查询中包含user_id即可使用索引 无论是在find条件中 还是在sort中 1,-1都会使用

  2,复合索引

    db.table.createIndex({"user_id":1,"name":-1})

    使用说明:使用上述索引查询中sort中只有当条件是{"user_id":1,"name":-1} 和{"user_id":-1,"name":1},{"user_id":1 or -1}的时候才会使用索引

    find中只要包含user_id才会使用,不能够创建基于哈希索引类型的复合索引 ,任意复合索引字段不能超过31个

  3,多键索引

    针对value是[]类型的mongo会自动建立多键索引,

    db.table.createIndex( { "stock": 1 }

    {
_id: 1,
item: "abc",
stock: [1,4,5,6]
}

    当文档如下json所示的结构时可以建立内嵌文档索引:

    db.table.createIndex( { "stock.size": 1, "stock.quantity": 1 } )

    {
_id: 1,
item: "abc",
stock: [
{ size: "S", color: "red", quantity: 25 },
{ size: "S", color: "blue", quantity: 10 },
{ size: "M", color: "blue", quantity: 50 }
]
}

  

    使用说明:对于一个复合多键索引,每个索引最多可以包含一个数组。

  4,地理空间索引

    2dsphere 允许使用GeoJSON格式(http://www.geojson.org)指定点、线和多边形。

    创建一个地理空间索引:

    db.world.createIndex({"loc": "2dsphere"})

    可以使用多种不同的地理空间查询:交集(intersection)、包含(within)以及接近(nearness)。查询时,需要将希望查找的内容指定为形如 {"$geometry":geoJsonDesc}

     的 GeoJSON 对象。

    另外还有一个2d类型类似更趋于平面化数据的处理这里不做过多介绍

  5,全文索引

    全文索引用于在文档中搜索文本,我们也可以使用正则表达式来查询字符串,但是当文本块比较大的时候,正则表达式搜索会非常慢,而且无法处理语言理解的问题(如 entry

    和 entries 应该算是匹配的)。使用全文索引可以非常快地进行文本搜索,就如同内置了多种语言分词机制的支持一样。创建索引的开销都比较大,全文索引的开销更大。创建

    索引时,需后台或离线创建。

   db.table.createIndex({"content": "text"})

    使用全文索引查询内容:

   db.table.find({"$text": {"$search": "coffee"}})

  6,哈希索引

    哈希索引可以支持相等查询,但是哈希索引不支持范围查询。无法创建一个带有哈希索引键的复合索引或者对哈希索引施加唯一性的限制。但是可以在同一个键上同时创建一个

    哈希索引和一个递增/递减(例如,非哈希)的索引,这样MongoDB对于范围查询就会自动使用非哈希的索引。

   db.table.createIndex({"user_id": "hashed"})

MongDB的索引属性介绍:

  1,TTL索引

    TTL索引是一种特殊索引,通过这种索引MongoDB会过一段时间后自动移除集合中的文档。这对于某些类型的信息来说是一个很理想的特性,例如机器生成的事件数据、日志、

    会话信息等,这些数据都只需要在数据库中保存有限时间。

    TTL索引有如下限制:

    • 它不支持复合索引 。

    • 被索引键必须是日期类型的数据。

    • 如果这个键存储的是一个数组,且在索引中有多个日期类型的数据(和一篇文档关联),那么当其中最低 (比如,最早)过期阀值得到匹配时,这篇文档就会过期失效了。

    TTL索引不能保证过期数据会被立刻删除。在文档过期和MongoDB从数据库中删除文档之间,可能会有延迟。删除过期数据的后台任务 每隔60秒 运行一次。所以,在文档过期

    之后 和 后台任务运行或者结束 之前 ,文档会依然存在于集合中。删除操作的持续实际取决于您的 mongod 实例的负载。因此,在两次后台任务运行的间隔间,过期数据可能会

    继续留在数据库中超过60秒。在其他方面,TTL索引是普通索引,并且如果可以的话,MongoDB会使用这些索引来匹配任意查询。

   db.token.createIndex({"lastUpdated": 1}, {"expireAfterSecs": 60*60*24})

    token 超过24小时就会被删除掉。

  2,唯一索引

    唯一索引可以拒绝保存那些被索引键的值已经重复的文档。

   db.table.createIndex({"user_id": 1}, {unique: true})

    唯一性同样适用use_id.a内嵌字段上

  3,稀疏索引

    稀疏索引会跳过所有不包含被索引键的文档。这个索引之所以称为 “稀疏” 是因为它并不包括集合中的所有文档。与之相反,非稀疏的索引会索引每一篇文档,如果一篇文档不含被

    索引键则为它存储一个null值。

   db.table.createIndex({"xmpp_id": 1}, {"sparse": true})

    如果一个索引会导致查询或者排序的结果集是不完整的,那么MongoDB将不会使用这个索引,除非用户使用 hint() 方法来显示指定索引。例如,查询 { x: { $exists: false } }和sort

    中使用x字段将不会使用 x 键上的稀疏索引,或者sort中适用改字段,除非显示的hint。

  4,部分索引

    部分索引只为那些在一个集合中,满足指定的筛选条件的文档创建索引。由于部分索引是一个集合文档的一个子集,因此部分索引具有较低的存储需求,并降低了索引创建和维护

    的性能成本。部分索引通过指定过滤条件来创建,可以为MongoDB支持的所有索引类型使用部分索引。

   db.persons.createIndex({country:1},{partialFilterExpression: {age: {$gt:25}}})

-索引创建

  前台方式:

    当为一个集合创建索引时,这个操作将阻塞其他的所有操作。即该集合上的无法正常读写,直到索引创建完毕

  后台方式:

    适用于那些需要长时间创建索引的情形 这样子在创建索引期间,MongoDB依旧可以正常的为提供读写操作服务

  db.people.createIndex( { zipcode: 1}, {background: true} )

  后台创建索引比前台慢,如果索引大于实际可用内存,则需要更长的时间来完成索引创建

  所有涉及到该集合的相关操作在后台期间其执行效能会下降,应在合理的维护空挡期完成索引的创建

  db.currentOp():查看当前创建进度  db.killOp():杀掉创建进程

-索引数据结构B-tree B+tree

  索引的本质:索引是数据结构

  树型结构查询的有时

  B-tree结构:

  带有顺序访问指针的B+Tree

B-Tree:更少次数的磁盘I/O(一般使用磁盘I/O次数评价索引结构的优劣)

根据B-Tree的定义,可知检索一次最多需要访问h个节点。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。

B+Tree:查询效率高更适合外存索引(感觉这就是mongo会把索引放到内存里的原因)

原因和内节点出度d有关。从上面分析可以看到,d越大索引的性能越好,而出度的上限取决于节点内key和data的大小:

dmax = floor(pagesize / (keysize + datasize + pointsize))   (pagesize – dmax >= pointsize)

或 dmax = floor(pagesize / (keysize + datasize + pointsize)) – 1   (pagesize – dmax < pointsize)

floor表示向下取整。由于B+Tree内节点去掉了data域,因此可以拥有更大的出度,拥有更好的性能。

此处参考文章:http://blog.jobbole.com/24006/

-表结构设计

  1,完全分离(范式化设计)

    利于更新,不利于查询(需要级联作者表查询作者信息)

{
"_id" : ObjectId("5124b5d86041c7dca81917"),
"title" : "如何使用MongoDB",
"author" : [
ObjectId("144b5d83041c7dca84416"),
ObjectId("144b5d83041c7dca84418"),
ObjectId("144b5d83041c7dca84420"),
]
}
 
  2,完全内嵌(反范式化设计)
    利于查询,不利于更新(需要对每本书下的每个作者更新)

{
"_id" : ObjectId("5124b5d86041c7dca81917"),
"title" : "如何使用MongoDB",
"author" : [
{
     "name" : "丁磊"
     "age" : 40,
    "nationality" : "china",
},
{
     "name" : "马云"
     "age" : 49,
     "nationality" : "china",
},
{
     "name" : "张召忠"
     "age" : 59,
     "nationality" : "china",
},
]
}

  3,部分内嵌(折中方案)

    特定场景,人名更新频次很低且业务查询只需要作者姓名

{
"_id" : ObjectId("5124b5d86041c7dca81917"),
"title" : "如何使用MongoDB",
"author" : [
{
    "_id" : ObjectId("144b5d83041c7dca84416"),
     "name" : "丁磊"
},
{
     "_id" : ObjectId("144b5d83041c7dca84418"),
     "name" : "马云"
},
{
     "_id" : ObjectId("144b5d83041c7dca84420"),
     "name" : "张召忠"
},
]
}

  

-如何做好那些重要但不紧急的事情

  让未来可视化,将结果拉近,呈现得具体清晰,倒逼种因。

  在正面谋求自律,从反面寻找他律。

  前期咬紧牙关,后期交给惯性

  叫醒你的,不是闹钟,也未必是梦想,是生物钟,是原理的运用,是客观规律。

  文章链接:https://www.jianshu.com/p/264a3bc87cd0

mongo学习笔记2--索引及表设计的更多相关文章

  1. Django学习笔记(五)—— 表单

    疯狂的暑假学习之  Django学习笔记(五)-- 表单 參考:<The Django Book> 第7章 1. HttpRequest对象的信息 request.path         ...

  2. UML和模式应用学习笔记-1(面向对象分析和设计)

    UML和模式应用学习笔记-1(面向对象分析和设计) 而只是对情节的记录:此处的用例场景为:游戏者请求掷骰子.系统展示结果:如果骰子的总点数是7,则游戏者赢得游戏,否则为输 (2)定义领域模型:在领域模 ...

  3. Flutter学习笔记(13)--表单组件

    如需转载,请注明出处:Flutter学习笔记(13)--表单组件 表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框.复选框等,常见的应用场景有:登陆.注册.输 ...

  4. Linux~学习笔记目录索引

    回到占占推荐博客索引 本篇文章是对自己学习Linux及在它的环境下部署工具的一个总结,以方便自己查阅,也给他人一个帮助,本文章同时会不断的更新,欢迎大家订阅! 本目录包括的内容会包括linux基础命令 ...

  5. Nginx学习笔记~目录索引

    回到占占推荐博客索引 前几天整理了<Docker的学习笔记索引>,受到了很多朋友的关注,今天把Nginx的文章也整理一下,以后将永久更新,像大叔之前的<EF文章系列>,< ...

  6. SpringMVC:学习笔记(5)——数据绑定及表单标签

    SpringMVC——数据绑定及表单标签 理解数据绑定 为什么要使用数据绑定 基于HTTP特性,所有的用户输入的请求参数类型都是String,比如下面表单: 按照我们以往所学,如果要获取请求的所有参数 ...

  7. hive学习笔记之三:内部表和外部表

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. 大数据学习(17)—— HBase表设计

    为啥要把表设计拿出来独立成章?因为我觉得像我这样搞了很多年Java后端开发的技术人员,在学习HBase的时候,会受到关系型数据库3NF.BCNF的影响.事实上,数据库范式在HBase里完全没用,必须转 ...

  9. MySQL学习笔记02_数据库和表的基本操作

    02_1 操作数据库 (1)创建数据库 CREATE DATABASE [IF NOT EXISTS] db_name [create_specification[, create_specifica ...

随机推荐

  1. [PHP] 解决人人商城收银台不能上传图片问题

    反正网上一大堆,也不知道哪个版本有修复,反正我的没有修复. 问题报错:ReferenceError: angular is not defined 解决如下: 修改文件:addons/ewei_sho ...

  2. Centos7 下安装mysql5.7.17(glibc版)

    一.安装前的检查 1.1 检查 linux 系统版本 [root@localhost ~]# cat /etc/system-release 1.2 检查是否安装了 mysql [root@local ...

  3. 宏开发:excel中添加拼接行

    Sub 万途标签()Dim iFor i = 1 To Sheets.Count    If Sheets(i).Name = "数据表" Then        If MsgBo ...

  4. Asp.Net Core WebApi 和Asp.Net WebApi上传文件

    public class UpLoadController : ControllerBase { private readonly IHostingEnvironment _hostingEnviro ...

  5. 日常开发工作常用linux命令

    :wq 保存退出 :q! 强制退出 vi 查看 vim 编辑 rpm -qa|grep jdk 命令查看当前的jdk情况 yum -y remove java java-1.7.0-openjdk* ...

  6. Hadoop 安全模式safemode

    启动Hdfs 系统的时候,其中的一个阶段“”安全模式 发生阶段:NameNode启动中,已经读取了fsimage 并且生成了edits 文件,在等待dataNode 向nameNode 发送block ...

  7. Windows环境下IOS APP打包上传AppStore详细流程

    我们知道在上架苹果应用过程中,申请发布证书需要用到钥匙串,上传ipa需要用到xcode或Application loader提交构建版本,这都需要Mac苹果机. 本文介绍如何在Windows环境下申请 ...

  8. ps top 命令

    pstree :显示进程树 ps: a:查看和终端有关的进程 u:显示进程是哪个用户启动的 x:和终端无关 ps aux |head 进程的分类: 和终端有关 和终端无关 进程状态: D:不可中断睡眠 ...

  9. [c/c++] programming之路(31)、位运算(二)

    一.取反的高级用法 #include<stdio.h> #include<stdlib.h> //取反的作用:末位清零 取反适用于各种位数不同的数据 void main0(){ ...

  10. python学习之——习题一

    习题一:使用while循环输入1 2 3 4 5 6   8 9 10 (不含7) 首先想到,先使用while循环打印出1-10数字,然后再将数字“7”剔除. # 先打印出1-10 n = 1 whi ...