MongoDB Indexes
- 默认 _id 会作为collection的索引
- 对于单个字段的索引, 排序方向并不影响索引的使用
- 嵌入文档的索引,必须要完全匹配
- 对于复合索引,可以匹配任意带有前缀的查询
1 | { "item": 1, "location": 1, "stock": 1 } |
支持:
1 | { item: 1 } |
- 排序
1 | db.events.createIndex( { "username" : 1, "date" : -1 } ) |
支持sort:
1 | db.events.find().sort( { username: -1, date: 1 } ) |
不支持:
1 | db.events.find().sort( { username: 1, date: 1 } ) |
实验
MongoDB 版本
1 | ~ » mongo --version |
单个索引
创建订单表, 插入10000条数据
1 | ~ » mongo |
根据sku查询, 使用explain()进行分析
1 | db.order.find({"sku":100}).explain() |
1 | { |
观察到 winningPlan 的 stage 为 COLLSCAN 为 全表扫描
添加索引
1 | db.order.ensureIndex({"sku":1}) |
再次根据sku查询
1 | > db.order.find({"sku":100}).explain() |
发现现在 stage 为 IXSCAN, 意为 index scan, 索引扫描, 此时利用了索引
复合索引
创建collection, 添加数据
1 | for(var i = 0; i < 10000; i++) { |
添加复合索引
sku_1_cid_1
1 | db.order_2.ensureIndex({"sku":1, "cid":1}); |
观察现象
查询条件 | 查找方式 | 是否使用索引 |
---|---|---|
sku : 100 | IXSCAN | 是 |
cid : 100 | COLLSCAN | 否 |
sku:2, cid:9998 | IXSCAN | 是 |
cid:2, sku:9998 | IXSCAN | 是 |
4个字段组成的复合索引支持的查询类型
1 | for(var i = 0; i < 10000; i++) { |
1 | db.order_4.ensureIndex({"sku":1,"cid":1,"status":1,"order":1}) |
索引 sku_1_cid_1_status_1_order_1
查询条件 | 查找方式 | 是否使用索引 |
---|---|---|
sku : 100 | IXSCAN | 是 |
cid : 100 | IXSCAN | 是 |
status : 100 | IXSCAN | 是 |
order : 100 | IXSCAN | 是 |
sku:2, cid:9998 | IXSCAN | 是 |
sku:9998, status: 100 | IXSCAN | 是 |
sku:9998, order: 100 | IXSCAN | 是 |
cid:1, status:100 | COLLSCAN | 否 |
cid:1, order: 0 | COLLSCAN | 否 |
status:100, order:1 | COLLSCAN | 否 |
sku:1,cid:100,status:1 | IXSCAN | 是 |
sku:1,cid:100,order:1 | IXSCAN | 是 |
sku:1,status:100,order:0 | IXSCAN | 是 |
cid:1,status:100,order:0 | COLLSCAN | 否 |
sku:1,cid:100,status:1,order:1 | IXSCAN | 是 |
综上所述:
- 是否使用索引与查询条件的顺序无关
- 创建索引时指定的字段顺序很重要
- 只要查询条件满足索引的前缀就会使用索引
- 确保你创建的复合索引在大部分的查询语句中使用到前缀(包含最前面的字段)