网易首页 > 网易号 > 正文 申请入驻

公司新来一个技术总监:禁止将 UUID 和雪花 ID 列入主键选型!

0
分享至

钓友宝 (微信小程序):一款专门为 钓友 开发的 免费的 分享钓点地图与实时天气的软件,地图中标记了所有野钓、钓场、公共水域等的精确位置,支持导航、 预测钓鱼位置的鱼情 等功能。
前言

在 mysql 中设计表的时候,mysql 官方推荐不要使用 uuid 或者不连续不重复的雪花 id(long 形且唯一,单机递增),而是推荐连续自增的主键 id,官方的推荐是 auto_increment,那么为什么不建议采用 uuid,使用 uuid 究竟有什么坏处?

一、mysql 和程序实例

1.1.要说明这个问题,我们首先来建立三张表

分别是 user_auto_key,user_uuid,user_random_key,分别表示自动增长的主键,uuid 作为主键,随机 key 作为主键,其它我们完全保持不变。

根据控制变量法,我们只把每个表的主键使用不同的策略生成,而其他的字段完全一样,然后测试一下表的插入速度和查询速度:

注:这里的随机 key 其实是指用雪花算法算出来的前后不连续不重复无规律的 id:一串 18 位长度的 long 值

id 自动生成表:

用户 uuid 表:

随机主键表:

1.2.光有理论不行,直接上程序,使用 spring 的 jdbcTemplate 来实现增查测试:

技术框架:springboot+jdbcTemplate+junit+hutool,程序的原理就是连接自己的测试数据库,然后在相同的环境下写入同等数量的数据,来分析一下 insert 插入的时间来进行综合其效率,为了做到最真实的效果,所有的数据采用随机生成,比如名字、邮箱、地址都是随机生成。

package com.wyq.mysqldemo; import cn.hutool.core.collection.CollectionUtil; import com.wyq.mysqldemo.databaseobject.UserKeyAuto; import com.wyq.mysqldemo.databaseobject.UserKeyRandom; import com.wyq.mysqldemo.databaseobject.UserKeyUUID; import com.wyq.mysqldemo.diffkeytest.AutoKeyTableService; import com.wyq.mysqldemo.diffkeytest.RandomKeyTableService; import com.wyq.mysqldemo.diffkeytest.UUIDKeyTableService; import com.wyq.mysqldemo.util.JdbcTemplateService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.util.StopWatch; import java.util.List; @SpringBootTest classMysqlDemoApplicationTests{     @Autowired     private JdbcTemplateService jdbcTemplateService;     @Autowired     private AutoKeyTableService autoKeyTableService;     @Autowired     private UUIDKeyTableService uuidKeyTableService;     @Autowired     private RandomKeyTableService randomKeyTableService;     @Test     voidtestDBTime(){         StopWatch stopwatch = new StopWatch("执行sql时间消耗");         /**          * auto_increment key任务          */         final String insertSql = "INSERT INTO user_key_auto(user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?)";         List insertData = autoKeyTableService.getInsertData();         stopwatch.start("自动生成key表任务开始");         long start1 = System.currentTimeMillis();         if (CollectionUtil.isNotEmpty(insertData)) {             boolean insertResult = jdbcTemplateService.insert(insertSql, insertData, false);             System.out.println(insertResult);         }         long end1 = System.currentTimeMillis();         System.out.println("auto key消耗的时间:" + (end1 - start1));         stopwatch.stop();         /**          * uudID的key          */         final String insertSql2 = "INSERT INTO user_uuid(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)";         List insertData2 = uuidKeyTableService.getInsertData();         stopwatch.start("UUID的key表任务开始");         long begin = System.currentTimeMillis();         if (CollectionUtil.isNotEmpty(insertData)) {             boolean insertResult = jdbcTemplateService.insert(insertSql2, insertData2, true);             System.out.println(insertResult);         }         long over = System.currentTimeMillis();         System.out.println("UUID key消耗的时间:" + (over - begin));         stopwatch.stop();         /**          * 随机的long值key          */         final String insertSql3 = "INSERT INTO user_random_key(id,user_id,user_name,sex,address,city,email,state) VALUES(?,?,?,?,?,?,?,?)";         List insertData3 = randomKeyTableService.getInsertData();         stopwatch.start("随机的long值key表任务开始");         Long start = System.currentTimeMillis();         if (CollectionUtil.isNotEmpty(insertData)) {             boolean insertResult = jdbcTemplateService.insert(insertSql3, insertData3, true);             System.out.println(insertResult);         }         Long end = System.currentTimeMillis();         System.out.println("随机key任务消耗时间:" + (end - start));         stopwatch.stop();         String result = stopwatch.prettyPrint();         System.out.println(result);     }

1.3.程序写入结果

user_key_auto 写入结果:

user_random_key 写入结果:

user_uuid 表写入结果:

1.4.效率测试结果

在已有数据量为 130W 的时候:我们再来测试一下插入 10w 数据,看看会有什么结果:

可以看出在数据量 100W 左右的时候,uuid 的插入效率垫底,并且在后序增加了 130W 的数据,uudi 的时间又直线下降。

时间占用量总体可以得出的效率排名为:auto_key>random_key>uuid,uuid 的效率最低,在数据量较大的情况下,效率直线下滑。那么为什么会出现这样的现象呢?带着疑问,我们来探讨一下这个问题。

二、使用 uuid 和自增 id 的索引结构对比

2.1.使用自增 id 的内部结构

自增的主键的值是顺序的,所以 Innodb 把每一条记录都存储在一条记录的后面。当达到页面的最大填充因子时候(innodb 默认的最大填充因子是页大小的 15/16,会留出 1/16 的空间留作以后的修改):

  • 下一条记录就会写入新的页中,一旦数据按照这种顺序的方式加载,主键页就会近乎于顺序的记录填满,提升了页面的最大填充率,不会有页的浪费;

  • 新插入的行一定会在原有的最大数据行下一行,mysql 定位和寻址很快,不会为计算新行的位置而做出额外的消耗;

  • 减少了页分裂和碎片的产生。

2.2.使用 uuid 的索引内部结构

因为 uuid 相对顺序的自增 id 来说是毫无规律可言的,新行的值不一定要比之前的主键的值要大,所以 innodb 无法做到总是把新行插入到索引的最后,而是需要为新行寻找新的合适的位置从而来分配新的空间。

这个过程需要做很多额外的操作,数据的毫无顺序会导致数据分布散乱,将会导致以下的问题:

写入的目标页很可能已经刷新到磁盘上并且从缓存上移除,或者还没有被加载到缓存中,innodb 在插入之前不得不先找到并从磁盘读取目标页到内存中,这将导致大量的随机 IO

因为写入是乱序的,innodb 不得不频繁的做页分裂操作,以便为新的行分配空间,页分裂导致移动大量的数据,一次插入最少需要修改三个页以上

由于频繁的页分裂,页会变得稀疏并被不规则的填充,最终会导致数据会有碎片

在把随机值(uuid 和雪花 id)载入到聚簇索引(innodb 默认的索引类型)以后,有时候会需要做一次 OPTIMEIZE TABLE 来重建表并优化页的填充,这将又需要一定的时间消耗。

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

2.3.使用自增 id 的缺点

那么使用自增的 id 就完全没有坏处了吗?并不是,自增 id 也会存在以下几点问题:

别人一旦爬取你的数据库,就可以根据数据库的自增 id 获取到你的业务增长信息,很容易分析出你的经营情况

对于高并发的负载,innodb 在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点,因为所有的插入都发生在这里,并发插入会导致间隙锁竞争

Auto_Increment 锁机制会造成自增锁的抢夺,有一定的性能损失。

附:Auto_increment 的锁争抢问题,如果要改善需要调优 innodb_autoinc_lock_mode 的配置
三、总结

本篇博客首先从开篇的提出问题,建表到使用 jdbcTemplate 去测试不同 id 的生成策略在大数据量的数据插入表现,然后分析了 id 的机制不同在 mysql 的索引结构以及优缺点,深入的解释了为何 uuid 和随机不重复 id 在数据插入中的性能损耗,详细的解释了这个问题。

在实际的开发中还是根据 mysql 的官方推荐最好使用自增 id,mysql 博大精深,内部还有很多值得优化的点需要我们学习。

附:本篇博客 demo 地址:https://gitee.com/Yrion/mysqlIdDemo

Java精选面试题 (微信小程序):5000+道面试题和选择题,包含Java基础、MQ、Redis、SpringBoot、Elasticsearch、Docker、K8s、Flink、Spark、架构设计、大厂真题等,在线随时刷题!
来源:https://www.cnblogs.com/wyq178/p/12548864.html

公众号“Java精选”所发表内容注明来源的,版权归原出处所有(无法查证版权的或者未注明出处的均来自网络,系转载,转载的目的在于传递更多信息,版权属于原作者。如有侵权,请联系,笔者会第一时间删除处理!

最近有很多人问,有没有读者或者摸鱼交流群!加入方式很简单,公众号Java精选,回复“加群”,即可入群!

文章有帮助的话,点在看,转发吧!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
吴君如早就说过:陈妍希私下根本不是什么清纯女孩,穿得着大胆得很

吴君如早就说过:陈妍希私下根本不是什么清纯女孩,穿得着大胆得很

八卦王者
2026-02-21 16:06:57
美国开始秋后算账!前市长双重身份骗取国籍20年,如今面临剥夺!

美国开始秋后算账!前市长双重身份骗取国籍20年,如今面临剥夺!

华人生活网
2026-02-23 02:28:10
没有不透风的墙!沈腾和林允的瓜未必是假的、站姐关站跑路

没有不透风的墙!沈腾和林允的瓜未必是假的、站姐关站跑路

草莓解说体育
2026-02-22 10:20:13
“被亏待的人就这面相”,大二女生视频火了,不被爱的痕迹太明显

“被亏待的人就这面相”,大二女生视频火了,不被爱的痕迹太明显

妍妍教育日记
2026-02-06 20:18:00
谁能想到,国内几块钱一沓的冥币,在海外居然摇身变为奢侈品

谁能想到,国内几块钱一沓的冥币,在海外居然摇身变为奢侈品

有书
2026-02-22 20:30:04
贾乃亮带全家吃全鱼宴,甜馨坐爸爸旁边埋头猛吃,一家人其乐融融

贾乃亮带全家吃全鱼宴,甜馨坐爸爸旁边埋头猛吃,一家人其乐融融

月下守候
2026-02-23 00:16:17
存储芯片,正在接过AI行情的接力棒

存储芯片,正在接过AI行情的接力棒

扬子晚报
2026-02-22 19:20:03
一夜消失近30家!村镇银行大洗牌:功成身退还是排雷安民?

一夜消失近30家!村镇银行大洗牌:功成身退还是排雷安民?

小陆搞笑日常
2026-02-20 21:02:29
某鱼惊现“天价笔”:800元一支的中性笔,藏着多少肮脏暗语?

某鱼惊现“天价笔”:800元一支的中性笔,藏着多少肮脏暗语?

戗词夺理
2026-01-24 16:05:41
哲凯赖什本赛季英超进球已上双,为阿森纳队内第一人

哲凯赖什本赛季英超进球已上双,为阿森纳队内第一人

懂球帝
2026-02-23 02:52:41
医生发现:若每天早上都吃面条,用不了多久,身体或有这6个变化

医生发现:若每天早上都吃面条,用不了多久,身体或有这6个变化

阿兵科普
2026-01-24 09:43:03
不是血统问题!美媒主编点破:谷爱凌争议,只因她是美国本可拥有的王牌

不是血统问题!美媒主编点破:谷爱凌争议,只因她是美国本可拥有的王牌

草莓解说体育
2026-02-18 03:01:17
中国的社保压力超乎想象,不投资,过几年可能就不够用了

中国的社保压力超乎想象,不投资,过几年可能就不够用了

流苏晚晴
2026-02-22 15:20:23
轰27+5!中国男篮19岁2米03新星闪耀:全美高中第25位创纪录

轰27+5!中国男篮19岁2米03新星闪耀:全美高中第25位创纪录

李喜林篮球绝杀
2026-02-22 09:23:52
一日之计在于晨,安徽合肥一位女士却在清晨遭遇了“饭桌浩劫”

一日之计在于晨,安徽合肥一位女士却在清晨遭遇了“饭桌浩劫”

娱乐的硬糖吖
2026-02-22 11:52:34
正常的乳房到底长什么样?(内附图解)

正常的乳房到底长什么样?(内附图解)

第十一诊室
2026-01-31 11:36:21
武汉病毒研究所有重大发现

武汉病毒研究所有重大发现

越乔
2026-02-22 10:43:29
为什么五百万人民币在全球都算中产,在网上却被认为穷困潦倒?

为什么五百万人民币在全球都算中产,在网上却被认为穷困潦倒?

小白鸽财经
2026-02-02 07:05:03
越南副主席黄文欢,因不满反华被判死刑,投奔中国后,结局如何?

越南副主席黄文欢,因不满反华被判死刑,投奔中国后,结局如何?

近史谈
2026-02-15 07:41:48
一度被认为灭绝!2025年云南一山洞中发现6条,已消失近半个世纪

一度被认为灭绝!2025年云南一山洞中发现6条,已消失近半个世纪

万象硬核本尊
2026-01-03 19:30:50
2026-02-23 04:07:00
Java精选
Java精选
一场永远也演不完的戏
1772文章数 3859关注度
往期回顾 全部

科技要闻

马斯克:星舰每年将发射超过10000颗卫星

头条要闻

男子持霰弹枪燃烧罐闯特朗普私宅被击毙 细节披露

头条要闻

男子持霰弹枪燃烧罐闯特朗普私宅被击毙 细节披露

体育要闻

谷爱凌:6次参赛6次夺牌 我对自己非常自豪

娱乐要闻

谷爱凌:真正的强大 敢接纳生命的节奏

财经要闻

特朗普新加征关税税率从10%提升至15%

汽车要闻

续航1810km!smart精灵#6 EHD超级电混2026年上市

态度原创

亲子
时尚
数码
健康
公开课

亲子要闻

萌娃看见阿姨的大肚子竟这样说,着急的样子萌化了

50+女人更适合基础款,掌握3个高段位搭配思路,轻松提升品味

数码要闻

古尔曼:苹果3月2 - 4日发布“至少五款产品”

转头就晕的耳石症,能开车上班吗?

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版