-
索引可以加快查询速度,但是会让insert,update,delete等写操作变慢
-
索引在某些情况下可能导致查询变慢:
- 查询所有:db.collections.find({}), 无索引更快, 因为有索引的话,就分2步,先找索引,再找记录
- 太小的collecions
- 太小的documents
-
索引可以使sort()变快
- 如果排序有多个字段,index只有一个字段, 应该是没啥效果的
- db.users.find().sort({“age” : 1, “username” : 1})
- createIndex({“username” : 1})或createIndex({“age” : 1})都是没啥效果的
- 最好设置index为 db.users.createIndex({“age” : 1, “username” : 1})
natural order
: 一个不经过排序的查询结果- 排序与index
- 如果排序只有一个字段,对应的也是单个的index, 那么升序,降序都可以用这个index
- sort({“age”:1})/sort({“age”:-1}) 都可以用这个索引: createIndex({“age”:1})
- {“age” : 1, “username” : -1}和{“age” : -1, “username” : 1}是一样的
- 如果排序只有一个字段,对应的也是单个的index, 那么升序,降序都可以用这个index
- 如果排序有多个字段,index只有一个字段, 应该是没啥效果的
-
有索引和无索引(命中索引和未命中索引)可能导致返回不一样的值
-
索引的类型:
- 唯一索引(
Unique Indexes
), 与MySQL一样, - 部分索引(
Partial Indexes
), 因为某些字段在某些documents是可以不存在的db.users.ensureIndex({"email" : 1}, {"unique" : true,"partialFilterExpression" :{ email: { $exists: true } }})
- 联合唯一索引(
Compound unique indexes
)复合索引保证这几个字段联合起来是唯一的
- 唯一索引(
-
创建在collections上, 同样的index只能创建一个
-
index保存在每个database的
system.indexes
里, 不能直接修改这个collection -
record identifier
: 存储引擎里的东西,索引会指向他 -
query shape
: A combination of query predicate, sort, and projection -
query's plans
: For a query, the MongoDB query optimizer chooses and caches the most efficient query plan given the available indexes -
covered query(覆盖索引查询)
- https://blog.csdn.net/fly910905/article/details/78315046
explain
的表现IXSCAN
stage不是FETCH
stage的后代executionStats.totalDocsExamined
为0
-
隐式索引
- 创建索引: {“a”: 1, “b”: 1, “c”: 1, …, “z”: 1}
- 隐式索引: {“a”: 1}, {“a”: 1, “b” : 1}, {“a”: 1,“b”: 1, “c”: 1}, {“a”:1, “c”:1}
- 非隐式索引: {“b”: 1} or {“a”: 1, “c”: 1}, {“b”:1,“c”:1}
-
导致索引低效的操作符
- $ne
- $nin
- $not
-
一个查询基本上只用到一个索引
- 对于{“x”:123, “y”:456}这样的查询
- 只有{“x”:1}和{“y”:1}这2个索引,只会用到其中一个
$or
操作符例外,每一个条件都是一个单独的查询,然后合并去重,可以用到多个index
-
$in
和$or
- 优先使用
$in
而不是$or
,基于上面所说的$or
是多个查询合并的 $in
返回的是无序
的: {“x” : {“KaTeX parse error: Expected 'EOF', got '}' at position 15: in" : [1, 2,3]}̲}和 {"x" : {"in” : [3, 2,1]}}返回顺序可能是一样的
- 优先使用
-
复合index
包含多个字段的index
db.users.createIndex({“age”:1, “username” : 1})
- db.users.find({“age” : 21}).sort({“username” : -1}),
ok
- db.users.find({“age” : {“
g
t
e
"
:
21
,
"
gte" : 21, "
gte":21,"lte” : 30}}),
ok
- db.users.find({“age” : {“
g
t
e
"
:
21
,
"
gte" : 21, "
gte":21,"lte” :30}}).sort({“username” : 1}),
not ok
- 改进,更改index顺序: db.users.createIndex( {“username” : 1, “age” : 1})
- 多个字段索引, 通常把sort的field放在多字段索引的第一个字段
- 设计准则:
- 有相等查询(equality filters)字段放前面
- 有排序字段放在相等查询字段之后,范围查询(比如: 大于某个值,小于某个值)字段之前(好像有问题)
- 范围查询字段放最后
- db.users.find({“age” : 21}).sort({“username” : -1}),
-
multikey index
- 如果index里有字段是array就被标记为multikey index
- 在explain里命中这个索引后, isMultiKey为True
- index一旦被标记为multikey index,那怕相关的doc被删除都还是这个标记, 只有删除index,然后重建才可以抹掉这个标记 -
.explain(“executionStats”)
用于为find()提供query plan的信息, 跟MySQL的explain指令差不多:
用法: db.collName.find({}).explain(), 或者 db.collName.find({}).explain(“executionsStats”)
.explain("executionsStats")
返回结果里的关键字段COLLSCAN
字段: 没用到索引,作了全文扫描SORT
字段: 如果有这个 stage在结果里,那么这就是比较糟糕的: 排序没有用到索引,在内存里排序了,如果超过32M
还会报错executionTimeMillis
字段: 实际执行时间nReturned
字段: 实际返回的条数totalKeysExamined
字段: 检查的index的条数,与nReturned
一致是最好的totalDocsExamined
字段: 检查的documentation的条数,与nReturned
一致是最好的
-
.createIndex()
创建索引,createIndex({“filedName”:1, “fieldName”:-1})
- 顺序: 字段名后面为
1
是升序,-1
是降序
- 顺序: 字段名后面为
-
.hint()
强制使用某个索引,参数可以是索引名字, 也可以是shape
- 指定索引: db.users.find().hint( { age: 1 } )
- 索引名: db.users.find().hint( “age_1” )
-
查询计划: https://zhuanlan.zhihu.com/p/47281465