DBA技术栈MongoDB: 索引和查询优化

news2024/11/27 14:35:38

2.1 批量插入数据

单条数据插入
db.collection.insertOne()
多条数据插入
db.collection.insertMany()

db.inventory.insertMany( [
   { item: "journal", qty: 25, size: { h: 14, w: 21, uom: "cm" }, status: "A" },
   { item: "notebook", qty: 50, size: { h: 8.5, w: 11, uom: "in" }, status: "A" },
   { item: "paper", qty: 100, size: { h: 8.5, w: 11, uom: "in" }, status: "D" },
   { item: "planner", qty: 75, size: { h: 22.85, w: 30, uom: "cm" }, status: "D" },
   { item: "postcard", qty: 45, size: { h: 10, w: 15.25, uom: "cm" }, status: "A" }
]);

插入数据

use testdb
for(var i =1; i<10; i++) db.users.insert({id:i,name: "zhangsan"+i,age: 100+i})

2.2 查询选择器

2.2.1 常规查询方式

最简单的查询语句为:db.customers.find(),按照插入的顺序返回前20个文档,如果 记录总数比20大,则我们可以通过命令“it”获取更多文档。 
> db.users.find({id:9}) 
精确匹配选择器,返回包含键值对id:9的文档。 
> db.users.find({name:"xiaoming",age:101}) 
精确匹配选择器,但查询条件是要返回同时匹配键值对{name:"xiaoming",age:101}的文档。 
> db.users.find({age:{$lt:102}}) 
$lt表示的是小于 
> db.users.find({age:{$lte:102}}) 
$lte表示的小于或等于 
> db.users.find({age:{$gt:105}}) 
$gt表示的是大于 
> db.users.find({age:{$gte:105}}) 
$gte表示的是大于或等于 
> db.users.find({age:{$lt:120,$gte:105}}) 
范围选择器,age:{$lt:120,$gte:119}表示的是小于120,大于或等于119 
> db.users.find({id:{$in:[1,2]}}) 
表示返回key的值在某些value范围内 
> db.users.find({id:{$nin:[1,2]}}) 
$nin表示返回key的值不在某些value范围内,$nin是一种比较低效的査询选择器,它会进行全表扫描,因此最好不要单独使用$nin 
> db.users.find({id:{$ne:1}}) 
$ne表示不等于。单独使用$ne,它也不会利用索引的优势,反而会进行全表扫描,我们最好与其他查询选择器配合使用。 
> db.users.find({$or:[{id:11},{age:109}] }$or表示或运算的选择器,主要用于对两个不同key对应的文档进行连接。 
> db.users.find({$and:[{id:1},{age:109}]}) 
$and表示与运算的选择器,对于两个不同的key,要同时满足条件。 
> db.users.find({id:{$exists:ture}}) 
$exists与关系数据库中的exists不一样,因为MongoDB的表结构不是固定的,有的时候需要返回包含有某个字段的所有记录或者不包含某个字段的所有记录。

2.2.2 索引和查询优化

索引是个与数据存储和査询相关的古老话题,目的只有一个:“提高数据获取的性能”。我们知道一本书的前面几页肯定会有一个目录,这个目录式的索引能使我们快速査询想看的内容索引保存在哪里,是个什么样的数据结构,计算机领域的索引无外乎也是这两个主题。
image.png
数据库保存记录的机制是建立在文件系统上的,索引也是以文件的形式存储在磁盘上,在数据库中用到的最多的索引结构就是B树。尽管索引在数据库领域是不可缺少的,但是对一个表建立过多的索引也会带来一些问题,索引的建立要花费系统时间,同时索引文件也会占用磁盘空间。
**索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。**扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。
MongoDB索引的数据结构也是B+树,它能存储一小部分集合的数据,具体来说就是存储集合中建有索引的一个或多个字段的值,而且按照值的升序或降序排列。对于一个查询来说,如果存在合适的索引,MongoDB能够利用这个索引减少文档的扫描数量。
如图所示查询低于30岁的用户,不用去扫描全部文档,通过索引快速返回结果,这样查询的效率是很高的。
image.png

单字段索引

MongoDB默认为所有集合都创建了一个_id字段的单字段索引,而且这个索引是唯一的,不能被删除,_id字段作为一个集合的主键,值是唯一的,对于一个集合来说,也可以在其他字段上创建单字段的唯一索引。
创建单一键索引:db.collection.createIndex( { : } ),其中 是你要创建索引的字段名, 是索引类型,例如:1(升序)或 -1(降序)。

插入数据
for(var i = 1;i < 10;i++) db.custoners.insert({name:"zhangsan"+i,province:"liaoning"})
for(var i = 1;i < 10;i++) db.customers.insert({name:"lisi"+i,province:"fujian"})
for(var i = 1;i < 10;i++) db.customers.insert({name:"niuer"+i,province:"guangdong"})
for(var i = 1;i < 10;i++) db.customers.insert({name:"wangwu"+i,province:"Hunan"})
for(var i = 1;i < 10;i++) db.customers.insert({name:"liyi"+i,province:"Sichuan"})

image.png

创建索引

建立单字段唯一索引或者去掉{unique:true}选项就是一个普通的单字段索引
db.customers.createIndex({name:1},{unique:true})

1表示升序创建索引,-1表示降序创建索引。

image.png

通过explain查看执行计划

MongoDB中的explain()方法用于显示查询执行计划,它可以帮助我们了解MongoDB如何执行一个查询。
执行explain()方法后,MongoDB将返回一个对象,该对象描述了查询执行的过程,包括查询的阶段、输入输出、使用的索引等信息。
这个对象通常包含以下字段:

  1. stages:查询执行的阶段列表,每个阶段描述了查询的一部分执行过程。
  2. input:查询输入的文档数量。
  3. output:查询输出的文档数量。
  4. millis:查询执行的时间(毫秒)。
  5. executionStats:更详细的执行统计信息。

其中,stages字段是最重要的,它描述了查询从开始到结束的所有阶段。每个阶段都有一个type字段,描述了这个阶段的类型,比如:

  • COLLSCAN:扫描整个集合。
  • IXSCAN:扫描索引。
  • SHARD_MERGE:合并从多个分片返回的结果。

通过查看stages字段,我们可以了解查询使用了哪些索引,是否有更好的优化方案等。
需要注意的是,explain()方法返回的结果包含了大量的详细信息,对于普通用户来说可能比较难以理解。通常我们只需要关注stages字段,以及其中的type值为IXSCAN的阶段,因为这是查询执行的关键阶段。

没走索引查询,查询使用了COLLSCAN阶段扫描了整个集合,但是并没有使用到索引。
image.png

命中索引进行查询
image.png

复合索引

创建复合索引:db.collection.createIndex( { : , : } ),其中 和 是你要创建索引的字段名, 和 是索引类型,
例如:1(升序)或 -1(降序)。
请注意,创建索引可能需要一些时间,具体取决于你的数据量及系统性能。同时,创建过多的索引可能会对写入性能产生负面影响,因此需要谨慎考虑。
image.png

> db.customers.find({"name" : "liyi6", "province" : "Sichuan"}).explain()
{
	"explainVersion" : "1",
	"queryPlanner" : {
		"namespace" : "sample_mflix.customers",
		"indexFilterSet" : false,
		"parsedQuery" : {
			"$and" : [
				{
					"name" : {
						"$eq" : "liyi6"
					}
				},
				{
					"province" : {
						"$eq" : "Sichuan"
					}
				}
			]
		},
		"queryHash" : "AE1EB7A5",
		"planCacheKey" : "C0AA3338",
		"maxIndexedOrSolutionsReached" : false,
		"maxIndexedAndSolutionsReached" : false,
		"maxScansToExplodeReached" : false,
		"winningPlan" : {
			"stage" : "FETCH",
			"inputStage" : {
				"stage" : "IXSCAN",
				"keyPattern" : {
					"name" : 1,
					"province" : 1
				},
				"indexName" : "name_1_province_1",
				"isMultiKey" : false,
				"multiKeyPaths" : {
					"name" : [ ],
					"province" : [ ]
				},
				"isUnique" : false,
				"isSparse" : false,
				"isPartial" : false,
				"indexVersion" : 2,
				"direction" : "forward",
				"indexBounds" : {
					"name" : [
						"[\"liyi6\", \"liyi6\"]"
					],
					"province" : [
						"[\"Sichuan\", \"Sichuan\"]"
					]
				}
			}
		},
		"rejectedPlans" : [ ]
	},
	"command" : {
		"find" : "customers",
		"filter" : {
			"name" : "liyi6",
			"province" : "Sichuan"
		},
		"$db" : "sample_mflix"
	},
	"serverInfo" : {
		"host" : "13727b89dec5",
		"port" : 27017,
		"version" : "5.0.5",
		"gitVersion" : "d65fd89df3fc039b5c55933c0f71d647a54510ae"
	},
	"serverParameters" : {
		"internalQueryFacetBufferSizeBytes" : 104857600,
		"internalQueryFacetMaxOutputDocSizeBytes" : 104857600,
		"internalLookupStageIntermediateDocumentMaxSizeBytes" : 104857600,
		"internalDocumentSourceGroupMaxMemoryBytes" : 104857600,
		"internalQueryMaxBlockingSortMemoryUsageBytes" : 104857600,
		"internalQueryProhibitBlockingMergeOnMongoS" : 0,
		"internalQueryMaxAddToSetBytes" : 104857600,
		"internalDocumentSourceSetWindowFieldsMaxMemoryBytes" : 104857600
	},
	"ok" : 1
}

数组的多键索引

注意,创建索引可能需要一些时间,具体取决于你的数据量和系统性能。同时,创建过多的索引可能会对写入性能产生负面影响,因此需要谨慎考虑。
tags 的数组字段为例,展示多键索

> for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"liyi"+i,"tags": ["sports", "music", "movies"]})
WriteResult({ "nInserted" : 1 })
> for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"liyao"+i,"tags": ["sports", "movies","games","read"]})
WriteResult({ "nInserted" : 1 })
> for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"lisi"+i,"tags": ["sports", "music", "movies"]})
WriteResult({ "nInserted" : 1 })
> for(var i = 1;i < 10;i++) db.ccustomers.insert({name:"liyiyi"+i,"tags": ["sports",  "movies","write"]})
WriteResult({ "nInserted" : 1 })
> db.ccustomers.createIndex({"tags":1})
{
	"numIndexesBefore" : 1,
	"numIndexesAfter" : 2,
	"createdCollectionAutomatically" : false,
	"ok" : 1
}

explain
image.png

查询结果
image.png

查询优化

MongoDB查询优化的方法主要有以下几点:

  1. 用合适的索引:索引是提高查询性能的关键。MongoDB支持多种索引类型,如单一键索引、复合索引、文本索引、地理空间索引等。在设计数据库时,应根据数据的特性和查询需求选择合适的索引类型。同时,也要注意索引的使用,尽量使用已经创建的索引,避免全集合扫描。
  2. 优化查询语句:查询语句的设计也会影响查询性能。应尽量避免使用不等于操作符、模运算符等导致全集合扫描的操作符。同时,应使用投影查询,减少返回的字段,减少数据传输和处理的开销。
  3. 批量操作:批量操作可以减少IO操作次数,提高性能。例如批量插入、批量更新、批量删除等。
  4. 使用缓存:使用缓存可以避免重复查询,提高查询性能。
  5. 优化数据结构:数据结构的设计也会影响查询性能。应尽量选择合适的数据类型,避免使用嵌套文档和数组,提高查询效率。
  6. 调整系统参数:根据系统性能和硬件配置调整MongoDB的配置参数,例如内存、磁盘、网络等参数。
  7. 使用分析工具:使用MongoDB提供的分析工具,如explain()、profile()等,可以了解查询性能,找出优化点。

位慢查询的方法是打开数据库的监视功能,它默认是关闭的,我们可以通过下面的命令打开。

db.setProfilingLevel(level,[ slowms]) 

参数:
level是监视级别。
值为0表示关闭数据库的监视功能
值为1表示只记录慢查询
值为2表示记录所有的操作
slowms为可选参数,设定慢查询的阈值。
所有监视的结果都将保存到一个特殊的集合system.profile中。

> db.setProfilingLevel(2)
{ "was" : 0, "slowms" : 100, "sampleRate" : 1, "ok" : 1 }
> db.system.profile.find()

实操记录:
一个走索引和没有走索引的查询
image.png
打开查看查询记录:
image.png
image.png

2.3 总结

MongoDB可以在一个集合上建立一个或多个索引,而且必须为在字段_id建立一个索引,建索引的目的与关系数据库一样,就是为了提高对数据库的查询效率;
一旦索引创建好,MongoDB会自动地根据数据的变化维护索引,如果索引太大而不能全部保存在内存中,将被移到磁盘文件上,这样会影响查询性能,因此要时刻监控索引的大小,保证合适的索引在内存中;
监控一个查询是否用到索引,可以在查询语句后用explain命令或profile()方式进行监控。并不是所有的字段都要建立索引,我们应该根据自己业务所涉及的查询,建立合适的索引;
如果系统有大量的写操作,由于需要维护索引的变化,会导致系统性能降低。我们在对大数据建立索引时最好在后台进行,否则会导致数据库停止响应。要注意虽然我们在某些字段上建了索引,但是查询时可能用不上索引,如使用 n e 和 ne和 nenin表达式等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1399532.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据大咖都在考CDMP,你呢?

&#x1f30d;全球通行证&#xff1a;无论走到哪里&#xff0c;CDMP都是你数据治理领域的“全球绿卡”&#xff0c;让你无惧地域限制&#xff0c;畅游数据世界&#xff01; &#x1f3c6;权威认证&#xff0c;业界标杆&#xff1a;DAMA国际2004年推出的CDMP认证&#xff0…

C++——函数的调用

1&#xff0c;函数功能的调用 功能&#xff1a;使用定义好的函数 语法&#xff1a;函数名&#xff08;参数&#xff09; 示例&#xff1a; #include<bits/stdc.h> using namespace std; //定义加法函数 int add(int num1,int num2){int sumnum1num2;return sum; …

一文2500字Robot Framework自动化测试框架超强教程

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

[3D]菜板上的鱼

本来想画条鲨鱼&#xff0c;结果成了条菜板上的鱼。 VS&#xff01; ** VS&#xff01; ** 【扭曲】更像菜板上的鱼了。

【原文链接】Tri-Perspective View for Vision-Based 3D Semantic Occupancy Prediction

原文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2023/papers/Huang_Tri-Perspective_View_for_Vision-Based_3D_Semantic_Occupancy_Prediction_CVPR_2023_paper.pdf 1. 引言 体素表达需要较大的计算量和特别的技巧&#xff08;如稀疏卷积&#xff09;&…

Docker-数据卷网络

docker数据卷 docker volume ls #查看有哪些数据卷 docker volume inspect mysql-db #查看具体数据卷的元信息 docker container run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORDTrue -v mysql-db:/var/lib/mysql mysql #会在docker 的卷下面新建一个mysqldb用于数据持久…

会体言一心文-码代-4202

简明版本 最近感悟就是在“常规赛”中&#xff0c;大部分奇技淫巧远不如官方教程。 我使用大模型工具快一年的时间所积累的经验远不如认真看看官方教程。 官方教程 里面有一点就可以秒99%的工具人&#xff0c;“文心一言7*24小时在线&#xff0c;伴你左右。 ” 结合文心一言…

opencv中初学者必须了解的5个函数-灰度化、模糊、Canny边缘检测、膨胀和侵蚀

opencv中初学者必须了解的5个函数-灰度化、模糊、边缘检测、膨胀和侵蚀 使用OpenCV可以对彩色原始图像进行基本的处理&#xff0c;涉及到5个常用的处理&#xff1a; 灰度化 模糊处理 Canny边缘检测 膨胀 腐蚀 原图test.png如下所示&#xff1a; 可以直接去https://github…

WEB接口测试之Jmeter接口测试自动化 (三)(数据驱动测试)

接口测试与数据驱动 1简介 数据驱动测试&#xff0c;即是分离测试逻辑与测试数据&#xff0c;通过如excel表格的形式来保存测试数据&#xff0c;用测试脚本读取并执行测试的过程。 2 数据驱动与jmeter接口测试 我们已经简单介绍了接口测试参数录入及测试执行的过程&#xff0…

集美大学“第15届蓝桥杯大赛(软件类)“校内选拔赛 H卯酉东海道

dijk spfa思想 然后你需要存一下每个点 * l种颜色&#xff0c;你开个数组存一下 st[i][j] 为到达i点且到达以后是j颜色的最小距离是否已经确定了 #include<bits/stdc.h> using namespace std; using ll long long; const int N 3e510; struct Edge{ll to,col,w;bool …

k8s-ingress一

Comfigmap&#xff1a;存储数据 Date&#xff1a; Key&#xff1a;value 挂载的方式&#xff0c;把配置信息传给容器 生产当中的yml文件很长&#xff1a; 有deployment 容器的探针 资源限制 Configmap 存储卷 Service Ingress K8s的对外服务&#xff0c;ingress Se…

10分钟完成权限系统全流程开发

背景 首先问下chatgpt,权限系统的模型有哪些&#xff1f; 基于上述的结论&#xff0c;我们选择基于角色的访问控制(RBAC)&#xff0c;请从数据库设计、接口文档、代码实现、单元测试四个方面分别详细描述每个部份需要实现的内容。 数据库实现 针对上述的数据库设计部份&#…

zoj 3494 BCD Code 数位DP + AC自动机

BCD Code 题意 将十进制数的每一位数位转化成一个 4 4 4 位的二进制数&#xff0c;并给定一些 禁止码&#xff0c;规定符合条件的数字的二进制表示中不能包含连续的某个禁止码。问 [ l , r ] [l,r] [l,r] 中有多少个符合条件的数字 思路 朴素的数位 D P DP DP 只涉及少量…

c++:通讯录的实现

大家可以先下载一下这篇文章的资源绑定的exe文件&#xff08;免费&#xff09;&#xff0c;体验下通讯录是如何运行的。 目录 完整代码 整体思路 功能主体部分 菜单 创建联系人结构体和通讯录的结构体 各个函数功能实现部分 添加联系人 显示联系人 删除联系人 查找联…

pytest实现多进程与多线程运行超好用的插件

前言 如果想分布式执行用例&#xff0c;用例设计必须遵循以下原则&#xff1a; 1、用例之间都是独立的&#xff0c; 2、用例a不要去依赖用例b 3、用例执行没先后顺序&#xff0c; 4、随机都能执行每个用例都能独立运行成功每个用例都能重复运行&#xff0c;不影响其它用例 这…

顶顶通用户申请和安装 空号识别 模块流程

一、申请 空号识别 授权 打开网址&#xff1a;http://my.ddrj.com&#xff0c;注册并登录。 点击“我的授权” -> “申请授权” &#xff08;根据负责人的要求选择“在线”或是“离线”&#xff09;。 找到名称为空号识别的授权并点击“加号”图标打开授权&#xff0c;然…

Hive数仓框架详解

Hive框架详解 1、Hive的介绍 ​ Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供类SQL查询功能。 ​ 本质是将SQL转换为MapReduce程序。 ​ 主要用途&#xff1a;用来做离线数据分析&#xff0c;比直接用MapRed…

百度大脑 使用

百度大脑&#xff1a; 官方网址&#xff1a;https://ai.baidu.com/ 文档中心&#xff1a;https://ai.baidu.com/ai-doc 体验中心&#xff1a;https://ai.baidu.com/experience 百度大脑则是百度AI核心技术引擎&#xff0c;它包括基础层、感知层、认知层和安全&#xff0c;是百…

Codeforces Round 803 (Div. 2) E. PermutationForces II(思维题 位置序列)

题目 给定长为n(n<2e5)的两个序列a和b&#xff0c; a为n的一个排列&#xff0c; b也为n的一个排列&#xff0c;但有一些位置被-1替换了&#xff0c;保证没被替换的位置在[1,n]之间且两两不同 你有一个距离最大限制s&#xff0c;你可以执行n次操作&#xff0c; 第i次操作…

【爬虫实战】2024知乎热榜可视化爬取

项目功能简介&#xff1a; 1.支持配置&#xff1b; 2.单次爬取&#xff1b; 3.循环爬取&#xff1b; 4.爬虫暂停&#xff1b; 5.数据清除&#xff1b; 6.数据保存到csv文件&#xff1b; 7.程序支持打包成exe文件&#xff1b; 8.项目操作说明文档&#xff1b; 9.模块封装到类&a…