如题,MySQL(5.7) 用 uuid 作为主键会导致“页分裂”,这种影响大吗,是否可以忽略?
1
erquiasz0825 OP 补充:uuid 非自增
|
2
Rumble66 2022-07-02 19:32:47 +08:00
非常大, 最好用有序自增整形做主键.
不仅是插入性能差, 查询性能也差. |
3
erquiasz0825 OP |
4
thinkershare 2022-07-02 19:45:17 +08:00 1
@erquiasz0825 因为按照分页查询时候, 数据会分散到不同的页, GUID 这种如果要作为主索引, 一定要支持自增, 否则插入 /查询都会有不小的性能损失. GUID 有自增的算法版本
|
5
Jooooooooo 2022-07-02 20:13:30 +08:00
设计一个毫秒时间戳+机器码+随机数的方案, 全本地操作, 也不复杂.
|
6
cxxlxx 2022-07-02 20:19:26 +08:00 1
@erquiasz0825 关于第二点,可以使用这个 进行转换 https://hashids.org/
|
7
cheng6563 2022-07-02 20:37:06 +08:00
换 ksuid
|
8
haoooooo 2022-07-02 20:46:55 +08:00
雪花
|
9
potatowish 2022-07-02 21:04:19 +08:00 via iPhone
用数据库自增保存原始 id ,对外用 hashid 包装
|
10
makelove 2022-07-02 21:05:41 +08:00
id 不想暴露的方法多了,比如上面的 hashid ,哪怕另建一列 uuid 当公开 id 都比用 uuid 作主键好,因为所有索引项都会包含主键,用 uuid 浪费内存和硬盘
|
11
ToBeHacker 2022-07-02 21:55:56 +08:00
看你是不是需要有序遍历或展示吧
|
12
erquiasz0825 OP |
13
lessMonologue 2022-07-03 00:32:02 +08:00
@erquiasz0825 根据主键 id 查实体,然后把这个实体对应的 uuid 返回出去吧。OP 应该去看看 InnoDB 的主键索引建立过程。
|
14
thinkershare 2022-07-03 00:43:49 +08:00
@makelove uuid 并不浪费内存, UUID 在很多数据库的实现中使用了 8 个字节, 也就是 2 倍 long 的长度, uuid 完全可以做到高效, 除非性能特别重要, 而且单个表数据极大, 否则选择 uuid 是一个很不错的选择, 性能是一个需要基准测试问题. 绝大部分系统的性能问题都不会因为你使用了 UUID 而导致. 反而我非常推荐使用 UUID 作为 id.
|
15
cheng6563 2022-07-03 00:56:44 +08:00
@thinkershare MySQL 没有原生 UUID 类型,要存 UUID 要么用 binary 要么用 varchar ,前者难用后者废空间。而且 UUID v4 也确实不太适合用 B+树来索引。
|
16
LostPrayers 2022-07-03 01:12:03 +08:00
如果是 JAVA 用 MybatisPlus 库,主键可以选 IdType.ASSIGN_ID (雪花算法的 bigint), 或者用自增 IdType.Auto (数据库自增)
|
17
Soar360 2022-07-03 02:07:54 +08:00
我用多主键比较多
|
18
ipwx 2022-07-03 02:30:58 +08:00
我不是 MySQL 玩家。PostgreSQL 如果用 uuid 肯定是为了在可预见的将来,对象互相引用的 ID 不会发生改变。我觉得这是 UUID 最大的作用。
|
19
elboble 2022-07-03 06:48:22 +08:00 via Android
Mongodb 的 id 好像是 uuid 但是还是有序递增的
|
20
makelove 2022-07-03 07:26:55 +08:00 1
@thinkershare 8 字节的 uuid ?给个链接让我开开眼?
|
21
zhuweiyou 2022-07-03 07:40:00 +08:00
snowflake 或 uuid_short
|
23
qaqLjj 2022-07-03 10:28:13 +08:00
建议采用雪花号,补一个之前做的总结:
UUID 为什么不推荐做索引? 1. 长度太长,int 4 b ,bigint 8 b ,但是 uuid 是 32 位字符串即 32 b ,一个 uuid 索引占用空间是 int 的 8 倍,是 bigInt 的 4 倍,这会导致二分查找遍历的页增多,甚至可能导致 b+ 树的层高变高,并且,每个二级索引都会存储主键 id 用于回表,如果主键太长,整个表的其他索引也会被拖慢 2. 没有顺序,会将顺序写变为随机写,产生多余的页分裂,多余的页缓存失效处理 3. 比较性能不佳,字符串比大小要先查码表再比较,整形直接就比较了 |
25
adoal 2022-07-03 12:35:26 +08:00 via iPhone
UUID 没毛病,但是在 MySQL 上用嘛……连原生支持都没有,就像上面有 v 友说的,你打算当 binary 还是 text ?
|
26
realpg 2022-07-03 14:34:56 +08:00
|
27
realpg 2022-07-03 14:51:11 +08:00
比如 我给你设计个算法
把数据库的 ID 起始设置为 10000001 确保位数不会太短 首先,生成两个随机数字[0-9] 分别为 x 和 y 把 ID 拆分成个位数的数字数组 a b c d e f g h i ... 然后遍历数组,a 乘以 x b 乘以 y 以此类推 奇数偶数 得到的如果是一位数那么前面补 9 ,比如 a=4 ,x=2 4*2=8 则变为 98 因为 9*9=81 不会出现十位数是 9 的情况 结果记为 aa bb cc dd ee ff gg hh ii jj 把这些结果拼接起来得到 aabbccddeeffgghhiijj... 会是结果的两倍长度 然后将 x 和 y 分别插进去一个固定位置 可以多次插入起到混淆作用,自己定个位置 这个定位要基于最前面的位数,也要基于最后面的位数,可以重复 比如结果这么排列 输出一个纯数字字符串 axabbccddeeffgghhiijjkyk 另外,可以定义一个 hash 表,将 0 1 2 3 4 5 6 7 8 9 分别替换成一个字母,因为字母[A-Za-z]比数字多,可以一个数字有随机的多种表示法 最后得到一串莫名其妙的字符串用来传递 decode 时,用同样的表将字符串替换回数字 然后对应位置抽出 x 和 y 然后每两位读取出来,十位数是 9 替换成 0 然后分别按顺序除以 x 和 y 如果不能整除报错 然后拼接起来得到 ID |
28
CEBBCAT 2022-07-03 15:06:45 +08:00 via iPhone
uuid 好像出了新版本,可以搜来看看。好像是考量了分布式和递增
|
29
erquiasz0825 OP @makelove 用 hashid ,需要一个 key ,这个 key 如果泄露了要更换,之前的 url 是不是就失效了,这很麻烦
|
30
4ark 2022-07-03 16:44:32 +08:00
前段时间看过一篇关于主键的文章,推荐一下:[《数据库主键一定要自增吗?有哪些场景不建议自增?
》]( http://itindex.net/detail/62310-%E6%95%B0%E6%8D%AE%E5%BA%93-%E4%B8%BB%E9%94%AE) |
32
thinkershare 2022-07-03 21:15:33 +08:00
@makelove 2 倍的 long, 16 字节, 打错了, mysql 用了 char32, 它应该是没提供原生的 uuid 支持
|
33
reneiw 2022-07-07 14:40:42 +08:00
@Jooooooooo 你说的不是雪花 id 吗?
|