前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >multi-key索引和wildCard索引场景比较

multi-key索引和wildCard索引场景比较

作者头像
MongoDB中文社区
发布2022-01-26 14:47:44
1.4K0
发布2022-01-26 14:47:44
举报
文章被收录于专栏:MongoDB中文社区MongoDB中文社区

本文来自获得《2021MongoDB技术实践与应用案例征集活动》优秀案例奖作品

作者:雷彻

引文

MongoDB早期版本支持multi-key索引,加快数组检索,很受程序员喜欢;在4.2版本又推出了wildCard索引,支持object和数组检索。这两种索引有相似之处,但在功能上wildCard更强大。日常工作中,有同学对这两种索引的使用场景比较模糊,因此在这里抛砖引玉,供大家借鉴。

Multi-key index

multi-key 支持对数组的高效查询。

举例:

代码语言:javascript
复制
db.employee1.insertMany([
{"name":"xiaoming","age":25,"ctime":new ISODate(),goodAt:
["mongodb","hbase","c++"]},{"name":"xiaohong","age":28,"ctime":new
ISODate(),goodAt:["es","java","c++"]},{"name":"xiaoguang","age":29,"ctime":new
ISODate(),goodAt:["mysql","c++","mongodb"]}
])
--index
db.employee1.createIndex({goodAt:1})
--查找
db.employee1.find({"goodAt":"mysql"})

explain的结果中,winningPlan.inputStage.stage为IXSCAN ,走索引goodAt_1。这里字

段"mysql"是一个完整的数组元素。下面再做两个测试:

侵入查询测试

如果数组元素为json串,不能通过multi-key索引查询某个元素的属性

代码语言:javascript
复制
db.employee1.insertMany([{
"name":"a",
"age":25,
"ctime":new ISODate(),
"goodAt":[
 {database:"mysql", lang:"c++"},
 {database:"hbase",lang:"java"}, 
 {database:"tidb",lang:"golang"}
 ]
}])
--截取json属性,不支持;db.employee1.find({"goodAt":{"database":"mysql"}}).explain() /**走索引,结果为
空,没有满足条件的元素**/
db.employee1.find({"goodAt":{"database":"mysql", "lang" : "c++" }}).explain() 
/**走索引,结果不为空**

建议使用如下写法:

代码语言:javascript
复制
 --递归
db.employee1.find({"goodAt.database":"mysql"}).explain() /**不走索引,结果不为空
**/

如果要查询database字段,只能对 goodAt.database 加索引

代码语言:javascript
复制
db.employee1.createIndex({"goodAt.database":1})
db.employee1.find({"goodAt.database":"mysql"}).explain() /**走索引,结果不为空
**/

tips:

  • multi-key适用于对数组进行索引
  • 不能对数组进行哈希
  • 不支持对嵌套的对象进行查询;

WildCard index

在上文中,查询数组元素某个字段,就需要对字段单独加索引,用起来很不方便。在MongoDB4.2版本引入了wildCard索引,支持对象,数组的检索,并且可以侵入元素内部遍历,非常方便。

多属性集合,ok:{k1:v1,k2:v2},对ok建索引

举例:

代码语言:javascript
复制
db.employee2.insertMany([
{
"name":"xiaoming",
"age":25,
"ctime":new ISODate(),
"goodAt":{
"database":["mongodb","hbase"],
"programLanguage":"c++"
}
},
{
"name":"xiaohong",
"age":28,
此时尚未建索引,查询goodAt某个属性,可以看到stage为COLLSCAN
添加wildCard索引后
"ctime":new ISODate(),
"goodAt":{
"database":"mysql",
"programLanguage":"java",
"middleAware":"zookeeper"
}
},
{
"name":"xiaoguang",
"age":29,
"ctime":new ISODate(),
"goodAt":{
"database":"mongodb",
"programLanguage":"python",
"web":"nodejs"
}
}
])

此时尚未建索引,查询goodAt某个属性,可以看到stage为COLLSCAN

代码语言:javascript
复制
db.employee2.find({"goodAt.database": "mysql"}).explain()

添加wildCard索引后

代码语言:javascript
复制
--对goodAt建索引
db.employee2.createIndex({ "goodAt.$**": 1 })
db.employee2.find({"goodAt.database": "mongodb"}).explain()

在元素"name":"xiaoming"中,goodAt.database字段的值为数组,我们看看能否走索引匹配

代码语言:javascript
复制
db.employee2.find({"goodAt.database": "mongodb"}).explain()

wildCard索引也支持一个multi-key索引,可以对其中的数组元素进行索引匹配。

侵入查询测试

进一步在wildCard索引中的数组元素下,添加对象,能否走索引?我们在goodAt.database属性中,增加数组属性,做属下测试,目标是确认wildCard能否在数组中递归;

代码语言:javascript
复制
db.employees2.insert(
{
"name":"xiaohong1",
"age":29,
"ctime":new ISODate(),
"goodAt":{
"database":[{"rdb":"mysql"},
 {"nosql":["mongodb","redis"]},
 {"newsql":"tidb"}
 ],
"programLanguage":"go"
 }
})
db.employee2.find({"goodAt.database.nosql": "mongodb"}).explain()

显然,wildCard索引支持对数组元素中的检索。

代码语言:javascript
复制
db.employees2.insert(
{
"name":"a",
"age":29,
"ctime":new ISODate(),
"goodAt":{
"database":{"rdb":"mysql","nosql":"mongodb","newsql":"tidb"},
"programLanguage":"go"
 }
})
db.employee2.find({"goodAt.database.nosql": 1}).explain()

再回到我们multi-key中的例子,把索引改为wildCard,是否可行?

代码语言:javascript
复制
db.employee1.dropIndexes('goodAt_1')
db.employee1.createIndex({ "goodAt.$**": 1 })
db.employee1.find({"goodAt.database":"mysql"}).explain()

可以满足需求。注意:

  • wildCard不能支持两层以上的数组嵌套
  • wildCard也不支持对如下查询的索引访问
代码语言:javascript
复制
db.employee1.find({"goodAt":{"database":"mysql"}}).explain()

查询子属性,建议使用 {"goodAt.database":1} 而不是 {goodAt:{"database":1}} ,对索引更友 好。

小结

multi-key和wildCard索引分别适用不同的场景,让entry建模变得更加简单。在使用时,需要注意:

  • multi-key索引主要加快数组遍历,功能纯粹;
  • wildCard可以侵入遍对象或数组内部,避免单属性创建索引,更加灵活;
  • wildCard不会遍历连续嵌套两层以上的数组;
  • 不建议太多层嵌套,尽量控制在3层以内;

关于作者:雷彻

搜狐集团数据库团队高级运维工程师,具有丰富的数据库运维经验,精通数据库架构设计、性能优化及故障诊断,目前负责MySQL及MongoDB运维管理工作,并参与公司数据库云平台开发建设,将运维经验集成到公司数据库云平台中。专注于CDC服务构建。愿和大家多交流学习,为社区贡献一份力量!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Mongoing中文社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档