UUID 做主键有什么优势和劣势?

gger 11月前 133

之前做过的项目,基本都是用自增 id 做主键或者没有主键。这次领导突然说用 UUID varchar(36)位做主键,让小弟有点迷惑,望大家指点迷津。

最新回复 (62)
  • 全麦 11月前
    引用 2
    分库
  • ahost 11月前
    引用 3
    不容易被人看出规律(隐藏用户数量), 散列好,做缓存字段更好处理, 不用自增降低数据库消耗,也更适合做分布式系统主键, 长度比 int 好, 字符串做主键也不会出现 long 型导致前端 js 麻烦问题

    缺点也就性能差点
  • 颠峰布衣飘 11月前
    引用 4
    *据说*,字符串的主键在某些 DB 下会有一些性能问题(毕竟数字就一个,字符串是一堆)
    压力不很大的话,snowflake + big int 也够用了
  • hxyz 11月前
    引用 5
    优势就是唯一了,劣势一堆,字符串还是不要用来做主键的好,浪费存储,mysql 有热数据的,不利于连续的热数据加载
  • 萌萌哒 11月前
    引用 6
    优势是猜不出来,劣势是采用聚簇索引时候会影响插入性能
  • ses10086 11月前
    引用 7
    劣势就是太长了啊,存着浪费空间。

    如果是为了如 所说隐藏规律,那可以写一个通过数字 id 加密生成一个无规律的字符串的方法。
  • 夜樱旅人 11月前
    引用 8

    这种做法一般得用 long, 比如上面说的 snowflake
    long 在 js 上很麻烦,还要特意转为 string
  • Cllp 11月前
    引用 9
    uuid 这种方案其实挺尴尬的,小项目不需要,而大项目性能又不好
  • blanco 11月前
    引用 10
    如果是 MySQL innodb,非自增主键空间利用率低 and 插入性能稍差
    详细原因请自行了解 B+树的原理
  • kwx 11月前
    引用 12
    我们是两者都有,系统内部用自增 id 做主键,系统间 RPC 用 uuid 标识唯一用户
  • 全民护苗 11月前
    引用 13
    项目大了好分库,小项目主键哪个都差不多,大项目肯定不能用自增,所以业务扩展上 uuid 比较好。说 uuid 性能问题的,你真的让 uuid 有性能影响的时候,其它地方的瓶颈才是重点……
  • 优势就是猜不出规律

    劣势就是浪费存储和索引性能
  • 浪子之心 11月前
    引用 15
    没啥优势. 推荐用趋势递增的 long 型数字.
  • lonefly 11月前
    引用 16
    优势:无规律,碰撞小
    劣势:无规律,大数据量一样会碰撞
    总结:建议使用雪花算法等解决碰撞问题
  • meshell 11月前
    引用 17
    哈哈 看来我下一主题 就是怎么劝领导放弃 UUID 做主键了
    感谢 我在一篇博客里看到过这种
  • gain_loc 11月前
    引用 18
    ORM 那边可以做一个 trick
    类里写的是 UUID 其实 db 里存的是 big int 哒
  • REIJI 11月前
    引用 19
    有种东西叫做时间有序 UUID,在数据库中的性能依然很好

    https://www.codeproject.com/Articles/388157/GUIDs-as-fast-primary-keys-under-multiple-database
  • 003 11月前
    引用 20
    用自增 ID 做物理主键,再加一个 uuid 做逻辑主键(加 unique 索引),在外键关联的时候用逻辑主键,这样子在分库的时候无痛, 也不会遇到 uuid 作为物理主键的时候遇到的性能问题。唯一的 issuse 就是会浪费一部分存储空间
  • bax 11月前
    引用 21
    我觉得对 UUID 作为 DB 的主键有着错误的认知,UUID 可以实现微秒精度的时间有序
  • vpsou 11月前
    引用 22
    优势就是全局唯一了,但是劣势嘛,性能会差
  • ljm4216 11月前
    引用 23
    主键还是自增,给每条数据分配 uuid 不是更好?有问题?
  • elliot 11月前
    引用 24
    优势是可分布式唯一

    劣势性能差,浪费空间 和 自增比
  • jiaomangege 11月前
    引用 25
    雪花了解一下 .
  • yuchongwei 11月前
    引用 26
    雪花超级好用 ,数字主键对新能提升也超级棒
  • bonnod 11月前
    引用 27
    UUID 性能差?少写点 bug,什么都有了
  • 揽月 11月前
    引用 28
    优点:
    1.可以用来做分布式 id 更方便;
    2. 具有唯一性, 可以让数据分布的更均匀;
    3.字符串可以屏蔽掉 java 和 js 的一些数据类型差异,比如使用 Long 时如果数字过大会产生问题;
    缺点:
    1.太长了,主键会被用作聚簇索引,每次插入都要损耗不少性能,bigint 也才 8 个字节;
    2.临近的数据没有相关性,不能有效利用局部性原理节省性能;
    3.进行范围查询时会扫描过多的页,性能不好,这点和 2 类似。
    优先推荐 Twitter 的 snowflake,但需要记得在最外层和前端交互时使用 String
  • 哦,我的天 11月前
    引用 29
    优势:完全业务无关,完全与数据库无关,意味着生成迅速、生成简单、全局统一、不依赖底层基础设施。
    劣势:完全业务无关,完全与数据库无关,意味着不是自然主键(你需要另加唯一索引字段才能有自然主键)、不直观、底层基础设施的性能优化措施用不上。

    至于前面那些人所说的“太长”的劣势,这纯粹是人云亦云,早期存储值钱的时候还可以这么说,现在都大数据了,还这么说就是扯淡。另外,UUID 本质上是 16 字节 128 位二进制数据,如果没有特殊需要(懒得加额外的自然主键,直接拿 UUID 做不那么高效的自然主键),那么 UUID 就没必要再 dump 成 32/36 字节的字符串,直接用十六字节长度二进制类型进行存储。
  • nisngyo 11月前
    引用 30
    数据库无关, 你的几百行业务代码中, 各种数据库插入就是为了获取自增 ID, 然后给后面业务逻辑用。

    如果我们使用 UUID, 那么你的业务代码中数据库操作出现的概率会小很多, 方便测试, 也是一种解耦
  • songkqx1c 11月前
    引用 31
    UUID 用什么 varchar ?
    首先 UUID 是定长的,不需要变长类型。定长类型在储存和索引时有优势
    其次 UUID 是 hex,一共才 36 种字母数字,为什么作为 text 存?任何 UUID 完全可以导出为二进制
    数据库提供 UUID 数据类型时存 UUID 类型。原因是比较顺序。UUID1 前几位是机器代号,最后才是随机数。所以最好从后往前建立索引,这样可以帮助索引自然平衡。

    UUID 最适合分库的情况,UUID 的随机性保证了分库的平均。同时结合机器代号可以保证不同机器无需单点也能保证不碰撞。
  • fansfan 11月前
    引用 32
    最后,主键只是数据库内在的储存结构的一部分。如果你用的是单机或者客户端了解的分表分库,那自增主键的性能反而更好
    楼上说什么方便给用户的,你自己想想看,数据库主键直接暴露给用户,这是求人碰撞攻击你吗?给用户看到的 token 为什么不和内部 ID 解耦? token 和 id 解耦之后还能 revoke
    就算用自增主键,也可以另外生成一个带索引的 token 字段,隐藏用户 ID 和主键用什么,没有半毛钱关系

    再吐槽一下 varchar 做主键,存的是 UUID。真的不知道在想什么。任何读过数据库的用户手册的人都想不出这样的主意。你就没有想过为什么某些数据库要专门做个 UUID 类么?
  • matolv 11月前
    引用 33
    和储存无关,主键要进索引的。硬盘是不值钱,但是 1.内存值钱 2.CPU cache 值钱 3.硬盘 IO 操作数量 /延迟值钱
    能不能用?能
    但是数据量上来以后性能会很差
  • leftgg 11月前
    引用 34
    正确使用 UUID1 是不会有碰撞的。要碰撞需要你在 100 纳秒内反复生成还刚好遇上随机数碰撞
    UUID4 是纯随机,鉴于值域有 128bit,你可以算算 10 年内碰撞到一次需要多高的频率。实际上也基本可以忽略,当然,比不上 UUID1 的绝对保证。优点是不依赖,不暴露机器信息
    其他 UUID 各有生成逻辑,使用之前彻底搞懂生成逻辑,然后论证为什么可以避免碰撞即可。
  • Path 11月前
    引用 35
    最直接的好处是,避免被穷举
  • hotsky 11月前
    引用 36
    劣势
    1. 不自增, 插入性能会有点问题. 这个和索引的结构有关系, 往中间插一个数据如果遇上当页数据满了后面都得重做

    2. 数据量大一点碰撞是很常见的, 或者可以说是必现的, 按天维度 (这个可以搜一下别人的使用经验)
  • ailaike 11月前
    引用 37
    UUID 优势:
    1、避免 API 接口传入恶意 ID,试图绕过验证
    2、分库不用担心 ID 冲突
    3、web 端不用考虑 ID 精度丢失,因为是字符串
    3、UUID 理论上无限大,可以认为插入无限量的 ID,而序列是有限的

    UUID 劣势:
    1、相对序列耗费资源
    2、文本的索引效率相对低了一点
  • cherbim 11月前
    引用 38
    减少对具体数据库的主键依赖
  • 砍柴郎 11月前
    引用 39
    雪花也不是没有缺点,对系统时钟有严格要求
  • backlitz 11月前
    引用 40
    UUID 优势:
    1、避免 API 接口传入恶意 ID,试图绕过验证
    2、分库不用担心 ID 冲突
    3、web 端不用考虑 ID 精度丢失,因为是字符串
    4、UUID 理论上无限大,可以认为插入无限量的 ID,而序列是有限的
    5、不需要维护 ID 的顺序

    UUID 劣势:
    1、相对序列耗费资源
    2、文本的索引效率相对低了一点
  • soyeo 11月前
    引用 41
    其实为啥要把表主键和数据主键弄成一个,是不是表自身还是有个自增的 int 主键 ID 更好一些?数据再有个非线性可分布式的数据主键
  • TyrielWW 11月前
    引用 42
    UUID 数据量的大话会有吃屎的感觉,别问我咋知道的。。。。。。。
  • fl20002 11月前
    引用 43
  • 吃货 11月前
    引用 44
    哪怕用 UUID 也不要 varchar(36) 啊,8 个二进制字节的事你搞这么大干嘛
  • bbx188 11月前
    引用 45
    #33 都说了大数据量,概率再低不是没有概率
    我明确说明是大数据量就是防止你这种说概率低的抬杠,没想到你还是来了
  • cnly1987 11月前
    引用 46
    直接搞个 id 生成服务, 和数据库自增一样的。
    唯一缺点就是要单独部署一个服务
  • hostvps 11月前
    引用 47
    分布式只能用 UUID 的情况。

    假定我是一个公开的接口,有不特定的若干个客户端。
    没个客户端给我们系统发送请求的时候,又需要这些请求记录都保存在 db 中。

    这种需求就让客户端自己发 UUID 作为主键,你们随便发,保证不会冲突。

    这是一种必须用 UUID 的场景。
  • 圼逍遥 11月前
    引用 48
    建议用雪花算法
  • foboy 11月前
    引用 49
    #39 照你这“概率再低不是没有概率”的说法,下雨天就不能出门,遭雷劈的概率可要比 UUID 碰撞发生的概率高的多。抛开具体数字去说“大”,你这才是真正的抬杠。
  • xiaoluo 11月前
    引用 50
    劣势很明显,不自增
  • 怪人 11月前
    引用 51
    #48 爱抬你就多抬点,我当乐子看
  • 绝望法师 11月前
    引用 52
    uuid 碰撞和什么大数据量没关系

    关键是两点,吞吐和生成 uuid 的机器
  • ADC 11月前
    引用 53
    我们是用的 PG 自带的 uuid 生成。_(:з」∠)_
  • 京东 11月前
    引用 54
    求楼主头像的高清大图……
  • ansheng 11月前
    引用 55
    前公司代码规范里 禁止使用 uuid 做主键
  • loeveo 11月前
    引用 56
    优势是简单,劣势是性能差,而且差到在有的场景成为瓶颈
  • poctopus 11月前
    引用 57
    各方面都有优势,劣势是总有人用字符串存他
  • pxy185 11月前
    引用 58
    如果是 INNODB 的话,索引结构是一颗 B+树,叶子节点存储的是索引的值,如果存递增的数字作为索引,那么无论是空间还是在一定范围内搜索都是高效的,如果存一段 UUID,真想不出有什么优势。
    有人提到可以搞分布式+大数据量,但是 Mysql 本来就不是干这个事情的,如果是量级达到这个级别不如换成 HBase
  • liugogal 11月前
    引用 59
    靠 uuid 反爬根本就是掩耳盗铃。等把所有主键都换成 uuid,我想知道服务端一条日志能有多长。
  • 方块李 11月前
    引用 60
    UUID 劣势是因为 mysql 索引是 B+树的结构导致的
  • dzwangfei 11月前
    引用 61
    你应该先补充一下索引结构的知识,就是到上面大家说的 UUID 索引性能差是为什么了
  • 引用 62
    你才抬杠好么
    你什么系统做到单节点 100 纳秒多次调用?一般操作系统调度时间都要几十微秒。就算针对低延迟特别调优,你随便处理处理数据 100 纳秒就过去了。你要每秒 1 千万次插入操作才会碰撞。先问问你数据库性能到这个数没有?
    就算到了,后面还有 14 位序号,正确使用的话,重复需要超过 10 亿次插入每秒。你用的什么数据库可以做到这个性能?
    有这功夫和我杠,为什么不去查一下 UUID 的生成方式,再自己用笔算一下?


    UUID1 是靠生成机制*保证*不可能重复
    UUID4 才是拼概率。然而 128 位随机,实际上碰撞概率也是低到忽略不计。
    UUID3/5 是靠 hash 算法的碰撞复杂度来拼概率
  • 东方星雨 11月前
    引用 63
    雪花算法生成的字符串更长,更适用分库分表的高频记录。既然用 uuid 目的是分库,那他造成的性能损失已经无关紧要了。字符串长度不会影响索引速度,内存不够可以再分,io 可以忽略不计
返回
发新帖