• MongoDB 索引的最佳实践


    MongoDB 索引的最佳实践

    大部分开发者都知道加索引会快。但实际过程中,我们常碰到一些疑问&困难:

    • 我们查询的字段会各种case都有,是不是各个涉及查询的字段都要加索引?
    • 复合索引和单字段怎么选择,都加还是每一个的单个字段就好了?
    • 加索引有没有副作用?
    • 索引都加了,但还是不够快?怎么办?

    本文尝试去解释索引的基本知识&解答上述的疑问。

    索引究竟是什么东西?

    大部分开发者接触索引,大概知道索引类似书的目录,你要找到想要的内容,通过目录找到限定的关键字,进而找到对应的章节的pageno,再找到具体的内容。
    在数据结构里面,最简单的索引实现类似hashmap,通过关键字key,映射到具体的位置,找到具体的内容。但除了hash的方式,还有多种的方式实现索引。

    索引的多种实现方式以及特色

    hash / b-tree / b+-tree
    redis HSET / MongoDB&PostgreSQL / MySQL

    hashmap

    hashmap

    一图见b-tree & b+-tree 差别

    b-tree & b+-tree

    • b+-tree 叶子存数据,非叶子存索引,不存数据,叶子间有link
    • b-tree 非叶子可存数据

    算法查找复杂度上来说
    hash 接近O(1)
    b-tree O(1)~ O(Log(n))更快的平均查找时间,不稳定的查询时间
    b+ tree O(Log(n)) 连续数据, 查询的稳定性

    至于为何MongoDB 的实现选择b-tree 而非 b+-tree ?
    网上多篇文章有阐述,非本文重点。

    数据&索引的存储

    storage
    index 尽量存储在内存, data 其次。
    注意只保留必要的index,内存尽量用在刀刃上。
    如果index memory 都接近占满memory,那么就很容易读到disk,速度就下来了。

    知道索引的实现&存储原理后的思考

    insert/update/delete 会触发rebalance tree -- 所以,增删改数据,索引会触发修改,性能会有损耗
    索引不是越多越好
    既然如此,选择哪些字段作为索引呢?当查询用到这些条件,怎么办?
    拿一个最简单的hashmap来讲,为什么复杂度不是O(1),而是所谓接近 O(1)。因为有key 冲突/重复啊~。DB 去找的时候,key 冲突的数据一大堆的话,还是得轮着继续找。
    上面的b-tree 看键(key)的选择也是如此。
    因此一个大部分开发经常犯的错就是对没有区分度的key 建索引
    例如:很多就只有集中类别的 type/status 的 documents count 达几十万以上的collection --- 通常这种索引没什么帮助。

    复合索引

    复合索引不是越多越好
    如果不想多建多余的索引,开发的同事在复合 & 单个字段 有时选择上挺纠结的。

    根据典型碰到的场景,来做几个实验
    这里创建了个loans collection。简化只有100条数据。这个是借贷的表有 _id, userId, status(借贷状态), amount(金额).

    看完 这个实验, 明白了 {userId:1, status:1}, vs {status:1,userId:1} 的差别了吗?

    PS:这个case 里面其实status 区分度不高,不应该建立的,这里只是作为实例展示。

    总结:

    • 注意使用上 使用频率上 区分高的/常用的在前面
    • 如果需要减少索引以节省memory/提高修改数据的性能的话,可以保留区分度高,常用的,去除区分度不高,不常用的索引。

    学会用explain()验证分析性能

    DB 一般都有执行器优化的分析,MySQL & MongoDB 都是 用explain 来做分析。
    语法上MySQL :

    explain your_sql

    MongoDB:

    yoursql.explain()

    至于怎么看,这里不展开,网上可以搜到各种文章。

    总结典型:理想的查询

    结合explain 的指标,他们通常是多个的混合

    • IXSCAN : 索引命中
    • Limit : 带limit
    • Projection : 相当于非 select *
    • Docs Size less is better
    • Docs Examined less is better
    • nReturned=totalDocsExamined=totalKeysExamined
    • SORT in index :sort 也是命中索引,否则,需要拿到数据后,再执行一遍排序
    • Limit Array elements : 限定数组返回的条数,数组也不应该太多数据,否则schema 设计不合理

    文末,还有一个最开头一个问题没回答,如果我的索引该加的都加了,还不够快。怎么办?留个悬念,之后再写一篇。

    PS:这个case 里面其实status 区分度不高,不应该建立的,这里只是作为实例展示。

    总结:

    • 注意使用上 使用频率上 区分高的/常用的在前面
    • 如果需要减少索引以节省memory/提高修改数据的性能的话,可以保留区分度高,常用的,去除区分度不高,不常用的索引。

    学会用explain()验证分析性能

    DB 一般都有执行器优化的分析,MySQL & MongoDB 都是 用explain 来做分析。
    语法上MySQL :

    explain your_sql

    MongoDB:

    yoursql.explain()

    至于怎么看,这里不展开,网上可以搜到各种文章。

    总结典型:理想的查询

    结合explain 的指标,他们通常是多个的混合

    • IXSCAN : 索引命中
    • Limit : 带limit
    • Projection : 相当于非 select *
    • Docs Size less is better
    • Docs Examined less is better
    • nReturned=totalDocsExamined=totalKeysExamined
    • SORT in index :sort 也是命中索引,否则,需要拿到数据后,再执行一遍排序
    • Limit Array elements : 限定数组返回的条数,数组也不应该太多数据,否则schema 设计不合理

    文末,还有一个最开头一个问题没回答,如果我的索引改加的都加了,还不够快。怎么办?留个悬念,之后再写一篇。

  • 相关阅读:
    Mac 下安装Ant
    MAMP 10.10下启动报错解决方案
    [转]常用iOS图片处理方法
    Mac下Android SDK更新不了的解决办法
    细说23+1种设计模式
    mysql应该了解的知识点
    java快排思想
    简介一下 i++和++i&&i=i+i,i+=1;的区别
    对int类型的数据,如何让获取长度
    第一次写博客
  • 原文地址:https://www.cnblogs.com/no7dw/p/13628785.html
Copyright © 2020-2023  润新知