zoukankan      html  css  js  c++  java
  • MongoDB 的主键 _id 为什么不是自增数字

    MongoDB 从一开始就是设计作为分布式数据库的,为了方便不同的机器都能全局唯一的生成 _id,而自增 id 需要在多个服务器上同步其值,费时费力,所以自然得设计成长字符串。

    ObjectId 是"_id" 的默认类型,举个官网的例子

    db.products.insert(
       [
         { _id: 11, item: "pencil", qty: 50, type: "no.2" },
         { item: "pen", qty: 20 },
         { item: "eraser", qty: 25 }
       ]
    )
    
    { "_id" : 11, "item" : "pencil", "qty" : 50, "type" : "no.2" }
    { "_id" : ObjectId("51e0373c6f35bd826f47e9a0"), "item" : "pen", "qty" : 20 }
    { "_id" : ObjectId("51e0373c6f35bd826f47e9a1"), "item" : "eraser", "qty" : 25 }
    

    ObjectId 是一个字符串,有 24 个字符,使用 12 字节的存储空间,每个字节两位十六进制数字。

    上文官网那个例子,ObjectId 的前 8 个字符可以被当做时间来计算,以秒做单位的。

    new Date(parseInt('51e0373c', 16) * 1000).toJSON()
    "2013-07-12T17:05:00.000Z"
    

    接下来的 3 字节是所在主机的唯一标识符。通常是机器主机名的 MD5 散列值。这样就可以确保不同主机生成不同的 ObjectId,不产生冲突

    parseInt('6f35bd', 16)
    7288253
    

    还为了确保同一台机器上并发多个进程的 ObjectId 是唯一的,那么还需要加入进程的 PID

    // PID 是 33391
    parseInt('826f', 16)
    33391
    

    最后来一个自动增加的计数器,来确保相同进程同一秒产生的 ObjectId 也是不一样的。

    parseInt('47e9a0', 16)
    4712864
    

    MySQL 为什么需要使用自增数字做主键

    参照 Mysql 索引使用以及优化策略 的 “为什么说主键最好使用与业务无关的自增字段”,

    Innodb 使用聚集索引,数据记录本身被存于主索引(一颗B+Tree)的叶子节点上

    如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置

    此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销,同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。

    MongoDB 可没有聚族索引,没有那样的顾虑。

    参考

    Mysql 索引使用以及优化策略 的 “为什么说主键最好使用与业务无关的自增字段”,

    MongoDB学习笔记-ObjectId主键的设计,本篇分析了 MongoDB 主键设计的部分源码。

    【Mongodb】_id和ObjectId详解

  • 相关阅读:
    正则表达式
    对象与私有成员变量恩仇录
    c语言,中缀表达式转后缀表达式并计算
    Graphics Class
    获取当前应用程序所在目录的路径
    centos安装vim
    Linux更改IP地址
    Linux常用命令
    Linux添加环境变量
    Linux虚拟机安装
  • 原文地址:https://www.cnblogs.com/everlose/p/12826194.html
Copyright © 2011-2022 走看看