› MySQL 5.5 Community Server
› MySQL 5.6 Community Server
› Percona Configuration Wizard
› XtraBackup 搭建主从复制
Great Sites on MySQL
› Percona
› MySQL Performance Blog
› Severalnines
推荐管理工具
› Sequel Pro
› phpMyAdmin
推荐书目
› MySQL Cookbook
MySQL 相关项目
› MariaDB
› Drizzle
参考文档
› http://mysql-python.sourceforge.net/MySQLdb.html
erquiasz0825
V2EX  ›  MySQL

MySQL 用 uuid 作为主键会导致“页分裂”,这种影响可以忽略吗?

  •  1
     
  •   erquiasz0825 · Jul 2, 2022 · 7801 views
    This topic created in 1587 days ago, the information mentioned may be changed or developed.

    如题,MySQL(5.7) 用 uuid 作为主键会导致“页分裂”,这种影响大吗,是否可以忽略?

    33 replies  •  2022-07-07 14:40:42 +08:00
    erquiasz0825
    erquiasz0825
    OP
    Jul 2, 2022
    1
    补充:uuid 非自增
    Rumble66
    Rumble66
    Jul 2, 2022
    2
    非常大, 最好用有序自增整形做主键.
    不仅是插入性能差, 查询性能也差.
    erquiasz0825
    erquiasz0825
    OP
    Jul 2, 2022
    3
    @Rumble66
    1. 如果 id 不想对外暴露怎么办?
    2. 为什么也会影响查询性能呢?
    thinkershare
    thinkershare
    Jul 2, 2022❤️1
    4
    @erquiasz0825 因为按照分页查询时候, 数据会分散到不同的页, GUID 这种如果要作为主索引, 一定要支持自增, 否则插入 /查询都会有不小的性能损失. GUID 有自增的算法版本
    Jooooooooo
    Jooooooooo
    Jul 2, 2022
    5
    设计一个毫秒时间戳+机器码+随机数的方案, 全本地操作, 也不复杂.
    cxxlxx
    cxxlxx
    Jul 2, 2022❤️1
    6
    @erquiasz0825 关于第二点,可以使用这个 进行转换 https://hashids.org/
    cheng6563
    cheng6563
    Jul 2, 2022
    7
    换 ksuid
    haoooooo
    haoooooo
    Jul 2, 2022
    8
    雪花
    potatowish
    potatowish
    Jul 2, 2022 via iPhone
    9
    用数据库自增保存原始 id ,对外用 hashid 包装
    makelove
    makelove
    Jul 2, 2022
    10
    id 不想暴露的方法多了,比如上面的 hashid ,哪怕另建一列 uuid 当公开 id 都比用 uuid 作主键好,因为所有索引项都会包含主键,用 uuid 浪费内存和硬盘
    ToBeHacker
    ToBeHacker
    Jul 2, 2022
    11
    看你是不是需要有序遍历或展示吧
    erquiasz0825
    erquiasz0825
    OP
    Jul 3, 2022
    12
    @makelove
    “另建一列 uuid 当公开 id 都比用 uuid 作主键好”

    那么根据 uuid 查找实体吗?还是根据 uuid 查到 id ,再根据 id 查找实体?
    lessMonologue
    lessMonologue
    Jul 3, 2022
    13
    @erquiasz0825 根据主键 id 查实体,然后把这个实体对应的 uuid 返回出去吧。OP 应该去看看 InnoDB 的主键索引建立过程。
    thinkershare
    thinkershare
    Jul 3, 2022
    14
    @makelove uuid 并不浪费内存, UUID 在很多数据库的实现中使用了 8 个字节, 也就是 2 倍 long 的长度, uuid 完全可以做到高效, 除非性能特别重要, 而且单个表数据极大, 否则选择 uuid 是一个很不错的选择, 性能是一个需要基准测试问题. 绝大部分系统的性能问题都不会因为你使用了 UUID 而导致. 反而我非常推荐使用 UUID 作为 id.
    cheng6563
    cheng6563
    Jul 3, 2022
    15
    @thinkershare MySQL 没有原生 UUID 类型,要存 UUID 要么用 binary 要么用 varchar ,前者难用后者废空间。而且 UUID v4 也确实不太适合用 B+树来索引。
    LostPrayers
    LostPrayers
    Jul 3, 2022
    16
    如果是 JAVA 用 MybatisPlus 库,主键可以选 IdType.ASSIGN_ID (雪花算法的 bigint), 或者用自增 IdType.Auto (数据库自增)
    Soar360
    Soar360
    Jul 3, 2022
    17
    我用多主键比较多
    ipwx
    ipwx
    Jul 3, 2022
    18
    我不是 MySQL 玩家。PostgreSQL 如果用 uuid 肯定是为了在可预见的将来,对象互相引用的 ID 不会发生改变。我觉得这是 UUID 最大的作用。
    elboble
    elboble
    Jul 3, 2022 via Android
    19
    Mongodb 的 id 好像是 uuid 但是还是有序递增的
    makelove
    makelove
    Jul 3, 2022❤️1
    20
    @thinkershare 8 字节的 uuid ?给个链接让我开开眼?
    zhuweiyou
    zhuweiyou
    Jul 3, 2022
    21
    snowflake 或 uuid_short
    ZhenShaw
    ZhenShaw
    Jul 3, 2022 via Android
    22
    @elboble 类似雪花算法,不是 uuid
    MarkLazy
    MarkLazy
    Jul 3, 2022
    23
    建议采用雪花号,补一个之前做的总结:
    UUID 为什么不推荐做索引?
    1. 长度太长,int 4 b ,bigint 8 b ,但是 uuid 是 32 位字符串即 32 b ,一个 uuid 索引占用空间是 int 的 8 倍,是 bigInt 的 4 倍,这会导致二分查找遍历的页增多,甚至可能导致 b+ 树的层高变高,并且,每个二级索引都会存储主键 id 用于回表,如果主键太长,整个表的其他索引也会被拖慢
    2. 没有顺序,会将顺序写变为随机写,产生多余的页分裂,多余的页缓存失效处理
    3. 比较性能不佳,字符串比大小要先查码表再比较,整形直接就比较了
    MarkLazy
    MarkLazy
    Jul 3, 2022
    24
    @elboble 我印象中 MongoDB 用的也是类似雪花算法
    adoal
    adoal
    Jul 3, 2022 via iPhone
    25
    UUID 没毛病,但是在 MySQL 上用嘛……连原生支持都没有,就像上面有 v 友说的,你打算当 binary 还是 text ?
    realpg
    realpg
    Jul 3, 2022
    26
    @erquiasz0825 #3
    id 本来也不是必须暴露
    在 URL 上,ID 通过一定算法转成 encode 成字符串
    查询进到程序 decode 成 ID
    自增步长不要设成 1 ,大一点,很难破解
    realpg
    realpg
    Jul 3, 2022
    27
    比如 我给你设计个算法
    把数据库的 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
    CEBBCAT
    CEBBCAT
    Jul 3, 2022 via iPhone
    28
    uuid 好像出了新版本,可以搜来看看。好像是考量了分布式和递增
    erquiasz0825
    erquiasz0825
    OP
    Jul 3, 2022
    29
    @makelove 用 hashid ,需要一个 key ,这个 key 如果泄露了要更换,之前的 url 是不是就失效了,这很麻烦
    4ark
    4ark
    Jul 3, 2022
    30
    前段时间看过一篇关于主键的文章,推荐一下:[《数据库主键一定要自增吗?有哪些场景不建议自增?
    》]( http://itindex.net/detail/62310-%E6%95%B0%E6%8D%AE%E5%BA%93-%E4%B8%BB%E9%94%AE)
    4ark
    4ark
    Jul 3, 2022
    31
    @4ark markdown 没生效...
    thinkershare
    thinkershare
    Jul 3, 2022
    32
    @makelove 2 倍的 long, 16 字节, 打错了, mysql 用了 char32, 它应该是没提供原生的 uuid 支持
    reneiw
    reneiw
    Jul 7, 2022
    33
    @Jooooooooo 你说的不是雪花 id 吗?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2679 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 61ms · UTC 13:47 · PVG 21:47 · LAX 05:47 · JFK 08:47
    ♥ Do have faith in what you're doing.