V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
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 · 45 天前 · 4293 次点击
    这是一个创建于 45 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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