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

2019-09-06 15:01:06 +08:00
 aaronysj

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

18651 次点击
所在节点    程序员
77 条回复
ryd994
2019-09-07 04:37:47 +08:00
@wysnylc 你才抬杠好么
你什么系统做到单节点 100 纳秒多次调用?一般操作系统调度时间都要几十微秒。就算针对低延迟特别调优,你随便处理处理数据 100 纳秒就过去了。你要每秒 1 千万次插入操作才会碰撞。先问问你数据库性能到这个数没有?
就算到了,后面还有 14 位序号,正确使用的话,重复需要超过 10 亿次插入每秒。你用的什么数据库可以做到这个性能?
有这功夫和我杠,为什么不去查一下 UUID 的生成方式,再自己用笔算一下?


@passerbytiny UUID1 是靠生成机制*保证*不可能重复
UUID4 才是拼概率。然而 128 位随机,实际上碰撞概率也是低到忽略不计。
UUID3/5 是靠 hash 算法的碰撞复杂度来拼概率
arraysnow
2019-09-07 10:30:52 +08:00
@ryd994 雪花算法生成的字符串更长,更适用分库分表的高频记录。既然用 uuid 目的是分库,那他造成的性能损失已经无关紧要了。字符串长度不会影响索引速度,内存不够可以再分,io 可以忽略不计
xuanbg
2019-09-07 14:13:26 +08:00
优点一大堆,缺点就一点:因为索引代价大,所以插入性能比较低。尽管插入性能低,每秒写入百十来条数据还是没问题了。
RyanOne
2019-09-07 15:28:07 +08:00
snowflake 强依赖机器时钟,如果机器上时钟回拨,或者分布式环境,每台机器上的时钟不可能完全同步,会导致发号重复或者服务会处于不可用状态。
FrankHB
2019-09-08 22:37:31 +08:00
UUID varchar,呵呵……

@passerbytiny 你搞反了扯蛋的方向。

首先,键的规模开销不是只有空间性能,之前回复的还反过来强调问题主要是响应性能开销。(之后也有别的回复提到。)
其次,对于通常的数据库,每行都有不可压缩的键的情况下,键的规模影响存储成本体现在整行数据中的占比。
注意考虑现有产品的承载能力,大数据的所谓大体现在行而不是列的规模。
存储再不值钱也不保证不要钱,扩大键的存储占用,越大数据绝对成本增加得越大,反而你不怎么大数据倒不用计较那么多。

定性都不正确,你还是不要纠结是不是得抛开具体数字的问题了。

另外真要杠你就该说零概率都不表示不可能事件,所谓的“没有概率”是什么鬼?

@lihongjie0209 要不要自增主键本来就和业务相关。前面有说业务内容了?
lihongjie0209
2019-09-08 22:56:12 +08:00
@FrankHB #65 使用自增主键是业务相关的, 但是使用数据库提供的自增组件就是一个具体的实现, 和 DB 强相关, 你的业务和数据库强相关就是耦合, 也就是难测试
FrankHB
2019-09-08 23:18:14 +08:00
@lihongjie0209 我理解你的意思是不清楚具体业务的场景下,用自增主键是一个实现细节。
但是从业务的角度来讲,是否允许依赖插入有序这个保证通常就是系统设计的基础特性而不是实现细节。如果这样的基础性质会被需求变更推翻,整个数据库设计很可能都得推倒重来。
这类数据库设计的决策本来就得在这种业务需求明确后才能做,你的测试能先于业务需求明确前搭建?考虑这类需求变更导致数据库设计的整体不确定性,你确定这样出来的测试能覆盖多少内容才能确保业务变化有更大适应性?特别地,一些业务就算不用自增主键,也得用其它逻辑来实现这个保证,你如何应对测试这些东西的需求——测试 DB 可能确实是简单了,但测试整个系统呢?
lihongjie0209
2019-09-08 23:40:59 +08:00
@FrankHB #67
1. 好的架构应该是存储无关的(尽可能)
2. 业务就管好业务, 要有序就在程序中实现, 加一个额外的排序字段就可以了
3. 业务需求作为最重要的核心, 应该是第三方(数据库)依赖于业务需求, 比如数据量大了上 nosql,但是你的业务需求不应该依赖于数据库, 这是依赖倒置原则。
4. 我的测试不会先于需求, 但是我的设计理念高于需求。
5. 需求变化导致数据库变化是正常现象, 数据库依赖于业务!!!变就变嘛, 软件写出来就是用来改的。
6. 不使用数据库的自增主键那么测试就会很简单, 自己写的代码实现的纯业务代码怎么不能测试了。
7. 测试业务逻辑(单元测试)和测试整个系统(集成测试)本来就是不同层面的东西, 二者的需求和测试量是不同的, 也没有任何依赖关系。 单元测试的简单与否与集成测试的可测试性没有关系。


以上观点来自《 Clean Architecture 》
Elecoxy
2019-09-09 09:05:11 +08:00
crazy 使用 uuid 做主键?!?
wysnylc
2019-09-09 11:10:22 +08:00
@ryd994 #61 uuid 的生成方式有多种,你让我看哪种?还是你觉得只有一种?
雪花算法是 Twitter 提出的算法,请问你比 Twitter 厉害吗?
雪花算法生成的是 long,uuid 是字符串请问哪个好?
uuid 的不同生成算法会依赖不同的种子,例如 time-based:基于时间的 UUID name-based:基于名字的 UUID,通过计算名字和名字空间的 MD5 来计算 UUID 所以 uuid 就不能重复?谁说碰撞非得每秒使用到 1630 亿个 uuid?可笑
memi
2019-09-09 15:25:17 +08:00
@love 您好,请教下。uuid 业界一般用什么字段存比较好,我看了我之前写的 demo 都是用 varchar 存的 T_T。
FrankHB
2019-09-21 22:49:20 +08:00
@lihongjie0209
1.我认为“存储无关”决定架构优劣这是教条,并且有悖常理。
因为架构设计是服务于业务的,是不是允许系统设计依赖甚至鼓励依赖某个子系统(不管是持久化层还是你这里说更具体的“存储”这样的实现)的特征以便使系统容易具有其它优势,这根本还是业务需求说了算。
而且,强制要求先划分出存储还可能使实现容易违反一些其它更一般的普遍原则,比如 Principle of least privilege。
2.决定存储在哪里实现本身就是需要设计决策确定的一个问题,不能总是简单地排除出业务之外。
3.更一般地,数据库实际上不过是存储(或者持久化层)的一种实现。预先要求依赖某种数据库也是应该在普遍的架构设计中避免的——只不过这个主题的题设已经限定了数据库这个背景而已。
4.设计是需求的解。你的“高于需求”的理念不符合工程上一般意义的认知,这个矛盾看来需要你在落实设计之前解决。
5.设计的变化不一定成问题,但是为了变化付出太大的成本可能成问题。(另外,明确架构设计的一个作用就是为了避免这种成本太大。)不是任意的变化都应该是被无条件接受的。
6.你似乎认为测试数据库总是困难的,测试别的模块总是比测试数据库简单。不过事实上恐怕未必总是如此。
的确有几种强行让业务逻辑看起来总是更容易测试的设计套路,但是因为会限制表达能力,并不是每个业务领域都允许这样。
7.这点原则上我同意你的意见,虽然严格来讲测试业务逻辑不总是单元测试,这是和这里内容没有直接关系的次要话题。我的提法有些不够清楚,原意是指整个系统中的其它模块。
ruandao
2020-01-15 10:17:43 +08:00
@Raymon111111

劣势
1. 不自增, 插入性能会有点问题. 这个和索引的结构有关系, 往中间插一个数据如果遇上当页数据满了后面都得重做


存在这个问题吗?

uuid1 不是时间顺序的吗?

我现在感觉,问题好像就只有要进索引,但是太大
sherlockfff
2020-06-29 10:39:02 +08:00
@love
uuid 长度为 128bit,16 字节,以 mysql 来看,数值类型中最大的 bigint 为 8 字节,所以没法用数值
sherlockfff
2020-06-29 10:40:51 +08:00
@singworld 那主键是用数值类型吗?
那对于上面提到的那些缺点,如分库等情况怎么处理呢
love
2020-06-29 11:00:49 +08:00
@sherlockfff mysql 有二进制数据类型
huanghq
2020-10-21 10:50:20 +08:00
以前做个一个项目,自增 id 做主键,另加 UUID 字符串字段做唯一索引。
内部使用自增 ID 关联,暴露在外部的 api 使用 uuid.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/598593

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX