文章目录

  • MongoDB大数据查询优化
  • 索引基础
  • 比较有无创建索引查询速度
  • 复合索引
  • 唯一索引
  • MongonDB账户权限配置
  • MongoDB账户权限配置中常用的命令
  • 数据库角色
  • 连接数据库的时候需要配置账户密码
  • 关系型数据库中表与表的关系
  • 一对一的关系
  • 一对多的关系
  • 多对多的关系
  • MongoDB高级查询aggregate聚合管道
  • MongoDB聚合管道(Aggregation Pipeline)
  • 测试
  • $project
  • $match
  • $group
  • $sort
  • $limit
  • $skip
  • $lookup 表关联


MongoDB大数据查询优化

索引基础

索引是对数据库表中的一列或多列的值进行排序的一种结构,可以让我们查询数据库变得更快。MongoDB的索引几乎与传统关系型数据库一模一样,这其中也包括一些基本的查询优化技巧。

  • 下面是创建索引的命令
db.user.ensureIndex({"username":1});
  • 获取当前集合的索引
db.user.getIndexes()
  • 删除索引的命令是
db.user.dropIndex({"username":1})

比较有无创建索引查询速度

  1. 首先进入数据库,使用for循环创建80000条数据:

mongo聚合不走索引 mongodb聚合查询优化_数据

  1. 使用如下语句显示查询时间:
db.dog.find({"dogName":"xiaohua50000"}).explain("executionStats")

mongo聚合不走索引 mongodb聚合查询优化_mongo聚合不走索引_02


mongo聚合不走索引 mongodb聚合查询优化_数据_03

  1. 创建索引:

mongo聚合不走索引 mongodb聚合查询优化_一对一_04

  1. 再次换一个数据查询:

mongo聚合不走索引 mongodb聚合查询优化_数据库_05


mongo聚合不走索引 mongodb聚合查询优化_数据库_06

我们可以看到创建索引后查询速度变快了很多

  1. 删除索引,再查看我们的查询时间:

mongo聚合不走索引 mongodb聚合查询优化_数据_07


mongo聚合不走索引 mongodb聚合查询优化_mongo聚合不走索引_08

复合索引

db.dog.ensureIndex({"dogName":1,"age":-1}) //1表示升序,-1表示降序
  • 该索引被创建后,基于dogName和age的查询将会用到该索引,或者是基于dogName的查询也会用到该索引。
  • 但是只是基于age的查询将不会用到该复合索引。因此可以说,如果想用到复合索引,必须在查询条件中包含复合索引的前N个索引列。
  • 然而如果查询条件中的键值顺序和复合索引中的创建顺序不一致的话,MongoDB可以智能的帮助我们调整该顺序,以便使复合索引可以为查询所用。如:
db.dog.find({"age":30,"dogName":"stephen"})

唯一索引

  • 下面的示例将创建唯一索引,如:
db.dog.ensureIndex({"age":1},{"unique":true})
  • 如果再次插入age重复文档时,MongoDB将会报错,以提示插入重复键,如:
db.dog.insert({"age":100001})
db.dog.insert({"age":100001})

E11000 duplicate key err index:dog.dog.$age_1 dup key:{:100001.0}

MongonDB账户权限配置

  1. 创建超级管理员:
use admin

db.createUser({
	user:'admin',
	pwd:'123456',
	roles:[{role:'root',db:'admin'}]
})
  1. 修改MongoDB数据库配置文件。
  2. 重启mongdb服务。
  3. 用超级管理员管理账户连接数据库。
mongo admin -u 用户名 -p 密码

mongo 192.168.1.200:27017//test -u username -p password   //远程
  1. 给aniu数据库常见一个用户,只能访问aniu不能访问其他数据库。
use aniu

db.createUser({
	user:"aniuadmin",
	pwd:"123456",
	roles:[{role:"dbOwner",db:"aniu"}]
})

mongo聚合不走索引 mongodb聚合查询优化_数据库_09

MongoDB账户权限配置中常用的命令

1、show users;   查看当前库下的用户
2、db.dropUser("aniu111");   删除用户
3、db.updataUser("admin",{pwd:"password"});   修改用户密码
4、db.auth("admin","password");   密码认证

数据库角色

  1. 数据库用户角色:read、readWrite;
  2. 数据库管理角色:dbAdmin、dbOwner、userAdmin;
  3. 集群管理角色:clusterAdmin、clusterManager、clusterMonitor、hostManager;
  4. 备份恢复角色:backup、restore;
  5. 所有数据库角色:readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase;
  6. 超级用户角色:root

连接数据库的时候需要配置账户密码

const url = 'mongodb://admin:123456@localhost:27017';

关系型数据库中表与表的关系

一对一的关系

  • 例如:一个人对应一个唯一的身份证号,即为一对一关系。

一对多的关系

  • 例如:一个班级有多个学生,一个学生只能属于一个班级。

多对多的关系

  • 一个学生可以选多门课程,而同一门课程可以被多个学生选修,彼此的对应关系即是多对多关系。

MongoDB高级查询aggregate聚合管道

MongoDB聚合管道(Aggregation Pipeline)

  • 使用局和管道可以对集合中的文档进行变换和组合。
  • 语法
    aggregate() 方法的基本语法格式如下所示:
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
  • 实际项目中用于:表的关联查询、数据的统计。

mongo聚合不走索引 mongodb聚合查询优化_mongo聚合不走索引_10

这里我们介绍一下聚合框架中常用的几个操作:

  • $project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
  • $match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
  • $limit:用来限制MongoDB聚合管道返回的文档数。
  • $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
  • $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
  • $group:将集合中的文档分组,可用于统计结果。
  • $sort:将输入文档排序后输出。
  • $geoNear:输出接近某一地理位置的有序文档。

下表展示了一些聚合的表达式:

表达式

描述

实例

$sum

计算总和。

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}])

$avg

计算平均值

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}])

$min

获取集合中所有文档对应值得最小值。

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}])

$max

获取集合中所有文档对应值得最大值。

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : {likes"}}}])

$push

在结果文档中插入值到一个数组中。

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : {url"}}}])

$addToSet

在结果文档中插入值到一个数组中,但不创建副本。

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : {url"}}}])

$first

根据资源文档的排序获取第一个文档数据。

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : {url"}}}])

$last

根据资源文档的排序获取最后一个文档数据

db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : {url"}}}])

测试

模拟数据:

> db.order.find()
{ "_id" : ObjectId("5f48c087f6f819aca2112b34"), "order_id" : "1", "uid" : 10, "trade_no" : "111", "all_price" : 100, "all_num" : 2 }
{ "_id" : ObjectId("5f48c0b3f6f819aca2112b35"), "order_id" : "2", "uid" : 7, "trade_no" : "222", "all_price" : 90, "all_num" : 2 }
{ "_id" : ObjectId("5f48c194f6f819aca2112b36"), "order_id" : "3", "uid" : 9, "trade_no" : "333", "all_price" : 20, "all_num" : 6 }

> db.order_item.find()
{ "_id" : ObjectId("5f48c1e7f6f819aca2112b37"), "order_id" : "1", "title" : "商品鼠标1", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5f48c1f6f6f819aca2112b38"), "order_id" : "1", "title" : "商品键盘2", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5f48c208f6f819aca2112b39"), "order_id" : "2", "title" : "牛奶", "price" : 50, "num" : 1 }
{ "_id" : ObjectId("5f48c216f6f819aca2112b3a"), "order_id" : "2", "title" : "酸奶", "price" : 40, "num" : 1 }
{ "_id" : ObjectId("5f48c231f6f819aca2112b3b"), "order_id" : "3", "title" : "矿泉水", "price" : 2, "num" : 5 }
{ "_id" : ObjectId("5f48c242f6f819aca2112b3c"), "order_id" : "3", "title" : "毛巾", "price" : 10, "num" : 1 }

在我们的数据库中建立一个叫order的表以及一个叫order_item的表。加入以上的数据。

$project

修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	}
])

mongo聚合不走索引 mongodb聚合查询优化_数据_19

$match

用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}} 
	}
])

mongo聚合不走索引 mongodb聚合查询优化_数据库_20

$group

将集合中的文档分组,可用于统计结果。

db.order_item.aggregate([
	{
		$group:{_id:"$order_id",total:{$sum:"$num"}}
	}
])

mongo聚合不走索引 mongodb聚合查询优化_数据库_21

db.order_item.aggregate([
	{
		$group:{_id:"$order_id",total:{$sum:"$price"}}
	}
])

mongo聚合不走索引 mongodb聚合查询优化_数据库_22

$sort

将输入文档排序后输出。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}}
	},
	{
		$sort:{"all_price":-1}
	}
])

mongo聚合不走索引 mongodb聚合查询优化_数据库_23

$limit

用来限制MongoDB聚合管道返回的文档数。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}}
	},
	{
		$sort:{"all_price":-1}
	},
	{
		$limit:1
	}
])

mongo聚合不走索引 mongodb聚合查询优化_数据_24

$skip

在聚合管道中跳过指定数量的文档,并返回余下的文档。

db.order.aggregate([
	{
		$project:{trade_no:1,all_price:1}
	},
	{
		$match:{"all_price":{$gte:90}}
	},
	{
		$sort:{"all_price":-1}
	},
	{
		$skip:1
	}
])

mongo聚合不走索引 mongodb聚合查询优化_数据_25

$lookup 表关联

db.order.aggregate([
	{
		$lookup:
			{
			from:"order_item",
			localField:"order_id",
			foreignField:"order_id",
			as:"items"
			}
	}
])

mongo聚合不走索引 mongodb聚合查询优化_mongo聚合不走索引_26

得到的数据:

{
	"_id": ObjectId("5f48c087f6f819aca2112b34"),
	"order_id": "1",
	"uid": 10,
	"trade_no": "111",
	"all_price": 100,
	"all_num": 2,
	"items": [{
		"_id": ObjectId("5f48c1e7f6f819aca2112b37"),
		"order_id": "1",
		"title": "商品鼠标1",
		"price": 50,
		"num": 1
	}, {
		"_id": ObjectId("5f48c1f6f6f819aca2112b38"),
		"order_id": "1",
		"title": "商品键盘2",
		"price": 50,
		"num": 1
	}]
} 

{
	"_id": ObjectId("5f48c0b3f6f819aca2112b35"),
	"order_id": "2",
	"uid": 7,
	"trade_no": "222",
	"all_price": 90,
	"all_num": 2,
	"items": [{
		"_id": ObjectId("5f48c208f6f819aca2112b39"),
		"order_id": "2",
		"title": "牛奶",
		"price": 50,
		"num": 1
	}, {
		"_id": ObjectId("5f48c216f6f819aca2112b3a"),
		"order_id": "2",
		"title": "酸奶",
		"price": 40,
		"num": 1
	}]
} 

{
	"_id": ObjectId("5f48c194f6f819aca2112b36"),
	"order_id": "3",
	"uid": 9,
	"trade_no": "333",
	"all_price": 20,
	"all_num": 6,
	"items": [{
		"_id": ObjectId("5f48c231f6f819aca2112b3b"),
		"order_id": "3",
		"title": "矿泉水",
		"price": 2,
		"num": 5
	}, {
		"_id": ObjectId("5f48c242f6f819aca2112b3c"),
		"order_id": "3",
		"title": "毛巾",
		"price": 10,
		"num": 1
	}]
}

即将表orde_item数据关联到表order中。