MySQL 创立表的时候能够不设置主键吗?
MySQL 创立表的时候是能够不被动设置主键的,然而表是肯定须要一个主键的,MySQL 会被动将第一个不为 null 的惟一索引设置为主键
为什么 MySQL 举荐应用自增 id 作为主键?
MySQL 官网举荐不要应用 uuid 或者不间断不反复的雪花作为主键,而是应用间断自增的主键 id
应用自增 id 的内部结构
自增 id 的值是程序的,所以 innodb 在索引 B + 树的叶子节点层面能够间接把每一条记录都存储在上一条记录的前面,当达到页面的最大填充因子的时候(页面容量曾经满了)下一条记录就会写入新的页中,数据依照这种程序的形式进行填充,主键页就会以近乎于程序的记录填满,晋升了页面的最大填充率,不会有页的节约
新插入的行肯定会在原有的最大数据的下一行,这样 MySQL 定位和寻址十分快,不会因为计算而做出额定的耗费,
并且可能缩小页决裂和碎片的产生
页决裂:保障后一个数据页的所有行主键值比前一个数据页的主键值大,所以当 ID 不为自增的主键的时候,就会导致后一个页的所有行并不一定比前一个数据页的行的 id 大。这时就会触发页决裂的逻辑,对两个页之间的数据进行调整,底层就是树结构的调整,这个耗费是很大的,甚至会波及到多个数据页,导致性能升高
应用自增 id 的毛病
- 他人一旦爬取你的数据库,就能够依据数据库的自增 id 获取到你业务的增长信息,从而剖析出经营状况
- 对于高并发的负载,innodb 在依照主键进行插入的时候会造成显著的锁争用,auto_increment 锁机制会造成自增锁的抢夺,有肯定的性能损失
为什么分布式系统不必自增 id,而是要用雪花算法生成 id
分布式 id 创立的业务需要 - 全局惟一
- 趋势递增 innodb 引擎的叶子结点是有序的双向链表,趋势递增能够减少性能,不会打乱树的构造
- 信息安全
- 最好蕴含工夫戳
为什么自增 id 不适宜分布式系统?
当数据宏大的时候,在数据库分库分表之后,数据库自增 id 不能满足惟一 id 来示意数据;因为每个表都依照本人的节奏自增,会造成 id 抵触,从而无奈满足需要
应用 auto_increment 实现便宜的分布式惟一主键
flickr 有相似的计划,构建是一个专用的数据库服务器,下面只有一个数据库,在数据库外面有用于 32 位 id 和 64 位 id 的 id 表,id 是 auto 自增的,所有数据库生成 id 都会向这个服务器发申请,而后服务器散发 id 上来,也能达到一种分布式惟一主键的成果
相似于 session-redis 的思维,把所有的 sessionid 都存在 redis 外面,所有的服务器实例在比拟 cookie 的时候就先去 redis 外面比拟,这样就能防止因为负载平衡导致的 cookie 生效问题
当然这个便宜的做法显然是有很大问题的 - 并发量很小,因为只有一台服务器
- 减少开销,并且整个申请流程变慢,因为须要向服务器发申请,并且是在硬盘层面进行操作的
- flickr 服务器成了整个零碎的瓶颈和隐患,如果服务器宕机整个零碎间接崩掉了
雪花算法
是 twitter 开源的分布式 id 生成算法,后果是一个 64 位的 longint 类型,核心思想是用 41 位来作为工夫戳,10 位来作为机器的 id,12 位作为毫秒内的流水号(意味着每个节点能够在每毫秒生成 4096 个 id),最初还有一个符号为永远为 0
长处
● 齐全在内存生成,高性能高可用
● 容量大,每秒能够生成几百万 id
● 趋势递增,插入数据库索引树的时候,性能比拟高
毛病
● 依赖零碎时钟的一致性,如果某台机器的零碎时钟回拨,有可能造成 id 抵触
● 多台机器的 ID 只能保障趋势减少,即每一台机器都能保障这台机器生成的 ID 是在减少的,然而多台机器并不一定相对递增
● 41 位工夫戳只能保障 69 年无反复 ID
● 因为是 64 位的 ID,在传递给前端的时候须要用字符串的类型进行传递,因为 js 的 number 类型最大只反对 53 位
其余分布式 ID 计划
● UUID:JAVA 自带的 API,生成一个唯一性的字符串,不能保障有序递增
● UidGenerator: 百度开源的分布式 ID 生成器,基于雪花算法
● Leaf: 美团开源的分布式 ID 生成器,能保障全局惟一,趋势递增,然而须要依赖关系数据库、Zookeeper 等中间件
本文由 mdnice 多平台公布