数据库的演进
随着计算机的发展,越来越多的数据需要被处理,数据库是为处理数据而产生。从概念上来说,数据库是指以一定的方式存储到一起,能为多个用户共享,具有更可能小的冗余,与应用程序彼此独立的数据集合。从功能上来说,就是数据管理软件。
到了2000年随着互联网的发展,数据量呈现爆发式增长。海量数据的诞生,传统的关系型数据库在应对大规模,超大流量的时候就显得力不从心。借此,NoSQL数据库跟NewSQLl数据库就此登场。
NoSQL 全称 “not only sql”,所有非关系型的数据库都统称为NoSQL数据库,NoSQL数据库主要有四种类型,文档数据库(MongoDB为代表),键值数据库(Redis为代表),宽列存储(Hbase为代表)和图形数据库(Neo4J为代表)。
NewSQL数据库,提供了与NoSQL相同的扩展性,但仍属于关系型模型,还保留SQL作为查询语言,保证了ACID事务性。代表数据库有Spanner,CockroachDB。
数据库发展到今天,可以说是百花齐放,随着2020年阿里云数据库进入全球魔力四象限的Leader象限,这也是中国数据库40年来首次进入全球顶级数据库行列,标志着国产数据库开始崛起。
数据库索引技术
数据库是用来处理数据的,那高效的存储、检索数据,是数据库管理系统必备的技能。数据库中用于提高检索效率很重要的一项技术就是索引。
数据结构指的是“一组数据的存储结构”,算法指的是“操作数据的一组方法”。数据结构是为算法服务的,算法是要作用在特定的数据结构上的。数据库提高检索效率使用的是索引,数据库索引是一种树形数据结构,如MongoDB使用的是B-tree、MySQL使用的是B+tree。
参考https://blog.csdn.net/dbaxiaosa/article/details/127750957
MongoDB介绍
本文重点介绍MongoDB,它虽然诞生于NoSQL,但4.0版本之后,已经不仅仅是NoSQL了,可以与上文中任何一位NewSQL的代表PK。MongoDB是一个开源、高性能、无模式的文档数据库,旨在简化开发和扩展。
MongoDB索引
磁盘读取依靠的是机械运动,分为寻道时间、旋转延迟、传输时间三个部分,这三个部分耗时相加就是一次磁盘IO的时间,大概9ms左右。这个成本是访问内存的十万倍左右。正是由于磁盘IO是非常昂贵的操作,所以数据库性能优化的核心思想是降低磁盘IO次数。
普通的机械盘HDD一次磁盘IO的时间大概是9ms
普通SSD一次磁盘IO耗时大概是0.2ms(IOPS:5000)
PCIe卡一次磁盘IO耗时大概是0.05ms(IOPS:20000)
从二叉树的查找过程了来看,最坏的情况下磁盘IO的次数由树的高度来决定。要减少磁盘IO的次数就必须要压缩树的高度,让瘦高的树尽量变成矮胖的树,所以B-Tree就在这样伟大的时代背景下诞生了。
索引是一种特殊的数据结构,常用于提高检索效率。MongoDB索引使用的是B-tree数据结构。
MongoDB 索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
MongoDB 索引类型
1、默认_id 索引:会默认为每个表创建_id索引,不可以删除
2、唯一索引:对于单字段索引和排序操作,索引键的排序顺序(即升序或降序)无关紧要,因为MongoDB可以在任一方向上遍历索引。
3、复合索引:MongoDB支持用户在多个字段上定义索引,即 复合索引。对于复合索引和排序操作,索引键的排序顺序(即升序或降序)可以确定索引是否可以支持排序操作
4、多键索引:MongoDB使用多键索引来索引存储在数组中的内容。如果索引字段包含数组值,MongoDB会为数组的每个元素创建单独的索引条目。这些多键索引允许查询通过匹配数组中的元素来获取包含数组的文档。如果索引字段包含数组值,MongoDB会自动决定是否需要创建多键索引; 不需要显式指定多键类型。
5、地理空间索引:为了支持对地理空间坐标数据的高效查询,MongoDB提供了两个特殊索引:返回结果时使用平面几何的2d索引和使用球面几何的2dphere索引。
6、全文索引(文本索引):MongoDB提供了一种text索引类型,支持在集合中搜索字符串内容。
7、hash索引:为了支持基于哈希的分片,MongoDB提供了哈希索引类型,索引字段值的哈希值。这些索引在其范围内具有更随机的值分布
注意
在分片群集中,如果不将该_id字段用作分片键,则应用程序必须确保_id字段值的唯一性以防止出错。通常使用标准的自动生成的ObjectId来完成。
索引方法:
createIndex() 方法
MongoDB使用 createIndex() 方法来创建索引。
db.collection.createIndex(keys, options)
语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。
1、查看集合索引
db.col.getIndexes()
2、查看集合索引大小
db.col.totalIndexSize()
3、删除集合所有索引
db.col.dropIndexes()
4、删除集合指定索引
db.col.dropIndex("索引名称")
索引失效时间设定
db.col.createIndex({“createDate”: 1},{expireAfterSeconds: 180})
利用 TTL 集合对存储的数据进行失效时间设置:经过指定的时间段后或在指定的时间点过期,MongoDB 独立线程去清除数据。类似于设置定时自动删除任务,可以清除历史记录或日志等前提条件,设置 Index 的关键字段为日期类型 new Date()。
MongoDB 覆盖索引查询
官方的MongoDB的文档中说明,覆盖查询是以下的查询:
1、所有的查询字段是索引的一部分
2、所有的查询返回字段在同一个索引中
由于所有出现在查询中的字段是索引的一部分, MongoDB 无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询结果。
因为索引存在于RAM中,从索引中获取数据比通过扫描文档读取数据要快得多。
MongoDB 查询分析
MongoDB 查询分析可以确保我们所建立的索引是否有效,是查询语句性能分析的重要工具。
MongoDB 查询分析常用函数有:explain() 和 hint()。
1 使用 explain()
explain 操作提供了查询信息,使用索引及查询统计等。有利于我们对索引的优化。
2 使用 hint()
虽然MongoDB查询优化器一般工作的很不错,但是也可以使用 hint 来强制 MongoDB 使用一个指定的索引。
MongoDB 索引限制
每个索引占据一定的存储空间,在进行插入,更新和删除操作时也需要对索引进行操作。所以,如果你很少对集合进行读取操作,建议不使用索引。
内存(RAM)使用
由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。
如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。
最大范围
集合中索引不能超过64个
索引名的长度不能超过128个字符
一个复合索引最多可以有31个字段
查询限制
索引不能被以下的查询使用:
正则表达式及非操作符,如 $nin, $not, 等。
算术运算符,如 $mod, 等。
$where 子句
通过执行计划查看索引是否有用
尽量使用覆盖索引
利用前缀索引
避免建重复索引,提高索引使用率
尽量利用索引排序,避免产生临时表
避免使用全模糊查询 like '%xxx%’
单集合索引建议不超过7个
MongoDB 全文检索
全文检索对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。
比如:db.posts.ensureIndex({post_text:“text”})
索引注意事项
创建索引时,请考虑索引的以下行为:
1、每个索引至少需要 8 kB 的数据空间。
2、添加索引对写操作有一些负面的性能影响。对于具有高write-to-read比率的集合,索引很昂贵,因为每个插入还必须更新索引。
3、具有高read-to-write比率的集合通常受益于额外的索引。索引不影响未索引的读取操作。
4、当处于活跃状态时,每个索引都会消耗磁盘空间和内存。这种使用可能很重要,应该跟踪容量规划,尤其是对工作集大小的关注。
通过本文的学习,你应该对索引有了一定的认识,希望让你对mongodb优化有一定的提高。