文章目录
- 1 MongoDB介绍
- 2 安装
- 3 常用命令
- 4 索引
- 5 Java操作MongoDB
- 6. 副本集
- 7 分片
1 MongoDB介绍
1.1 应用场景
传统的关系型数据库(如MySQL),在应对当下互联网产品的某些需求面前,显得力不从心
- 数据库高写入负载需求(比如日志,常写,不常看)
- 对海量数据的高效率存储和读取(比如人脸识别采集,物流位置定位,数据采集量很大)
- 对数据库的高扩展性的需求(数据表经常修改)
这些场景中,MySQL处理起来略有麻烦,主要在于压力过大,而MongoDB应对起来则很灵活。
具体的应用场景:
视频直播:使用MongoDB存储点赞、评论、弹幕信息。
游戏场景:使用MongoDB存储用户积分、打怪记录、NPC对话记录。
社交场景:使用MongoDB存储朋友圈信息、浏览记录、评论、转发、收藏、附近的人、聊天记录。
电商场景:使用MongoDB存储收藏、购物车、浏览历史。
数据不太重要了,不经常看,且丢失少量也在接收范围内
这些场景中,数据操作方面的共同特点是:
- 数据量大
- 写入操作频繁
- 数据价值较低,能接受少量的数据丢失和不同步
- 查询频率可能很频繁或者频率很低。
1.2 什么时候选择MongoDB
在架构选型上,除了上面4个特点外,还有什么场景可以使用到MongoDB?
- 业务不需要强力的事务或者不需要复杂的连表查询
- 快速迭代开发,需求变更较快,表结构常常会因此修改
- 系统需要应对高达3000QPS(或者更高)的读写
- 业务数据需要GB、TB甚至PB级别的存储
- 系统接受数据在允许的范围内丢失
- 系统需要大量数据的查询,如地理位置。
如果遇到了以上的场景,就可以考虑MongoDB。当然你可以继续使用MySQL,这样可以降低引入一门新技术带来的维护、学习成本,但是以上场景使用MySQL往往会使系统存在瓶颈。
1.3 MongoDB简介
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
MongoDB特点
MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库 单表查询的绝大部分功能 ,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。具体特点总结如下:
- 面向集合存储,易于存储对象类型的数据
- 模式自由
- 支持动态查询
- 支持完全索引,包含内部对象
- 支持复制和故障恢复
- 使用高效的二进制数据存储,包括大型对象(如视频等)
- 自动处理碎片,以支持云计算层次的扩展性
- 支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++语言的驱动程序,社区中也提供了对Erlang 及.NET 等平台的驱动程序
- 文件存储格式为 BSON(一种 JSON 的扩展)
1.4 MongoDB体系结构
MongoDB 的逻辑结构是一种层次结构。主要由:文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
(1)MongoDB 的文档(document),相当于关系数据库中的一行记录。
(2)多个文档组成一个集合(collection),相当于关系数据库的表。
(3)多个集合(collection),逻辑上组织在一起,就是数据库(database)。
(4)一个 MongoDB 实例支持多个数据库(database)
1.5 数据类型
数据类型 | 简介 | 举例 |
---|---|---|
字符串 | 字符串类型的数据 | {“name”: “张三”} |
对象id | 对象id是文档的12字节的唯一ID,一般key是固定的_id | {"_id": ObjectId()} |
布尔值 | true/false | {“state”: true} |
数组 | 值的集合,类似于json中的数组 | {“hobby”: [“唱”, “跳”, “rap”, “篮球”]} |
64位浮点数 | BSON中数字只支持这种类型,没有整数类型。但是可以使用NumberInt(4字节整数)或者NumberLong(8字节符号整数)来表示整数 | {“score”: 150}, {“age”: NumberInt(18)} |
null | 表示空值或者未定义的对象 | {“sex”: null} |
undefined | 表示未定义的对象 | {“sex”: undefined} |
正则表达式 | BSON的正则采用JavaScript的正则表达式语法 | {“pattern”: /\d/} |
代码 | BSON可以包含JavaScript代码 | {“code”: function() {xxx}} |
1.6 MongoDB的特点
-
高性能
MongoDB提供高性能的数据持久性,对嵌入式数据模型的支持减少了数据库系统上的IO活动。
支持索引查询,使查询的速度更加提高
支持如mmapv1、wiredtiger等多种存储引擎
-
高可用
MongoDB的复制工具称为副本集,它可以提供自动故障转移和数据冗余
-
高扩展
MongoDB提供了水平可扩展性作为核心功能的一部分。
分片将数据分布在一组集群的机器上。
从3.4版本开始,MongoDB支持基于分片键创建数据区域,在一个平衡的集群中,MongoDB将一个区域所覆盖的读写只定向到该区域内的那些片
-
丰富的查询支持
MongoDB支持丰富的查询语言,如数据聚合、文本搜索、地理空间查询等。
2 安装
MongoDB的版本号是x.y.z,其中x是大版本,y为奇数的时候是开发板,y为偶数的时候是稳定版,z是修正版本号,z越大往往意味着bug越少。当前版本是4.4.0,不建议下载该版本,推荐下载4.0.19版本。
如果是Linux则下载Linux版本
2.1 windows系统安装
下载windows版本的zip包,放到一个目录中,解压到当前目录。
在解压目录中,手动创建一个目录存放数据文件,如data/db
命令行启动
在bin目录中按住键盘 shift ,右击鼠标,选择在此处打开命令窗口(如果打开的是powershell就需要手动进cmd切换到bin目录),然后输入如下命令启动MongoDB:
mongod --dbpath=../data/db
mongodb默认的端口是27017,如果想改变默认的端口,可以在启动的时候使用 –port 来指定端口。
为了方便启动,可以将bin目录配置到环境变量中,这样就可以在任何地方使用mongodb的命令了。
配置文件方式启动服务
在解压目录中新建config文件夹,在里面新建配置文件 mongod.conf
,内容如下
storage:
dbPath: H:\\mongodb\\data
注意:路径中不可以有Tab字符,路径有空格需要加双引号,双引号需要转义,对于\字符也需要换成\或者/
接着使用命令启动
mongod -f ../config/mongod.conf
或者
mongod --config ../config/mongod.conf
2.2 Linux系统安装
Linux部署MongoDB操作和Windows差不多
官网下载Linux版的tgz包,上传到Linux目录中,解压到当前目录
tar -xvf mongodb-linux-x86_64-4.0.19.tgz
移动解压后的文件夹到指定目录
mv mongodb-linux-x86_64-4.0.19 /usr/local/mongodb
新建数据目录和日志目录
# 数据存储目录
mkdir -p /mongodb/data/db
# 日志存储目录
mkdir -p /mongodb/log
新建配置文件,并修改内容
vi /mongodb/mongod.conf
配置文件内容
systemLog:
# MongoDB日志输出到文件
destination: file
# 日志文件路径
path: "/mongodb/log/mongod.log"
# 当mongod实例重新启动时,将新条目附加到现有日志文件的末尾
logAppend: true
storage:
# mongod实例存储数据的目录
dbPath: "/mongodb/data/db"
journal:
# 启用或禁用持久性日志
enabled: true
processManagement:
# 启用在后台运行
fork: true
net:
# 这里是个坑,只能配置0.0.0.0或者本机ip。网上很多教程都是复制粘贴,很不负责任。如果需要限制ip访问,请使用云服务器的安全组
bindIp: 0.0.0.0
# 绑定的端口,默认是27017
port: 27017
启动服务
/usr/local/mongodb/bin/mongod -f /mongodb/mongod.conf
启动后显示successfully,如果没有就说明配置文件有问题,启动失败了。
[root@iZ2zebq96d1zohii1vadzqZ mongodb]# /usr/local/mongodb/bin/mongod -f /mongodb/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 1526
child process started successfully, parent exiting
查看服务是否启动成功
ps -aux|grep mongod
Linux下关闭MongoDB步骤(极不建议使用kill强制杀死进程,这样数据会存在损坏,下次无法启动了)
推荐以下方式关闭,通过客户端指令关闭服务端:
# 客户端登录服务
mongo --port 27017
# 切换到admin库
use admin
# 关闭服务
db.shutdownServer()
2.3 Docker安装
安装docker
yum -y install gcc
yum -y install gcc-c++
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
yum -y install docker-ce
systemctl start docker
上面全部复制,一起粘贴即可
下面是配置国内仓库,可以不进行
mkdir -p /etc/docker
vim /etc/docker/daemon.json
在文件中添加如下配置
#阿里云镜像加速器{"registry-mirrors": ["http://hub-mirror.c.163.com"] }
systemctl daemon-reload
systemctl restart docker
先创建目录存放数据、日志、配置文件
# 进入local
cd /usr/local
# 创建docker目录,以后的挂载文件都放到这里
mkdir -p docker
cd docker
mkdir -p mongodb
# 进入mongodb目录
cd mongdob
# 创建data、log、conf三个文件夹
mkdir data log conf
chmod 777 data
touch log/mongod.log
chmod 777 log/mongod.log
# 创建配置文件
vi conf/mongod.conf
配置文件中添加如下配置
systemLog:
# MongoDB日志输出到文件
destination: file
# 日志文件路径
path: "/usr/local/docker/mongodb/log/mongod.log"
# 当mongod实例重新启动时,将新条目附加到现有日志文件的末尾
logAppend: true
storage:
# mongod实例存储数据的目录
dbPath: "/usr/local/docker/mongodb/data/db"
journal:
# 启用或禁用持久性日志
enabled: true
processManagement:
# 启用在后台运行
fork: true
net:
# 服务实例绑定的IP,默认是localhost,这里设置的是哪些ip可以访问
bindIp: 0.0.0.0
# 绑定的端口,默认是27017
port: 27017
创建mongodb容器
docker run -di --name mongodb --restart=always --privileged -p 27017:27017 -v /usr/local/docker/mongodb/data:/data/db -v /usr/local/docker/mongodb/conf:/data/configdb -v /usr/local/docker/mongodb/log:/data/log/ mongo:latest -f /data/configdb/mongod.conf
–restart=always Docker服务重启容器也启动
–privileged -p 拥有真正的root权限
-f 指定配置文件(注意,这里指定的是容器内路径,如果需要使用外部配置文件,则需要将容器内路径映射到外面)
2.4 连接mongodb
2.4.1 命令行连接
在命令行界面输入一下命令完成连接并登录
mongo
或者
mongo --host=ip地址 --port=27017
如果是docker,需要先进入docker容器
docker exec -it mongodb bash
2.4.2 Compass客户端连接
到官网下载compass 下载地址
直接解压运行,界面上输入连接信息点击连接
2.4.3 Navicat连接
Navicat安装、破解教程在资料中已经提供
Navicat不是MongoDB官方的连接软件,但是很好用,只需要下载12.1以上的navicat即可。
点击连接,选择mongodb
3 常用命令
3.1 数据库操作
3.1.1 选择和创建数据库
use 数据库名称
如果数据库不存在就自动创建,如果存在则选择该数据库
以下数据库名是保留的,可以直接访问
admin:这是root数据库,如果将一个用户添加到这个数据库,这个用户就自动继承所有数据库的权限。一些特定的命令,如关闭数据库,只能在这个数据库运行
local:这个数据库永远不会被复制,可以用来存储本地单台服务器的任意集合
config:当mongodb分片设置时,config数据库用于保存分片信息
3.1.2 查看当前有权限查看的所有数据库
show dbs
或者
show databases
3.1.3 查看当前正在使用的数据库
db
MongoDB默认的数据库是test,如果不选择数据库,集合就默认存放到test
3.1.4 删除数据库
db.dropDatabase()
该命令执行前需要进入一个数据库。删除的是当前数据库
3.2 集合操作
注意:MongoDB中,集合只有在内容被插入后才会创建。因此创建一个集合后,需要再插入一个文档。
集合,与MySql中的表类似
3.2.1 创建集合
db.createCollection(集合名称)
比如创建一个叫user的集合
db.createCollection("user")
接着查看当前数据库中的集合
show tables
或者
show collections
注意:
- 集合名称不能为空,也不可以是空字符串。
- system.是系统集合的前缀,创建集合不可以以这个为开头
- 一般我们并不会使用显式的创建集合,因为当向一个集合中插入一个文档的时候,如果集合不存在,就会自动创建集合
3.2.2 集合删除
du.集合名称.drop()
如果删除成功,该方法返回true,否则返回false
3.3 文档增删改
3.3.1 文档插入
文档类似于MySql中的row,表示一行数据。MongoDB中文档的数据结构和JSON基本一样,是一种叫BSON的格式。
单条数据插入
插入方法使用 insert()
或者 save()
或者 insertOne()
方法
语法
db.集合名.insert(BSON格式文档内容)
或者
db.集合名.save(BSON格式文档内容)
或者
db.集合名.insertOne(BSON格式文档内容)
- save():如果 _id 主键存在则更新数据,如果不存在就插入数据。该方法新版本中已废弃,可以使用 db.collection.insertOne() 或 db.collection.replaceOne() 来代替。
- insert(): 若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据。
如向user集合中插入一条数据
db.user.insert({name: "张三", age: 23})
默认情况下,MongoDB使用
_id
字段作为主键,自动生成。如果手动指定,则使用手动指定的数据。
_id
字段类型是ObjectId,手动指定id时可以使用ObjectId,也可以使用MongoDB支持的任意类型
批量插入
db.集合名.insertMany(
[文档1, 文档2...],
{
ordered: 指定MongoDB是否有序插入。可选值
}
)
MongoDB的批量插入并不是同时成功或者同时失败。如果在插入过程中有一条数据失败,就会终止插入,但是在此之前的数据都会插入成功。
插入数据较多的情况下可能会报错,可以在命令前后使用try catch进行异常捕捉
try {
db.集合名.insertMany()
} catch(e) {
print(e)
}
3.3.2 更新文档
更新文档使用update方法
db.集合名.update(
{BSON格式查询条件},
{BSON格式要更新的内容},
{
upsert: 布尔类型,指定如果不存在update的记录,是否插入。默认false
multi: 默认false,只更新找到的第一条记录。如果为true,则更新查询条件下的所有记录
}
)
覆盖修改
修改用户编号是1的数据,姓名修改为 李四
db.user.update(
{_id: "1"},
{name, "李四"}
)
修改完成后发现这条文档只剩下name字段了,其他字段被覆盖掉了,因此实际使用不可以这么写。
局部修改
修改数据时,建议使用修改器 $set
来实现。还是上面那条需求。
db.user.update(
{_id: "1"},
{$set: {name: "李四"}}
)
修改成功,其他字段依然存在
批量修改
更新所有年龄是18岁的用户,年龄更新为19
db.user.update(
{age: NumberInt(18)},
{$set: {age: NumberInt(19)}},
{multi: true}
)
如果不加multi参数,只会更新符合条件的一条数据
列值自增
如果想要 对某列的值进行自增操作,可以使用 $inc
db.集合名.update(
{_id: "1"},
{$inc: {age: NumberInt(1)}}
)
3.3.3 删除文档
db.集合名称.remove(BSON格式条件)
#下面的语句会删除所有数据,慎用
db.集合名称.remove({})
3.4 文档查询
3.4.1 查询方法
查询使用 find()
或者 findOne()
方法进行
语法
db.集合名.find(BSON格式条件).pretty()
pretty是可选项。功能是格式化输出查询结果。
find()
方法会查询出所有符合要求的数据
findOne()
方法只会查询出第一条符合要求的数据
例如我要查询编号是1的用户
db.user.find({_id: "1"})
3.4.2 条件查询
条件查询的作用是让MongoDB可以像MySQL一样根据特定的条件从数据库中查询数据
常用的条件如下表
操作 | 格式 | 范例 | MySQL中类似语句 |
---|---|---|---|
等于 | {key, value} | db.user.find({_id: 1}) | where id = 1 |
小于 | {key, {$lt: value} | db.user.find({age: {$lt: 18}}) | where age < 18 |
小于等于 | {key, {$lte: value}} | db.user.find({age: {$lte: 18}}) | where age <= 18 |
大于 | {key, {$gt: value}} | db.user.find({age: {$gt: 18}}) | where age > 18 |
大于等于 | {key, {$gte: value}} | db.user.find({age: {$gte: 18}}) | where age >= 18 |
不等于 | {key, {$ne: value}} | db.user.find({age: {$ne: 18}}) | where age != 18 |
包含 | {key, /value/} | db.user.find(name: /俊/) | where name like ‘%俊%’ |
以…开头 | {key, /^value/} | db.user.find(name: /^雷/) | where name like ‘雷%’ |
以…结尾 | {key, /value$/} | db.user.find(name: /华$/) | where name like ‘%华’ |
在…之中 | {key, {$in: [value1, value2…]}} | db.user.find(age: {$in: [1,2,3]}) | where age in (1,2,3) |
不在…之中 | {key, {$nin: [value1, value2…]}} | db.user.find(age: {$nin: [1,2,3]}) | where age not in (1,2,3) |
类型为… | {key: {$type: “string”}} | db.user.find(age: {$type: ‘string’}) | 无。查询用户集合中age是String类型的数据 |
其中,/value/ 事实上是正则表达式查询。语法和JS中的正则一模一样。
3.4.3 条件连接查询
AND 条件
find()
方法可以传入多个键值对,类似于SQL的AND条件
如,查询性别是男,年龄在18岁的用户
db.user.find({sex: "1", age: "18"})
OR 条件
MongoDB提供了关键字 $or
用来实现or查询
语法
db.集合名.find({$or: [{key1, value1}, {key2, value2}]})
如,查询年龄是17或者19的用户
db.user.find({$or: [{age: 17}, {age: 19}]})
AND 和 OR 联合使用
如,查询性别是男,并且年龄是17或者19的用户
db.user.find({sex: "1", $or: [{age: 17}, {age: 19}]})
3.4.4 投影查询
默认情况下,查询的结果是返回所有字段。这样的话性能可能会比较低。一般我们只查询需要的部分字段,就可以使用投影查询
如,只查询name, age字段
db.user.find({_id: "1"}, {name: 1, age: 1, _id: 0})
这里的_id默认是会被查询出来的,如果不想显示 _ id,就可以使用 _id: 0来隐藏该列
3.4.5 统计查询
语法
db.集合名.count(BSON格式条件)
统计所有性别为男的数据
db.user.count({age: "1"})
3.4.6 分页查询
使用 limit
读取指定数量的数据, skip
跳过指定数量的数据,二者搭配来进行分页查询。使用逻辑和MySql中的limit一样。
查询返回前三条记录,limit参数默认是20
db.集合.find().limit(3)
跳过前3条记录,skip参数默认是0
db.集合.find().skip(3)
每页查询2条数据
db.集合.find().skip(0).limit(2)
db.集合.find().skip(2).limit(2)
db.集合.find().skip(3).limit(2)
3.4.7 排序查询
排序查询使用 sort
方法。sort方法可以指定排序的字段,值为1升序,值为-1降序
根据性别升序排序,并根据年龄降序排序
db.user.find().sort({sex: 1, age: -1})
再进行分页,每页20条
db.user.find().sort({sex: 1, age: -1}).skip(0).limit(20)
3.5 角色权限操作(了解)
默认情况下,MongoDB运行时是没有启用和用户访问权限控制的,MongoDB不会对连接客户端进行用户验证,这样非常危险。
可以通过MongoDB启动时使用选项 --auth
或者在启动时指定的配置文件中添加 auth=true
来强制开启访问控制。
MongoDB是基于角色的访问控制,通过对一个用户授予一个或者多个角色来控制用户的权限。
3.5.1 角色查询
查询所有角色权限(仅用户自定义角色)
db.runCommand({rolesInfo: 1})
查询所有角色权限(包含内置角色)
db.runCommand({rolesInfo: 1, showBuiltinRoles: true})
查询当前数据库中指定角色的权限
db.runCommand({rolesInfo: 角色名})
查询其他数据库中指定的角色权限
db.runCommand({rolesInfo: {role: 角色名, db: 数据库名}})
查询多个角色权限
db.runCommand({rolesInfo: [角色名...., {role: 角色名, db: 数据库名}]})
常见角色
角色 | 描述 |
---|---|
read | 指定数据库的读权限 |
readWrite | 指定数据库的读写权限 |
readAnyDatabase | 任何数据的读权限(除了config和local) |
readWriteAnyDatabase | 任何数据的读写权限(除了config和local) |
userAdminAnyDatabase | 指定数据库创建修改用户的权限 |
dbAdminAnyDatabase | 任何数据库的读取、清理、修改、压缩、统计等权限 |
dbAdmin | 指定数据库的读取、清理、修改、压缩、统计等权限 |
userAdmin | 指定数据库创建和修改用户 |
clusterAdmin | 对整个集群或者数据库系统进行管理操作 |
backup | 备份MongoDB数据 |
restore | 还原MongoDB数据 |
root | 超级权限 |
3.5.2 安全认证
3.5.2.1 前置操作
关闭数据库
mongo --port 27017
use admin
db.shutdownServer()
3.5.2.2 添加用户和权限
先不进行配置,正常启动数据库
/usr/local/mongodb/bin/mongod -f /usr/local/mongod.conf
登录数据库
/usr/local/mongodb/bin/mongo
创建系统超级管理员mongoroot和admin数据库的管理用户mongoadmin
# 切到admin
use admin
# 创建系统超级用户mongoroot,密码123456,角色root
db.createUser({user: "mongoroot", pwd: "123456", roles: ["root"]})
# 创建admin库的管理员
db.createUser({user: "mongoadmin",pwd: "123456", "roles": [{role: "userAdminAnyDatabase", db:"admin"}]})
# 查看已经创建的用户
db.system.users.find()
MongoDB默认把用户信息存放到
admin
数据库的system.users
表中创建用户如果不指定数据库,则创建的用户在所有数据库上有效
3.5.2.3 认证测试
# 切到admin
db.auth("账号", "密码")
3.5.2.4 创建普通用户
# 切到bbs
use bbs
# 创建用户,拥有读写权限
db.createUser({user: "jigege", pwd: "123456", roles: [{role: "readWrite", db: "bbs"}]})
如果在启动mongodb时不开启认证,那么启动后不管是否用账号密码都可以成功连接数据库。
如果开启了认证,登陆的客户端必须使用admin中保存的角色
3.5.2.5 开启认证
先关闭数据库
use admin
db.shutdownServer()
重新启动mongodb,开启认证
参数方式
/usr/local/mongodb/bin/mongod -f /mongodb/mongod.conf --auth
配置文件方式
编辑配置文件
vim /mongodb/mongof.conf
加入以下内容
security:
#开启授权认证
authorization: enabled
正常启动
/usr/local/mongodb/bin/mongod -f /mongodb/mongod.conf
连接时认证
/usr/local/mongodb/bin/mongo --host 172.17.238.235 --port 27017 -u mongoroot -p 123456
对bbs数据库进行登录认证操作
/usr/local/mongodb/bin/mongo --host 172.17.238.235 --port 27017 -u jigege -p 123456
-u 用户名
-p 密码
3.6 暴力关闭数据库补救
暴力关闭数据库
ps -aux|grep monogodb
kill -9 进程号
暴力关闭后,可能会存在数据的损坏,导致mongodb无法启动,可以通过下面的操作恢复(如果失败那神仙也救不了你了)
删除lock文件
rm -f /mongodb/data/db/*.lock
修复数据
/usr/local/mongodb/bin/mongod --repair --dbpath=/mongodb/data/db
4 索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文档并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
MongoDB中使用 B树
数据结构存储索引,B树在本次课程中不作讲解。
4.1 索引分类
4.1.1 单字段索引
MongoDB支持在文档单个字段上创建用户定义的升序/降序索引,称之为 单字段索引
4.1.2 复合索引
MongoDB还支持多个字段的索引,称之为 复合索引
复合索引中对字段顺序也有要求,如果复合索引是由 {age: 1, sex: -1} 组成,就会先按照age正序排序,再按照sex倒序排序
4.1.3 地理空间索引
为了支持对地理坐标的有效查询,MongoDB提供了二维索引和二维球面索引
4.1.4 文本索引
MongoDB提供了文本索引,支持在集合中搜索字符串内容。
4.1.5 哈希索引
为了支持散列的分片,MongoDB提供了散列索引,它对字段值的散列进行索引。哈希索引只支持 = 条件查询,不支持范围查询。
4.2 索引操作
4.2.1 创建索引
语法
db.集合.createIndex(keys, options)
参数 | 描述 |
---|---|
keys | 键值对,格式:{字段: 1或-1},如{age: 1}表示在age字段上的升序索引,-1则为降序索引 |
options | 可选参数,见下表 |
options配置
参数 | 描述 |
---|---|
background | 布尔类型,默认为false。指定是否后台创建索引。建索引的过程中会阻塞其它数据库操作,后台创建则可以避免这种问题 |
unique | 布尔类型,默认false。指定建立的索引是否唯一 |
name | 索引名称。MongoDB默认通过建立索引的字段名和排序顺序生成索引名称 |
示例
单字段索引:对 age
字段建立索引
db.user.createIndex({age: 1})
复合索引:对 age
和 sex
同时创建复合索引
db.user.createIndex({age: 1, sex: -1})
4.2.2 查看索引
返回一个集合中所有的索引
db.集合名.getIndexes()
其中,_id 是默认的索引。
MongoDB在创建集合的过程中,在_id字段上创建一个唯一的索引,名称为 _id_ ,该索引可以防止客户端插入两个具有相同值的文档,该索引不可以被删除。
查看看集合索引大小
db.集合名.totalIndexSize()
4.2.3 删除索引
删除指定索引
db.集合名.dropIndex(索引名称或索引键值对)
如删除age上的升序索引
db.user.dropIndex({age: 1})
或者
db.user.dropIndex("age_1")
删除所有索引
db.集合名.dropIndexes()
该方法并不会将_id索引删除,只能删除_id之外的索引
4.2.4 查询分析
MongoDB 查询分析可以确保我们所建立的索引是否有效。
查询分析常用的方法是 explain()
explain 操作提供了查询信息、使用索引、查询统计等,有利于我们对索引的优化。
先在user中创建age和sex索引
db.user.createIndex({age: 1, sex: 1})
再使用explain对查询进行分析
db.user.find({age: 18, sex: 1, _id: 1}).explain()
> db.user.find({age: 18, sex: 1}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "bbs.user",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"age" : {
"$eq" : 18
}
},
{
"sex" : {
"$eq" : 1
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"age" : 1,
"sex" : -1
},
"indexName" : "age_1_sex_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"age" : [ ],
"sex" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"age" : [
"[18.0, 18.0]"
],
"sex" : [
"[1.0, 1.0]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "iZ2zebq96d1zohii1vadzqZ",
"port" : 27017,
"version" : "4.0.19",
"gitVersion" : "7e28f4296a04d858a2e3dd84a1e79c9ba59a9568"
},
"ok" : 1
}
重点看 stage
和 indexOnly
,这两个字段有时候可能并不会存在。
stage:当值为 COLLSCAN
时,表示全集合扫描,这样的性能是比较低的。当值为 IXSCAN
时,是基于索引扫描,创建索引后我们需要保证查询是基于索引扫描的
indexOnly:为true时表示使用到了索引
4.2.5 覆盖索引查询
覆盖索引查询和MySQL中的类似。当查询条件和所要查询的列全部都在索引中时,MongoDB会直接从索引返回结果。这样的查询性能非常的高
5 Java操作MongoDB
5.1 mongodb-driver
mongodb-driver 是mongodb 官方推出的Java连接MongoDB的驱动包,类似于JDBC驱动。该包操作mongodb非常的不友好,这里只提一下有这个技术,感兴趣的可以自己看菜鸟教程学习一下。
5.2 SpringDataMongoDB
SpringData家族成员之一,酷帅狂拽吊炸天的MongoDB持久层框架,底层封装了mongodb-driver。
5.3 论坛用户功能案例
需求:对用户进行添加、修改、删除、分页查询操作。用户有关注数,表示该用户被关注的数量。
5.3.1 项目搭建
(1)创建项目 bbs,pom.xml引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
(2)application.yml中加入以下配置
spring:
#数据源配置
data:
mongodb:
#主机地址
host: 127.0.0.1
#数据库
database: bbsdb
#默认端口是27017
port: 27017
(3)启动项目,看控制台是否报错
5.3.2 表结构
字段 | 描述 |
---|---|
_id | ID |
name | 姓名 |
age | 年龄 |
sex | 性别 |
address | 地址 |
createdTime | 创建时间 |
state | 状态,1启用0禁用 |
followNum | 关注者数量 |
5.3.3 实体类编写
package com.jg.mongo.pojo;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.io.Serializable;
import java.util.Date;
/**
* 使用 @Document("user") 指定这个类对应 user 集合
* 使用 @CompoundIndex(def = "{'id':1, 'age': -1}") 表示复合索引
*
* @Author: 杨德石
* @Date: 2020/8/13 22:01
* @Version 1.0
*/
@Document("user")
@CompoundIndex(def = "{'i