Mysql主键UUID和自增主键的区别及优劣分析

引言

之前有段时间用postgresql 数据库,在上云之后,从自增主键变为uuid,感觉uuid全球唯一,很方便。

最近用mysql,发现mysql主键都是选择自增主键,仔细比较一下,为什么mysql选择自增主键,有什么不同。

在mysql5.0之前,如果是多个master复制的环境,无法用自增主键,因为可能重复。在5.0以及之后的版本通过配置自增偏移量解决了整个问题。

什么情况下我们希望用uuid

1. 避免重复,便于scale,这就是我们做cloud service的时候选择uuid的主要原因

2. 入库之前可以知道id

3.相对安全,不能简单的从uuid获取信息,但是如果自增,则容易暴露信息,如果一个客户id是123456,很容易猜到有客户id是123456.

UUID有什么问题

1.uuid有16个字节,比int(4 byte)和bigint(8 byte)占用更多存储空间

2.由于size和无序性,可能引起性能问题

Mysql的uuid原理

mysql的innodb存储引擎处理storage的方式是靠聚集索引。

聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚集索引,因为一个表的物理顺序只有一种情况

1.为什么要使用uuid做主键

(1).其实在innodb存储引擎下,自增长的id做主键性能已经达到了最佳。不论是存储和读取速度都是最快的,而且占的存储空间也是最小。

(2).但是在我们实际到项目中会碰到问题,历史数据表的主键id会与数据表的id重复,两张自增id做主键的表合并时,id一定会有冲突,但如果各自的id还关联了其他表,这就很不好操作。

(3).如果使用UUID,生成的ID不仅是表独立的,而且是库独立的。对以后的数据操作很有好处,可以说一劳永逸。

2.UUID优缺点

缺点: 1. 影响插入速度, 并且造成硬盘使用率低

2. uuid之间比较大小相对数字慢不少, 影响查询速度。

3. uuid占空间大, 如果你建的索引越多, 影响越严重

优点:出现数据拆分、合并存储的时候,能达到全局的唯一性

3.最优方案

(1).InnoDB引擎表是基于B+树的索引组织表。

(2).B+树:B+树是为磁盘或其他直接存取辅助设备而设计的一种平衡查找树,在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶节点中,各叶节点指针进行连接。

(3).InnoDB主索引:叶节点包含了完整的数据记录。这种索引叫做聚集索引。InnoDB 的索引能提供一种非常快速的主键查找性能。不过,它的辅助索引也会包含主键列,所以,如果主键定义的比较大,其他索引也将很大。如果想在表上定义 、很多索引,则争取尽量把主键定义得小一些。InnoDB 不会压缩索引

(4).聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

综合上述可得:

(1).如果InnoDB表的数据写入顺序能和B+树索引的叶子节点顺序一致的话,这时候存取效率是最高的。为了存储和查询性能应该使用自增长id做主键。

(2).对于InnoDB的主索引,数据会按照主键进行排序,由于UUID的无序性,InnoDB会产生巨大的IO压力,此时不适合使用UUID做物理主键,可以把它作为逻辑主键,物理主键依然使用自增ID。为了全局的唯一性,应该用uuid做索引关联其他表或做外键。

4.如果非要使用uuid做主键,下面是小建议:

如果是主从即M-S模式,最好是不使用mysql自带函数uuid来生成唯一主键,因为主表生成的uuid要再关联从表时,需要再去数据库查出这个uuid,需要多进行一次数据库交互,而且在这个时间差里面主表很有可能还有数据生成,这样就很容易导致关联的uuid出错。如果真要使用uuid,可以在Java中生成后,直接存储到DB里,这时主从的uuid就是一样的了!

补充:mysql的uuid()主键重复

1、mysql的uuid()主键重复

mysql使用了navicat客户端,某次执行了如下sql

select replace(uuid(), '-', '') as id, u.user_id from t_user u;

结果发现,生成的uuid重复了,

经过排查,发现是navicat的问题,需要将该sql语句做如下调整:

select replace(convert(uuid() using utf8mb4), '-', ''), u.user_id from t_user u;

结果如下:

2、使用其他方案:

将uuid再进行一次md5:

select md5(uuid()) as id, u.user_id from t_user u;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 详解MySQL 表中非主键列溢出情况监控

    今天,又掉坑了. 之前踩到过MySQL主键溢出的情况,通过prometheus监控起来了,具体见这篇MySQL主键溢出复盘 这次遇到的坑,更加的隐蔽. 是一个log表里面的一个int signed类型的列写满了.快速的解决方法当然还是只能切新表来救急了,然后搬迁老表的部分历史数据到热表. 亡羊补牢,处理完故障后,赶紧写脚本把生产的其他表都捋一遍. 下面是我暂时用的一个检测脚本,还不太完善,凑合用 分2个文件(1个sql文件,1个shell脚本) check.sql 内容如下: SELECT ca

  • 浅谈MySQL中的自增主键用完了怎么办

    在面试中,大家应该经历过如下场景 面试官:"用过mysql吧,你们是用自增主键还是UUID?" 你:"用的是自增主键" 面试官:"为什么是自增主键?" 你:"因为采用自增主键,数据在物理结构上是顺序存储,性能最好,blabla-" 面试官:"那自增主键达到最大值了,用完了怎么办?" 你:"what,没复习啊!!"    (然后,你就可以回去等通知了!) 这个问题是一个粉丝给我提的,我觉得

  • MySQL的自增ID(主键) 用完了的解决方法

    在 MySQL 中用很多类型的自增 ID,每个自增 ID 都设置了初始值.一般情况下初始值都是从 0 开始,然后按照一定的步长增加(一般是自增 1).一般情况下,我们都是用int(11)来作为数据表的自增 ID,在 MySQL 中只要定义了这个数的字节长度,那么就会有上限. MySQL的自增ID(主键) 用完了,怎么办? 如果用 int unsigned (int,4个字节 ), 我们可以算下最大当前声明的自增ID最大是多少,由于这里定义的是 int unsigned,所以最大可以达到2的32幂

  • MySQL的主键命名策略相关

    最近在梳理数据生命周期管理的细节时,发现了一个小问题,那就是MySQL的主键命名策略,似乎会忽略任何形式的自定义命名. 也就意味着你给主键命名为idx_pk_id这种形式,在MySQL里面会统一按照PRIMARY来处理. 当然我们可以在这个基础之上做一些拓展和补充. 首先来复现下问题,我们连接到数据库test,然后创建表test_data2. mysql> use test mysql> create table test_data2 (id int ,name varchar(30)); Q

  • 深入分析mysql为什么不推荐使用uuid或者雪花id作为主键

    前言:在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究竟有什么坏处?本篇博客我们就来分析这个问题,探讨一下内部的原因. 一:mysql和程序实例 1.1:要说明这个问题,我们首先来建立三张表,分别是user_auto_key,user_uuid,user_random_key,分别表示自动增长的主键,uuid作为主键,随机

  • 使用prometheus统计MySQL自增主键的剩余可用百分比

    最近生产环境一套数据库因为疯狂写日志数据,造成主键值溢出的情况出现,因此有必要将这个指标监控起来. mysqld_exporter自带的这个功能,下面是我使用的启动参数: nohup ./mysqld_exporter --config.my-cnf="./my.cnf" --web.listen-address=":9104" --collect.heartbeat --collect.auto_increment.columns --collect.binlog

  • Mysql主键UUID和自增主键的区别及优劣分析

    引言 之前有段时间用postgresql 数据库,在上云之后,从自增主键变为uuid,感觉uuid全球唯一,很方便. 最近用mysql,发现mysql主键都是选择自增主键,仔细比较一下,为什么mysql选择自增主键,有什么不同. 在mysql5.0之前,如果是多个master复制的环境,无法用自增主键,因为可能重复.在5.0以及之后的版本通过配置自增偏移量解决了整个问题. 什么情况下我们希望用uuid 1. 避免重复,便于scale,这就是我们做cloud service的时候选择uuid的主要

  • Mysql自增主键id不是以此逐级递增的处理

    Mysql自增主键id不是以此逐级递增 一.介绍 在mysql数据库添加数据时使用ON DUPLICATE KEY UPDATE进行数据更新时可能会出现id不是逐级以此递增的,而是间断递增. 如id从10下次添加可能就是15或者其他的数字,两个数字之间间隔是ON DUPLICATE KEY UPDATE执行的次数,也就是说ON DUPLICATE KEY UPDATE在执行更新的时候把该表主键进行自增加一. 如图所示 二.问题介绍 在对于同一个表进行新增和修改时我用了两个mapper接口方法,也

  • 详解MySQL自增主键的实现

    目录 一.自增值保存在哪儿? 二.自增值修改机制 三.自增值的修改时机 四.自增锁的优化 五.自增主键用完了 一.自增值保存在哪儿? 不同的引擎对于自增值的保存策略不同 1.MyISAM引擎的自增值保存在数据文件中 2.InnoDB引擎的自增值,在MySQL5.7及之前的版本,自增值保存在内存里,并没有持久化.每次重启后,第一次打开表的时候,都会去找自增值的最大值max(id),然后将max(id)+步长作为这个表当前的自增值 select max(ai_col) from table_name

  • Mysql更新自增主键id遇到的问题

    目录 为什么要更新自增id 问题 如何解决 本是一个自己知道的问题,还是差点踩坑(差点忘了,还好上线前整理上线点时想起来了),特此记录下来 为什么要更新自增id 我是因为历史业务上的坑,导致必须更新一批id,且为了避免冲突需要将id扩大多少倍进行更新,因为我这个表的数据数量不高,属于高读低写的情况,所以就简单的扩大了1000 问题 MySQL中如果我们把自增主键更新为更大的值(例如现在自增id最大值是1000,你更新id=49这个记录到id=1049),MySQL并不会把表的自增值修改为更新后的

  • Mybatis高级映射、动态SQL及获得自增主键的解析

    MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis .下文给大家介绍Mybatis高级映射.动态SQL及获得自增主键的内容,具体详情请参考本文. 一.动态SQL 相信大家在用mybatis操作数据库时时都会碰到一个问题,假如现在我们有一个关于作者的list authorList,需要根据authorList里已有的作者信息在数据库中查询相应作者的博客信息.

  • 面试官问订单ID是如何生成的?难道不是MySQL自增主键

    一个美女面试官坐到我的对面,发光logo的MacBook也挡不住她那圆润可爱的脸庞. 程序媛本就稀有,美女面试官更是难寻. 这么温柔可爱的面试官,应该不会为难我吧.嗯,应该是的,毕竟我这么帅气,面试可能就是走个过场.美女面试官是不是单身?毕竟程序员都不善交流,因为我也是单身,难道我的姻缘就在此注定.孩子的名字我都想好了.一冰!好名字. 面试官: 小伙子,你低着头笑什么呐.开始面试了,你知道订单ID是怎么生成的吗? 啥?订单ID怎么生成?美女怎么不按套路出牌!HashMap实现原理,我已经倒背如流

  • spring boot整合mybatis利用Mysql实现主键UUID的方法

    前言 本文主要给大家介绍了关于spring boot整合mybatis利用Mysql实现主键UUID的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 实现 基础项目的pom.xml部分代码如下 <properties> <java.version>1.8</java.version> </properties> <!-- Inherit defaults from Spring Boot --> <parent&

  • 深入谈谈MySQL中的自增主键

    MySQL的主键可以是自增的,那么如果在断电重启后新增的值还会延续断电前的自增值吗?自增值默认为1,那么可不可以改变呢?下面就说一下 MySQL的自增值. 特点 保存策略 1.如果存储引擎是 MyISAM,那么这个自增值是存储在数据文件中的: 2.如果是 InnoDB引擎,1)在 5.6之前是存储在内存中,没有持久化,在重启后会去找最大的键值,举个例子,如果一个表当前数据行里最大 id是10,AUTO_INCREMENT=11.这时候,我们删除 id=10 的行,AUTO_INCREMENT 还

随机推荐