Mongodb

索引简介

索引的创建和分析

  • 分析语句db.index_test.find({'name': 'yjvud'}).explain() 不是很靠谱,和文档里面展示的内容不同没看出什么信息
  • 创建索引db.index_test.ensureIndex({'name': 1}) 创建后再进行分析查看,可以看到索引方案被使用了
  • 创建复合索引db.index_test.ensureIndex({'age': 1, 'name': 1})
    • Mongo里面复合索引逆序不能生效,也就是说上面的索引只能通过年龄定位后顺序的拿出名称,要从z-a的获取名称的话效率就很低了,需要再创建一个索引db.index_test.ensureIndex({'age': 1, 'name': -1}),当然单个索引不需要,这个后面看具体的数据结构就知道原因了
  • 覆盖索引,和mysql里面一样存在回表操作
  • 隐式索引,复合索引同样存在前缀原则,这些属于隐式索引

$操作符如何使用索引

使用经验太少,结论是用这个操作符之后大多数的操作不一定能使用索引,使用的时候最好进行确认

  • $where和$exists无法使用索引
  • 范围查询,使用复合索引的时候尽量将精确匹配的条件放到前面,其实就是通过一个个字段来尽量缩小查询范围
  • $or查询,mongo中一次查询只能使用一个索引,但是如果两个语句通过or进行连接的时候可以使用两个索引,本质可以看成两次查询,然后将查询结果进行合并

索引对象和数组

索引嵌套文档

1
2
3
4
5
6
7
8
{
"username": "sid",
"loc": {
"ip": "1.2.3.4",
"city": "Springfield",
"state": "NY"
}
}
  • 对于这样一个文档,可以为之字段创建索引db.users.ensureIndex({"loc.city" : 1}),其索引结构和普通索引没有区别
  • 当然也可以对整个嵌套文档建立索引db.users.ensureIndex({"loc" : 1}),不过这个时候只有使用与子文档字段顺序完全匹配的查询才能使用该索引db.users.find({"loc" : {"ip" : "123.456.789.000", "city" : "Shelbyville", "state" : "NY"}}}))

索引数组

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"title": "hello",
"comments": [
{
"date": "20220101",
"content": "sb"
},
{
"date": "20220102",
"content": "just so so"
}
]
}
  • 对数组中的元素创建索引db.blog.ensureIndex({"comments.date" : 1}),比如获取一段时间内评论次数最多的文章,这个时候会将数组中的每个元素都创建索引条目(数量规模会很大)
  • 与上面的嵌套文档不同,不能把数组作为一个实体创建索引,db.blog.ensureIndex({"comments" : 1})这个时候实际上是对数组中的每个字段创建索引
  • 数组上创建的索引并不包含位置信息,也就是说无法通过下角标对数据进行过滤,比如comments.4
  • 为了避免数据爆炸增长,mongo不允许一个索引中出现多个数组字段,假如创建索引{"x" : 1, "y" : 1},这个时候x和y不能同时为数组,注意两个都可以是数组元素,只是不能同时为数组
  • 多键索引,对于索引的键,如果某个文档中这个键的内容是一个数组,那这个索引会被标记为多键索引,即使后续所有数组文档都被删除也不会变回非多键索引,只有把索引删除再重建;多键索引可能会比非多键索引慢一些,因为可能会有多个索引条目指向同一个文档,返回结果集时需要进行去重

索引基数

就是指同一个索引中数据的不重复度,和mysql中一样

explain()和hint()

由于我这里没有拿到符合预期的结果,暂时不对这个方法进行分析了

索引类型

唯一索引

  • 创建唯一索引db.index_test.ensureIndex({'age': 1}, {"unique" : true})
  • 检查唯一性抛出异常时会影响效率,注意这里说的是抛出异常才会影响效率,检查好像影响不大(
    没有缓存穿透的问题?
    ),所以这里建议是只有少量重复数据时才使用,别用来作为数据校验
  • 如果一个文档对于字段没有值,那么索引里面会存储为null,对于唯一索引来说只能有一个文档允许索引字段没有值,因为第二个过来还会尝试存储为null就重复了
  • 索引的存储桶有大小限制,要小于1024,超过就无法存储到索引中了,也就是说对应的文档不能在索引中找到
  • 创建唯一索引可能会失败,因为已有的数据存在重复,这个时候有一个关键字dropdups可以强制创建,原理是保留第一个文档,删除其余重复文档,要谨慎使用

复合唯一索引

  • 创建复合唯一索引db.index_test.ensureIndex({'age': 1, 'name': 1}, {"unique" : true})
  • 复合键同时重复时抛出异常

稀疏索引

  • 注意这里的稀疏索引和关系型数据库中的稀疏索引不是一回事,mongo里面只是说不需要将每个文档都作为索引条目
  • 刚才说了对于多个没有值的文档无法创建唯一索引,这个时候可以通过稀疏索引来解决,也就是说只要求有值的文档值不重复
  • 对于非唯一稀疏索引,如果一个文档的索引键没有值,那么这个文档就不会出现在索引中,也就是只对有值的文档建立索引,这个时候如果进行非查询结果会和非稀疏索引不同

管理索引

mongo中有一个保留集合system.indexes,这里面存储了索引元信息

  • 修改索引:并没有修改的方法,只能删除重建,创建索引的时候会锁定集合,可以选择后台创建,但是创建的速度会慢一些
  • 在已有文档上创建索引比创建好索引后再插入数据要快