设计MySQL数据库表的时候,一定会考虑主键的设计。mysql官方推荐不要使用uuid或者不连续不重复的雪花id,推荐连续自增的主键id,官方的推荐是auto_increment。为什么不建议采用uuid,使用uuid究竟有什么坏处?

如果设计表不设置主键,MySQL官方有以下说明:

If you do not define a PRIMARY KEY for your table, MySQL picks the first UNIQUE index that has only NOT NULL columns as the primary key and InnoDB uses it as the clustered index. If there is no such index in the table, InnoDB internally generates a clustered index where the rows are ordered by the row ID that InnoDB assigns to the rows in such a table. The row ID is a 6-byte field that increases monotonically as new rows are inserted. Thus, the rows ordered by the row ID are physically in insertion order.

翻译:如果没有主动设置主键,就会选一个第一个不包含NULL的唯一索引列作为主键列,并把它用作一个聚集索引。如果没有这样的索引就会使用行号生成一个聚集索引,把它当做主键,这个行号6bytes,自增。可以用select _rowid from table来查询。

1. 什么是主键?主键有什么用

mysql 数据库表存放关系型结构化数据,一定会提供对数据的CRUD操作。在查询操作时,如果没有索引,MySQL必须从第一行开始,然后读取整个表以查找相关行。表越大,成本越高。通过建立索引,MySQL可以根据索引文件快速确定要在数据文件中间寻找的位置,而无需查看所有数据。

MySQL的索引主要分为主键索引(PRIMARY KEY),唯一索引(UNIQUE) ,普通索引(INDEX)和全文索引(FULLTEXT) 。主键索引是一种特殊的唯一索引,不允许有空值。

MySQL中索引是如何发挥功效的呢?先看一下MySQL的执行过程:

所有与数据的交互是会通过引擎服务的,MySQL中常见的引擎包括MyIsam和InnoDb。二者的差别这里不做叙述,可参见:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/96205289

InnoDB的存储文件有两个,后缀名分别是 .frm和 .idb;其中 .frm是表的定义文件, .idb是表的数据文件。InnoDB引擎采用B+Tree结构来作为索引结构,InnoDB主键的叶子节点是该行的数据,而其他索引则指向主键。

2. 为什么不推荐使用UUID

页是 InnoDB 管理的最小单位,常见的有 FSP_HDRINODE, INDEX 等类型。页结构分为文件头(前38字节),页数据和文件尾(后8字节)。每个数据页大小为16kb,结构如下:

系统从磁盘中读取数据到内存时是以磁盘块(block)为基本单位,位于同一个磁盘块中的数据会被一次性读取出来。block大小空间往往没有16kb大,因此innodb每次io操作时都会将若干个地址连续的磁盘块的数据读入内存,从而实现整页读入内存。

MySQL写入数据时,会把数据存放到索引页中。使用UUID作为主键,新行的主键值不一定比之前的主键值大,所以innoDb无法做到总是把新行插入到索引的最后,而需要为新行寻找合适的位置来分配新的空间,这个过程会导致:

  • 写入的目标页可能从缓存上移除了,或者还没有加载到缓存上,innodb写入之前需要先从磁盘找到目标页,会产生大量的随机IO;
  • 因为写入是乱序的,innoDb 要做频繁的分页操作,以便为行产生新的空间,页分裂导致移动大量的数据,一次插入最少需要修改三个页以上;
  • 频繁的页分裂,页会变得稀疏并被不规则的填充,最终会导致数据会有碎片;
  • 随机值(uuid和雪花id)载入到聚簇索引,有时候会需要做一次OPTIMEIZE TABLE来重建表并优化页的填充,这将又需要一定的时间消耗。

使用自增主键则可以避免上述问题:

  • 自增主键值是顺序的,所以Innodb把每一条记录都存储在一条记录的后面。当达到页面的最大填充因子时候(innodb默认的最大填充因子是页大小的15/16,会留出1/16的空间留作以后的     修改),下一条记录就会写入新的页中;
  • 数据按照顺序方式加载,主键页就会近乎于顺序的记录填满,提升了页面的最大填充率,不会有页的浪费;
  • 新插入的行一定会在原有的最大数据行下一行,mysql定位和寻址很快,不会为计算新行的位置而做出额外的消耗;
  • 减少了页分裂和碎片的产生

结论:使用innodb应该尽可能的按主键的自增顺序插入,并且尽可能使用单调的增加的聚簇键的值来插入新行

3. 使用自增主键的问题

  • 安全问题:如果采用自增主键,可能存在根据ID值爬取数据库记录,有安全风险;
  • 系统重构:系统重构或者与其他系统集成时,可能存在新老主键冲突;
  • 高并发负载,innodb在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点,因为所有的插入都发生在这里,并发插入会导致间隙锁竞争;
  • Auto_Increment锁机制会造成自增锁的抢夺,有一定的性能损失;
  • 自增主键有限,要考虑主键长度问题。

Auto_increment的锁争抢问题,可以通过调优innodb_autoinc_lock_mode的配置,总共有三个有效值可供设定,即0、1、2,具体说明如下:

0:是MySQL 5.1.22版本之前自增长的实现方式,即通过表锁的AUTO-INC Locking方式,所有的insert语句在开始时都会获得一个表锁AUTO-INC Locking。该锁会一直持有到insert语句执行结束才会被释放。对于一条insert插入多个行记录的语句,保证了同一条语句插入的行记录的自增ID是连续的。

1:这是该参数的默认值,对于”simple inserts”,该值会用互斥量(mutex)去对内存中的计数器进行累加的操作。insert语句在开始时会获得一个表锁AUTO-INC Locking,但对于bulk insert,自增锁会被一直持有直到语句执行结束才会被释放。这种模式仍然保证了同一条语句插入的行记录的自增ID是连续的。

2:对于所有的插入操作”INSERT-LIKE”自增长值的产生都是通过互斥量,而不是AUTO-INC Locking的方式,不管什么情况都使用轻量级互斥的锁。因为并发插入的存在,在每次插入时,自增长的值可能不是连续的。最重要的是,基于Statement的主从复制会出现问题,任何时候都应该使用Row方式,这样才能保证最大的并发性能及主从数据的一致。

MySql为什么不推荐使用UUID做主键相关推荐

  1. mysql uuid 做主键_MySQL UUID做主键

    UUID做主键,好还是不好?这是个问题. 我唯一还算熟悉的数据库就算是MySQL了,大概使用MySQL的人,百分之九九以上的人会使用Autoincrement ID做主键,这是可以理解的,因为MySQ ...

  2. 为什么不要用uuid做主键

    之前文章中介绍Snowflake的时候其实已经说过了,自增id做主键对于InnoDB更友好,如果用uuid做主键数据插入时会伴随大量的数据迁移,导致插入性能降低,今天从InnoDB数据结构聊聊数据是如 ...

  3. Java代码TkMyBatis通用Mapper中新增数据时同时获取自增主键ID,与适用uuid 做主键时获取 id

    一 . MyBatis mapper.xml文件中在xml 1.   加入 这句 :useGeneratedKeys="true" keyProperty="ID&quo ...

  4. 为什么是UUID做主键

    为什么是UUID做主键 什么是UUID UUID是通用唯一识别码(Universally Unique Identifier)的缩写,是一种软件建构的标准.其目的,是让分布式系统中的所有元素都能有唯一 ...

  5. mysql int做主键_mysql5.5 uuid做主键与int做主键的性能实测

    偶然的机会,得知mysql主键的类型采用 varchar 存UUID 的查询性能没有int型做主键好.网上查询大量资料,都是停留在理论上的,因此,自己写了代码进行实测,以下结果仅供参考,不具备权威性. ...

  6. centos修改磁盘uuid_为什么MySQL用uuid做主键会被骂?

    " 在 MySQL 中设计表的时候,MySQL 官方推荐不要使用 uuid 或者不连续不重复的雪花 id(long 形且唯一,单机递增),而是推荐连续自增的主键 id,官方的推荐是 auto ...

  7. MySQL之——mysql5.5 uuid做主键与int做主键的性能实测

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/51140577 偶然的机会,得知mysql主键的类型采用 varchar 存UUID ...

  8. mysql为何不建议使用外键_为什么很多mysql课程不推荐用物理外键?

    刚好今晚有师弟问我这个问题,就来搜搜.以前我对这个也是蛮困惑的.这一年来对这个问题感受比较深. 用外键的好处我就不多说了,既然是关系型数据库,外键的约束为我们保证了数据主从关系和产生的先后关系,级联操 ...

  9. 数据库-玩转数据-Pgsql 使用UUID做主键

    一.使用uuid-ossp 1.安装 uuid-ossp 文件: 在postgresql数据库中,是不能直接使用UUID函数的,需要手动安装 uuid 的相关文件,才能应用UUID相关的函数. 2.调 ...

最新文章

  1. php mysql insert数组_PHP – MySQL编写的INSERT数组语句
  2. mysql主从复制 跳过表_mysql主从复制-从库跳过异常日志点
  3. 明确需求与功能,优化小打卡的分享刺激点
  4. 共赴CIO时代,永洪BI如何推动企业数字化转型与创新?
  5. C语言重复加一个数的所有位数字的算法(附完整源码)
  6. LeetCode之Number Complement
  7. Weblogic 10.3.2 安装过程中出现致命错误的处理方法
  8. EssentialC++
  9. Android 应用开发(37)---RelativeLayout(相对布局)
  10. html中滤镜的效果图,CSS滤镜之Mask属性-网页设计,HTML/CSS
  11. function fnShowMessageBox(sTitle, sMsg)弹窗
  12. 来看一下:构造函数的小秘密详解
  13. 常见OJ提交结果对照表
  14. java 文件读取大全
  15. 系统动力学仿真软件Vensim下载
  16. OpenGL编程指南(第七版)
  17. 易邮服务器com组件注册失败,com组件注册失败有什么办法可以解决
  18. linux测试消息队列阻塞,Linux进程间通信:消息队列
  19. html的strong标签是什么意思,Strong标签和B标签怎么用?区别有哪些
  20. android 按钮边距,安卓button代码初始化默认内边距问题

热门文章

  1. 【华为交换机】流量统计及配置实例
  2. htc vive_HTC Vive Pro如何比原始Vive更好?
  3. 数据结构之字符串模式匹配
  4. [Ansible系列]ansible JinJia2过滤器
  5. 输了!柯洁首战告负AlphaGo,哈萨比斯:这不是人机大战
  6. [原创]AC97插针 转 3环3.5mm 接线教程
  7. WPF按钮文字随鼠标划入而变化
  8. Q620D高强板抗拉屈服强度及Q620D厚度方向抗撕裂性能
  9. vue 组件插槽solt 的使用
  10. 利用bind9搭建dns主从服务器(centos 7)