如题,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 ![]() @erquiasz0825 因为按照分页查询时候, 数据会分散到不同的页, GUID 这种如果要作为主索引, 一定要支持自增, 否则插入 /查询都会有不小的性能损失. GUID 有自增的算法版本 |
5 Jooooooooo 2022-07-02 20:13:30 +08:00 设计一个毫秒时间戳+机器码+随机数的方案, 全本地操作, 也不复杂. |
6 cxxlxx 2022-07-02 20:19:26 +08:00 ![]() @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 ![]() @thinkershare 8 字节的 uuid ?给个链接让我开开眼? |
21 zhuweiyou 2022-07-03 07:40:00 +08:00 snowflake 或 uuid_short |
23 MarkLazy 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 PRO |
![]() | 27 realpg PRO 比如 我给你设计个算法 把数据库的 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 吗? |