mongodb使用规范

库(database)

  1. 【强制】数据库名最多为64字符,库名全部小写,禁止使用任何_以外的特殊字符。
  2. 【强制】禁止使用数字打头的库名,如:123_abc
  3. 【强制】不要与系统保留的数据库名相同,这些数据库包括:admin,local,config等
    [正例]wd_journal
    [反例]WD_journal123test$jounralwd-journal

tips:库以文件夹的形式存在,使用特殊字符或其它不规范的命名方式会导致命名混乱。

  1. 【强制】库命名规则为业务名称_环境,如spischolar_test(spischolar测试环境),crscholar_online(crscholar线上环境)等,不建议使用无意义的库名称,如test

集合(conllection)

  1. 【强制】集合名称最多为64字符,集合名称全部小写,禁止使用任何_以外的特殊字符。
  2. 【强制】禁止使用数字打头的集合名,如:123_abc。
  3. 【强制】禁止system打头,system是系统集合前缀 。
  4. 【建议】为了避免库级锁带来的问题,应尽量对写入较大的集合使用“单库单集合”的结构,所以对于新增业务应尽量创建新库,而不是在现有库中创建新集合。

tips: 一个库中写入较大的集合会影响其它集合的读写性能 ,如果评估单集合数据量较大,可以将一个大表拆分为多个小表,然后将每一个小表存放在独立的库中,由于MongoDB是库级锁,因此这样做可以大幅减少并发写入带来的锁争用问题。

文档(document)

  1. 【强制】文档中的key禁止使用任何_以外的特殊字符。
    [反例]:$journal_abb
  2. 【强制】key全部小写,多个单词以下划线分隔。
    [反例]:journalAbb
  3. 【强制】禁止使用数字打头的key
    [反例]:1_journal_abb
  4. 【建议】尽量将相似类型的文档放在同一个集合中,将不同类型的文档分散在不同的集合中,相同类型的文档能大幅提高索引利用率,如果不同类型的文档混杂存放可能会出现查询经常全表扫描的情况。
  5. 【强制】禁止自定义_id的值。

tips:某业务的MongoDB在放量后出现严重的写入性能问题,大致为:写入达到300/s的时候IO跑满,排查中发现,该业务在设计的时候为了方便,而将_id中写入了无序的类似md5的数据。
MongoDB的表与InnoDB相似,都是索引组织表,数据内容跟在主键后,而_id是MongoDB中的默认主键,一旦_id的值为非自增,当数据量达到一定程度之后,每一次写入都可能导致主键的二叉树大幅度调整,这将是一个代价极大的写入,所以写入就会随着数据量的增大而下降,所以一定不要在_id中写入自定义的内容。

  1. 【建议】于MongoDB是大小写敏感的,如果字段无需大小写敏感,为了提高查询效率,应尽量存放统一了大小写后的数据,如:全部小写或为该字段增加一个统一了大小写的辅助字段。

tips:某业务需要根据字段{a:XxX}来进行查询,在MongoDB中a的值是大小写敏感的,并且无法配臵为忽略大小写,但该业务场景为了满足查询需求而需要忽略大小写,这个大小写敏感与否的矛盾导致业务需要使用正则来进行匹配:{a:/xxx/i}i参数在正则中表示忽略大小写,上线后发现, 查询性能非常低下,在一个拥有200万文档的集合中一次查询需要消耗2.8~7秒,并发达到50QPS的时候MongoDB实例所在服务器的CPU就跑到了973%。 MongoDB在查询条件中使用正则的时候,能够像普通精确匹配一样使用索引达到高效率的查询,但一旦使用了参数i来忽略大小写查询优化器就需要对每一个数据的大小写进行调整然后再进行匹配,此时这个请求就变成了全表扫描,这就是效率低下的根本原因。 对于这种场景可以采用新建一个统一了大小的字段,例如全部小写:假设原字段为:{a:aAbB},那么为其添加一个全部为小写的对应字段:{a_low:aabb}然后通过字段a_low进行查询就能达到精确匹配,按照该方案改进后,该场景的查询耗时降低到了2毫秒虽然新增字段导致实例会变大一些,但对于换来性能的大幅度提升还是非常值得的。

  1. 【建议】不要存放太长的字符串,如果这个字段为查询条件,那么确保该字段的值不超过1KB。

tips:MongoDB的索引仅支持1K以内的字段,如果你存入的数据长度超过1K,那么它将无法被索引。

索引(index)

  1. 【强制】索引名称长度不要超过128字符。
  2. 【强制】创建索引要在后台创建,避免阻塞业务正常DML和查询。
db.works.createIndex({a:1,b:1},{background:true})   
  1. 【强制】禁止在数组字段上创建索引,如禁止在字段{shoulu:[X,Y,Z]}上添加索引{shoulu:1}

tips:某业务在一个表的数组字段上创建了一个索引,创建完毕之后发现表体积增大了很多很多,排查发现是由于索引体积的大幅度增大导致在MongoDB中,如果为一个数组字段添加索引,那么MongoDB会主动为这个数组中的所有元素依次添加独立索引。
例如: 为数组字段{a:[x,y,z]}添加索引{a:1},实际上添加的索引为:
{a:[x:1]}
{a:[y:1]}
{a:[z:1]}
该业务的数组字段中有11个元素,那么等于一次创建了11条索引,这是索引体积大幅度增大的根本原因。另外,如果组合索引中存在数组字段,那么MongoDB会为每一个元素与其它字段的组合创建一个独立的索引,例如: 为数组字段{a:[x,y,z]}{b:qqq}添加索引{a:1,b:1},实际上添加的索引为:
{a:[x:1],b:1}
{a:[y:1],b:1}
{a:[z:1],b:1}
如果一个组合索引中存在两个数组字段,那么索引的数量将是两个数组字段中元素的笛卡儿积,所以MongoDB不允许索引中存在一个以上的数组字段。

  1. 【强制】在创建组合索引的时候,应评估索引中包含的字段,尽量将数据基数大(唯一值多的数据)的字段放在组合索引的前面;

tips:某业务某场景下的查询十分缓慢,大概需要1.7秒左右,需要进行调优,该场景的查询和对应索引如下:
查询:{name:baidu,status:0} 索引:{status:1,name:1}
乍一看没什么问题,因为查询和索引十分匹配,但对该集合分析后发现该集合一共有150万文档,而status=0的有1499930由于这基本上占了99%的文档数目(数据基数很小),所以导致虽然使用了索引,但依然需要从149万行数据中找到name=baidu的数据但name字段则有大量不同的数据(数据基数很大),所以如果将该组合索引调整为name在前,该查询即可先通过name字段抽出较少的数据,再通过status进行过滤,就快了: {name:1.status:1}调整后查询耗时降低到3~5毫秒。

查询

  1. 【建议】做等值查询,在做排序,在做范围查询
  2. 【建议】查询中的某些 $ 操作符可能会导致性能低下。

tips:$ne$not$exists$nin$or,尽量在业务中不要使用
$exist:因为松散的文档结构导致查询必须遍历每一个文档
$ne:如果当取反的值为大多数,则会扫描整个索引
$not:可能会导致查询优化器不知道应当使用哪个索引,所以会经常退化为全表扫描
$nin:全表扫描
$or:有多少个条件就会查询多少次,最后合并结果集,所以尽可能的使用 $in

你可能感兴趣的:(mongodb使用规范)