mongo学习笔记2--索引及表设计
-背景:
鉴于我们使用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"),
]
}
{
"_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--索引及表设计的更多相关文章
- Django学习笔记(五)—— 表单
疯狂的暑假学习之 Django学习笔记(五)-- 表单 參考:<The Django Book> 第7章 1. HttpRequest对象的信息 request.path ...
- UML和模式应用学习笔记-1(面向对象分析和设计)
UML和模式应用学习笔记-1(面向对象分析和设计) 而只是对情节的记录:此处的用例场景为:游戏者请求掷骰子.系统展示结果:如果骰子的总点数是7,则游戏者赢得游戏,否则为输 (2)定义领域模型:在领域模 ...
- Flutter学习笔记(13)--表单组件
如需转载,请注明出处:Flutter学习笔记(13)--表单组件 表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框.复选框等,常见的应用场景有:登陆.注册.输 ...
- Linux~学习笔记目录索引
回到占占推荐博客索引 本篇文章是对自己学习Linux及在它的环境下部署工具的一个总结,以方便自己查阅,也给他人一个帮助,本文章同时会不断的更新,欢迎大家订阅! 本目录包括的内容会包括linux基础命令 ...
- Nginx学习笔记~目录索引
回到占占推荐博客索引 前几天整理了<Docker的学习笔记索引>,受到了很多朋友的关注,今天把Nginx的文章也整理一下,以后将永久更新,像大叔之前的<EF文章系列>,< ...
- SpringMVC:学习笔记(5)——数据绑定及表单标签
SpringMVC——数据绑定及表单标签 理解数据绑定 为什么要使用数据绑定 基于HTTP特性,所有的用户输入的请求参数类型都是String,比如下面表单: 按照我们以往所学,如果要获取请求的所有参数 ...
- hive学习笔记之三:内部表和外部表
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- 大数据学习(17)—— HBase表设计
为啥要把表设计拿出来独立成章?因为我觉得像我这样搞了很多年Java后端开发的技术人员,在学习HBase的时候,会受到关系型数据库3NF.BCNF的影响.事实上,数据库范式在HBase里完全没用,必须转 ...
- MySQL学习笔记02_数据库和表的基本操作
02_1 操作数据库 (1)创建数据库 CREATE DATABASE [IF NOT EXISTS] db_name [create_specification[, create_specifica ...
随机推荐
- JavaIO流——简单对文件的写入及读取(三)
已经讲了写入和读取了,那么想要把一个文件的内容复制到另一个文件呢 不说太多,直接见代码 public static void copyFile(String srcFilename, String d ...
- python数据类型之集合类型
一.集合的作用 知识点回顾:可变类型是不可hash类型,不可变类型是可hash类型 作用:去重,关系运算 定义:可以包含多个元素,用逗号分割,集合的元素遵循三个原则: 1.每个元素必须是不可变类型(可 ...
- NetBeans远程调试Linux c++ 11项目
NetBeans远程调试Linux c++ 11项目 由于好多原因,好久没有写博客了,随着c++ 11的普及率越来越高,开发c++ 项目的人也越来越多,可以说c++ 11 给了c++ 这门语言第二次生 ...
- 洛谷P2611 信息传递
并查集裸题,记录每个点的胜读,取个min就好了 #include<stdio.h> #include<string.h> #include<algorithm> u ...
- python学习笔记之socket(第七天)
参考文档: 1.金角大王博客:http://www.cnblogs.com/alex3714/articles/5227251.html ...
- Java EE开发技术课程第六周(jsf、facelets)
1.jsf(java sever faces) 1.1 jsf的定义: jsf是一种用于构建java web应用程序的框架.它提供了一种以组件为中心的用户界面(UI)构建方法,从而简化了Java服务器 ...
- 前端使用node.js的http-server开启一个本地服务器
前端使用node.js的http-server开启一个本地服务器 在写前端页面中,经常会在浏览器运行HTML页面,从本地文件夹中直接打开的一般都是file协议,当代码中存在http或https的链接时 ...
- [转载]URI 源码分析
需要提前了解下什么是URI,及URI和URL的区别: URI. URL 和 URN 的区别 URI 引用包括最多三个部分:模式.模式特定部分和片段标识符.一般为: 模式:模式特定部分:片段 如果省略模 ...
- vue配置404页面
{ path:'*', name:"/404", component:cuowu } path星号表示没有这个路由 name表示去这个地址 component这个页面引入的时候叫的 ...
- centos6.9 PHP的编译安装并连接nginx
1.安装yum -y install libxml2-devel openssl-devel bzip2-devel libmcrypt-devel 解决php包的依赖关系,可能libmcrypt会报 ...