V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐工具
RoboMongo
推荐书目
50 Tips and Tricks for MongoDB Developers
Related Blogs
Snail in a Turtleneck
hheedat
V2EX  ›  MongoDB

Mongo 主键和非主键索引,性能差距为啥这么大?

  •  
  •   hheedat · 2017-11-10 15:08:16 +08:00 · 10829 次点击
    这是一个创建于 2555 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我往测试数据库里塞了 500 万 条数据

    {_id:1,field:1}
    {_id:2,field:2}
    ...
    ...
    ...
    {_id:5000000,field:5000000}
    
    

    5000000

    field 上建立有索引

    index

    然后按照主键和 field 查询, 相当于

    db.data4.find({_id:{$gte:4000000}}).limit(1)
    
    和
    
    db.data4.find({field:{$gte:4000000}}).limit(1)
    

    query1

    query2

    可以看出,时间差距巨大,这是为啥?

    23 条回复    2017-11-11 11:11:07 +08:00
    hheedat
        1
    hheedat  
    OP
       2017-11-10 15:18:31 +08:00
    mongod -version
    db version v3.4.3
    git version: f07437fb5a6cca07c10bafa78365456eb1d6d5e1
    OpenSSL version: OpenSSL 1.0.2l 25 May 2017
    billion
        2
    billion  
       2017-11-10 15:23:19 +08:00
    这是因为在 MongoDB 里面,非主键的索引会被转换成主键索引。
    nullcc
        3
    nullcc  
       2017-11-10 15:27:41 +08:00
    _id 是主键,一般来说主键索引是聚簇索引,field 是非主键索引,也叫二级索引,二级索引每个索引项内部还保存了主键值,对二级索引的使用在索引中找到相应的叶子节点后都会使用其主键进行主键索引,这样开销就多了
    hheedat
        4
    hheedat  
    OP
       2017-11-10 15:30:05 +08:00
    @nullcc 哦,那和 MySQL 一样一样的,不过也不应该有这么大的性能差距吧?
    hheedat
        5
    hheedat  
    OP
       2017-11-10 15:30:42 +08:00
    @nullcc 确切的说和 innodb 一样一样的
    nullcc
        6
    nullcc  
       2017-11-10 15:31:50 +08:00
    @hheedat 虽说每个存储引擎实现可能有些差别,不过我觉得内部原理应该差不多,你可以 explain 一下看看,也再建立一个(_id, field)的联合索引做覆盖查询对比看看。
    nullcc
        7
    nullcc  
       2017-11-10 15:32:42 +08:00
    @hheedat 对的,innodb 就是这样的,mangodb 有用过但是没研究太深
    nullcc
        8
    nullcc  
       2017-11-10 15:33:11 +08:00
    @hheedat 是不是有查询缓存在?
    janxin
        9
    janxin  
       2017-11-10 15:34:39 +08:00
    你 explain 一下,因为你用了 gte
    janxin
        10
    janxin  
       2017-11-10 15:35:27 +08:00
    看错了,主键也是 gte,基本上就是 6# 的问题了
    gzlock
        11
    gzlock  
       2017-11-10 15:40:26 +08:00 via Android
    楼主用的是什么 gui 管理?
    hheedat
        12
    hheedat  
    OP
       2017-11-10 16:00:21 +08:00
    @nullcc 不是,换几个数字,效果一样
    egen
        13
    egen  
       2017-11-10 16:00:52 +08:00
    500w 的记录数量一个 gte 需要 2s 不合理,这个速度几乎就是没有索引的速度
    刚简单测试了一下本地一个 40w 记录的数据库,一个加索引的日期,搜索时间不到 0.001 秒,另外一个未加索引的,搜索时间 200ms 左右,时间比例上和 lz 的接近
    hheedat
        14
    hheedat  
    OP
       2017-11-10 16:01:02 +08:00
    @janxin 能用到哦
    hheedat
        15
    hheedat  
    OP
       2017-11-10 16:01:38 +08:00
    @gzlock rock mongo
    egen
        16
    egen  
       2017-11-10 16:06:53 +08:00
    @hheedat #15 是否建立了 _id + field 的复合索引?建立了复合索引之后,单独搜索 field 是没法使用该索引的
    hheedat
        17
    hheedat  
    OP
       2017-11-10 16:12:21 +08:00
    @egen 没有,就两个索引,都是单独的,如图所示
    chenqh
        18
    chenqh  
       2017-11-10 19:58:16 +08:00 via iPhone
    是不是 int 和 long 的区别?
    a342191555
        19
    a342191555  
       2017-11-10 21:00:16 +08:00
    感觉你的索引没有正确工作…
    我在 MongoDB 里试了下,同样插入了 500W 条数据,索引和数据像这样:

    查询_id 的速度:

    查询 field 的速度:

    然后把 field 的索引删掉,查询 field 的速度:

    这个没有索引的时间和你的很像。另外,@chenqh 提出的 NumberInt 和 NumberLong 好像没有关系,虽然一开始我也是这么想的。。
    nekuata
        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 在这里不能用吧?
    a342191555
        21
    a342191555  
       2017-11-11 09:39:44 +08:00 via iPhone
    @nekuata 你的 field 也不是一个地理坐标呀。另外,dn.data4.getIndexes()返回什么?
    a342191555
        22
    a342191555  
       2017-11-11 09:41:00 +08:00 via iPhone
    @nekuata sry,把你当成 lz 了。在描述中我也没有看到 field 是 2d idx 呀
    nekuata
        23
    nekuata  
       2017-11-11 11:11:07 +08:00 via Android
    @a342191555 呃,不好意思看错了,索引图上面应该是按钮...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2757 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 14:45 · PVG 22:45 · LAX 06:45 · JFK 09:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.