我往测试数据库里塞了 500 万 条数据
{_id:1,field:1}
{_id:2,field:2}
...
...
...
{_id:5000000,field:5000000}
field 上建立有索引
然后按照主键和 field 查询, 相当于
db.data4.find({_id:{$gte:4000000}}).limit(1)
和
db.data4.find({field:{$gte:4000000}}).limit(1)
可以看出,时间差距巨大,这是为啥?
1
hheedat OP mongod -version
db version v3.4.3 git version: f07437fb5a6cca07c10bafa78365456eb1d6d5e1 OpenSSL version: OpenSSL 1.0.2l 25 May 2017 |
2
billion 2017-11-10 15:23:19 +08:00
这是因为在 MongoDB 里面,非主键的索引会被转换成主键索引。
|
3
nullcc 2017-11-10 15:27:41 +08:00
_id 是主键,一般来说主键索引是聚簇索引,field 是非主键索引,也叫二级索引,二级索引每个索引项内部还保存了主键值,对二级索引的使用在索引中找到相应的叶子节点后都会使用其主键进行主键索引,这样开销就多了
|
6
nullcc 2017-11-10 15:31:50 +08:00
@hheedat 虽说每个存储引擎实现可能有些差别,不过我觉得内部原理应该差不多,你可以 explain 一下看看,也再建立一个(_id, field)的联合索引做覆盖查询对比看看。
|
9
janxin 2017-11-10 15:34:39 +08:00
你 explain 一下,因为你用了 gte
|
10
janxin 2017-11-10 15:35:27 +08:00
看错了,主键也是 gte,基本上就是 6# 的问题了
|
11
gzlock 2017-11-10 15:40:26 +08:00 via Android
楼主用的是什么 gui 管理?
|
13
egen 2017-11-10 16:00:52 +08:00
500w 的记录数量一个 gte 需要 2s 不合理,这个速度几乎就是没有索引的速度
刚简单测试了一下本地一个 40w 记录的数据库,一个加索引的日期,搜索时间不到 0.001 秒,另外一个未加索引的,搜索时间 200ms 左右,时间比例上和 lz 的接近 |
16
egen 2017-11-10 16:06:53 +08:00
@hheedat #15 是否建立了 _id + field 的复合索引?建立了复合索引之后,单独搜索 field 是没法使用该索引的
|
18
chenqh 2017-11-10 19:58:16 +08:00 via iPhone
是不是 int 和 long 的区别?
|
19
a342191555 2017-11-10 21:00:16 +08:00
感觉你的索引没有正确工作…
我在 MongoDB 里试了下,同样插入了 500W 条数据,索引和数据像这样: 查询_id 的速度: 查询 field 的速度: 然后把 field 的索引删掉,查询 field 的速度: 这个没有索引的时间和你的很像。另外,@chenqh 提出的 NumberInt 和 NumberLong 好像没有关系,虽然一开始我也是这么想的。。 |
20
nekuata 2017-11-10 22:11:42 +08:00
@hheedat 虽然没用过 mongo...
你的_id 是 normal index,field 是 2d index 而 @a342191555 的两个 key 都是 1,大概都是 normal index 可能 2d index 在这里不能用吧? |
21
a342191555 2017-11-11 09:39:44 +08:00 via iPhone
@nekuata 你的 field 也不是一个地理坐标呀。另外,dn.data4.getIndexes()返回什么?
|
22
a342191555 2017-11-11 09:41:00 +08:00 via iPhone
@nekuata sry,把你当成 lz 了。在描述中我也没有看到 field 是 2d idx 呀
|
23
nekuata 2017-11-11 11:11:07 +08:00 via Android
@a342191555 呃,不好意思看错了,索引图上面应该是按钮...
|