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
Geekerstar
V2EX  ›  MySQL

MySQL 数据库主键用了字符串的 UUID 怎么办?

  •  1
     
  •   Geekerstar · 2021-09-05 17:16:36 +08:00 · 9164 次点击
    这是一个创建于 1207 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近参与到一个老项目中:

    MySQL 数据库主键 id varchar 64,如 00cfad279bf14e60a9c39c91e7dd8770

    这种还有救么??目前系统线上运行着,不太可能停掉来修改,有没有什么好的优化办法呢?

    另外,这是个 Java 项目,数据库字段下划线,实体接收也用下划线,没有用驼峰,看着不习惯,用什么理由能劝说大家用驼峰呢。。。

    第 1 条附言  ·  2021-09-06 12:24:25 +08:00
    非常感谢大家的回复!!!

    首先数据量比较大,确实是出现了性能问题才考虑去优化一下。

    原因有些同学已经讲的非常清楚了。

    目前考虑还是先从慢 SQL 入手吧,主键就先不动了😆😆😆😆😆😆
    79 条回复    2021-09-07 10:03:34 +08:00
    chendy
        1
    chendy  
       2021-09-05 17:23:26 +08:00
    遇到因为字符串 id 导致的严重性能问题了么?没有的话无所谓,有的话……
    下划线就下划线,反正都有名称转换的配置去做这些事情
    xupefei
        2
    xupefei  
       2021-09-05 17:24:33 +08:00 via iPhone   ❤️ 4
    字符串有什么问题,为啥要改
    chinvo
        3
    chinvo  
       2021-09-05 17:25:40 +08:00
    数据库和 json 用蛇式不是很正常么...

    字符串 id 不是性能瓶颈就没必要动. 实在要动可以停机维护改成 binary(16) 类型.
    9yu
        4
    9yu  
       2021-09-05 17:29:14 +08:00 via iPhone
    凭什么要听你的改?
    mreasonyang
        5
    mreasonyang  
       2021-09-05 17:32:58 +08:00 via iPhone
    数这么设计虽然很多人会说索引性能有问题,但其实大部分场景都遇不到所以还好,真正问题比较大的是你们用的这个 uuid 生成方案是不是可靠。

    另外数据库字段一般都是推荐用下划线分割,主要是为了避免忽略大小写等暗坑,当然这个还是要看你们的编码规范是怎么定的。
    shiji
        6
    shiji  
       2021-09-05 17:36:19 +08:00 via iPhone
    1,这样的主键没毛病,我也觉得不会产生多少性能问题。

    2,尊重现有的命名方式吧,现在才想改太晚了,劳民伤财。
    xiangyuecn
        7
    xiangyuecn  
       2021-09-05 17:53:41 +08:00
    无聊的需求🐶 程序只要能跑,跟代码美观不美观 符不符合你的规范没有任何关系
    ericbize
        8
    ericbize  
       2021-09-05 19:01:56 +08:00
    1. 不要一厢情愿的去改,数据库卡就卡啊,管你开发什么事情呢

    2. 你要看这个 id 涉及到的面有多广,不然你改了,不行,你再改回来,数据不一致,或者有新插入数据,你人都傻。

    3. 给你个不成熟的思路, 新建一个表 用 bigint 做主键,然后把 你现在这个表弄过去(就等于加了一个 int 的主键,然后原有的字段保留,只是把 主键改到 int 去),最后再 rename 。(可能途中会涉及到 表停用,之类的问题,自己要在测试环境 和 dba 一起跑通测试,不要直接拿线上去搞,不然你跑路都不好跑!!! )
    cweijan
        9
    cweijan  
       2021-09-05 19:24:45 +08:00
    mysql 主键就是一种索引, 所以如果数据量不大, 根本无需担心性能问题.
    数据库字段用下划线没什么毛病, 实体类用下划线确实不太好, 看你能不能说服项目负责人.
    namelosw
        10
    namelosw  
       2021-09-05 20:28:40 +08:00
    UUID 不考虑性能其实还挺好用的,ID 是有状态的,UUID 是无状态的。

    比如你写一个麦当劳的取餐号,四五位的你就要考虑碰撞所以就要记录发出去那些,收回哪些,不小心就容易出 bug,UUID 的话就当他不碰撞就好了,所以什么也不用记。只是人看 UUID 眼晕,但是机器不会眼晕。

    而且一般应用其实都用不上这点极限优化,总有远比这个值得优化的地方。
    roundgis
        11
    roundgis  
       2021-09-05 20:39:48 +08:00 via Android
    uuid 有什麼問題?
    iyaozhen
        12
    iyaozhen  
       2021-09-05 20:44:30 +08:00
    uuid 没问题呀,单查询的话

    实体接收也用下划线,这个也还行吧,其实这样也好。编程规范核心是统一,如果涉及数据库、json 的都用下划线,其它 java 本身用驼峰,挺好的呀,只要不是混着来
    akira
        13
    akira  
       2021-09-05 20:53:27 +08:00
    线上好好跑着的东西,为啥要去动他呢。。就因为你看着不习惯么。。
    是性能出问题了 还是维护成本过大了? 总要有点理由的啊。。
    shintendo
        14
    shintendo  
       2021-09-05 21:40:02 +08:00
    还是工作不饱和
    anaf
        15
    anaf  
       2021-09-05 22:13:19 +08:00
    我现在做的项目一些表就是 UUID 目前没发现什么缺点 主要是用户表 商品表 店铺表等一些用户 其他一些 比如 分类 还是 int 自增
    james2013
        16
    james2013  
       2021-09-05 22:21:36 +08:00
    楼主还是太年轻,老项目能够正常运行就不要再大改了
    大改没什么收益,大改出现问题,谁负责呢
    自己负责的模块下,自己尽量写好就好了
    除非楼主是 CTO,部门经理,架构师等职务,可以决定项目重构和统一项目
    levon
        17
    levon  
       2021-09-05 22:52:52 +08:00
    我怎么觉得数据库用 uuid 做主键才是正道
    cubecube
        18
    cubecube  
       2021-09-05 23:42:52 +08:00
    @levon 最好的是自增主键,uuid 会导致数据存储局部性差,相对来说查询性能是有影响的,哪怕是有索引也会导致过多的读操作。
    uuid 也有好处,分布均匀,某些情况下写性能还行。
    levon
        19
    levon  
       2021-09-06 00:23:07 +08:00
    @cubecube 自增主键诸多烦恼,比如你有个订单 id=1234,那么你就可以猜测可能有个订单 id=1235,这时候如果不控制的话,就可能可以打开别人的订单信息。如果是 uuid 则没有这样的问题。
    另外有时会添加记录,先知道 id 也会带来很多方便,不用等写入数据库再返回 id 才能用。
    opengps
        20
    opengps  
       2021-09-06 01:06:41 +08:00
    既然是老项目,那么就继续照老的来吧,不建议修改
    xuanbg
        21
    xuanbg  
       2021-09-06 06:14:07 +08:00
    uuid 的性能问题主要体现在插入数据上面,查询基本没啥问题。数据量不大的情况下,uuid 简直完美。折腾他干啥呢
    imycc
        22
    imycc  
       2021-09-06 07:50:44 +08:00 via iPhone
    数据量大不大,不大的话对性能也没啥影响吧。
    拿 uuid 做主键也是有好处的,要不你再结合一下业务的场景看看,是不是故意这么设计的?
    如果对开发效率和系统效率有明显影响,不建议动,动了也没好处。。
    ccagml
        23
    ccagml  
       2021-09-06 07:55:33 +08:00 via Android
    ccagml
        24
    ccagml  
       2021-09-06 07:56:28 +08:00 via Android
    ccagml
        25
    ccagml  
       2021-09-06 08:01:03 +08:00 via Android
    @chendy 发错了
    zt5b79527
        26
    zt5b79527  
       2021-09-06 08:33:12 +08:00
    请教一下,uuid 不是有可能会重复么,怎么都没见大家提这个
    gouki
        27
    gouki  
       2021-09-06 08:35:21 +08:00
    @levon #19 正解 。而且。。。事务的时候。主键 ID 其实会丢,到时候更烦人。UUID 除了看数据的时候不直观,其他应该都是推荐。毕竟分库分表的时候,根本不用考虑重复(看生成规则
    aragakiyuii
        28
    aragakiyuii  
       2021-09-06 08:43:47 +08:00
    varchar(64) 是认真的?没救了,祈祷一下表不会太大
    mysql 里 uuid 作主键的问题看这些
    https://www.percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/
    https://dba.stackexchange.com/questions/115766/should-i-use-uuid-as-well-as-id

    除了数据库,java 生态里默认都是驼峰吧。。当然可以自己转成蛇形。感觉很难劝说,要改大家都得改,况且主键都能用 varchar64 。。估计还有其他一堆问题吧
    aragakiyuii
        29
    aragakiyuii  
       2021-09-06 08:44:56 +08:00
    @zt52875287 #25 正常使用 version4 能重复的话感觉可以去买彩票。。
    aragakiyuii
        30
    aragakiyuii  
       2021-09-06 08:50:52 +08:00
    @levon #19 递增主键这种场景下单号应该是独立的字段
    cpstar
        31
    cpstar  
       2021-09-06 08:51:23 +08:00
    正如 5#所说,只要 UUID (其实你这个不能算是 UUID )生成没有碰撞,那是没有问题的。唯一有问题的恰恰是你关于数字的强迫症。

    编码拼写标准,完全就是规范,你没有话语权,那就是那句话:改变不了社会,就接受社会。
    cedoo22
        32
    cedoo22  
       2021-09-06 09:08:34 +08:00
    uuid 才是大部分系统的 ID 吧,递增这种 ID 如果需要暴露给 api 的话,容易被人吐槽
    cheng6563
        33
    cheng6563  
       2021-09-06 09:15:32 +08:00
    UUID 确实不太好,用带时间戳前缀的 UUID 比较好。
    securityCoding
        34
    securityCoding  
       2021-09-06 09:19:29 +08:00 via Android
    说没事的同学是不是没有了解过索引数据结构
    penll
        35
    penll  
       2021-09-06 09:21:48 +08:00
    @levon 这种情况,一般订单号是独立一个字段,根据特俗规则生成的。
    许多情况下,id 都不是直接暴露给前端,比如你为了不让外部自增遍历你的信息,都是用另一个生成的标识来作为该信息的唯一标识,比如 uuid(guid);
    lucays
        36
    lucays  
       2021-09-06 09:24:19 +08:00
    数据量不大的话无所谓吧,这点性能损失没必要优化
    levon
        37
    levon  
       2021-09-06 09:32:52 +08:00
    @aragakiyuii 你的表再大,有 youtube 的表大吗,人家也是字符串类型做主键的
    @penll 不要这么死脑筋好不好,我只是举个订单作为例子而已。
    ”另一个生成的标识来作为该信息的唯一标识,比如 uuid(guid);“这只是自欺欺人罢了
    forbreak
        38
    forbreak  
       2021-09-06 09:33:37 +08:00
    @zt52875287 因为跟中彩票一样,你根本不可能中。uuid 也只是理论存在重复,实际基本遇不到。
    xLight
        39
    xLight  
       2021-09-06 09:34:34 +08:00
    除了你看着不舒服,你能说出哪些理由要搞?
    Asuka0947
        40
    Asuka0947  
       2021-09-06 09:35:04 +08:00
    改出问题了你就会发现有人会把以前未发现的遗留问题一并甩给你,这时候就难办了。
    cco
        41
    cco  
       2021-09-06 09:39:34 +08:00
    能跑就行,你再怎么规范,最终的结果也是在屎上上接着拉。
    zealinux
        42
    zealinux  
       2021-09-06 09:48:17 +08:00
    一直都是 INT ID 改成 UUID 的,
    从来没有见过 UUID 改回 INT ID 的。
    pkoukk
        43
    pkoukk  
       2021-09-06 09:50:58 +08:00
    @securityCoding 大家都说了数据量不大的情况啊。
    那请问你觉得的在数据量不大的情况下有啥影响?
    levon
        44
    levon  
       2021-09-06 09:52:29 +08:00
    @cubecube 至于性能问题,你的数据库能大过 youtube,amazon 吗,他们也是一样以字符串作为主键
    lasuar
        45
    lasuar  
       2021-09-06 09:54:33 +08:00
    能够在你任职期间稳定运行 就够了,不要自己找麻烦。
    myd
        46
    myd  
       2021-09-06 09:56:48 +08:00
    确实,这点性能损失无关紧要。

    在性能方面,uuid 的缺点:
    1. 比 INT 占用更多的存储空间;
    2. 如果插入的 uuid 不是单调递、递减的,数据页会留出一部分空隙,导致存储占用进一步加大;
    3. 各个页面(基本上)是非连续存储的,每个页面存储的记录数又变少,查找性能下降。
    4. 添加的二级索引也有上面的问题。

    总结:占用更多存储,性能略微下降。
    wolfie
        47
    wolfie  
       2021-09-06 10:01:06 +08:00
    @cedoo22 #32
    支付宝交电费 生成的 订单 ID 就是能看到规律的数字。

    @zealinux #42
    因为有强迫症的空降老领导。
    zealinux
        48
    zealinux  
       2021-09-06 10:04:09 +08:00
    @wolfie
    那个订单 ID 是业务 ID (对用户可见),
    肯定不是 DB 的数据记录 ID
    chengyiqun
        49
    chengyiqun  
       2021-09-06 10:09:22 +08:00
    @zealinux uuid 最大的问题就是, 当数据量大的时候, 写入会造成索引重排很浪费性能, 还有破坏了数据局部性, 也会导致损失点性能. int id 的性能是比 uuid 好的, 这个是共识吧. 所以才有类似雪花算法的出现
    aliveyang
        50
    aliveyang  
       2021-09-06 10:16:48 +08:00
    收益经得起付出么?不然改它干嘛,能跑就行
    lap510200
        51
    lap510200  
       2021-09-06 10:23:54 +08:00
    @zealinux 正常来说 int 足够了,遇到过一些老项目用 uuid 多,主要都是为分表分库准备的,以前的机器配置和 mysql 性能在单表上不够,常常需要分表分库,但是现在很多都用 rds,固态+mariadb 普及,索引优化好,单表上亿数据都不慢
    lizuoqiang
        52
    lizuoqiang  
       2021-09-06 10:25:28 +08:00
    @levon 逗比,一口一个 youtube,amazon,咋滴他们数据库你设计的?还是说你看到过他们表结构了??
    谁让你用自增 id 做订单号了??
    主键 id 只是用作关系关联,用来做业务字段你怕是个 2b
    wolfie
        53
    wolfie  
       2021-09-06 10:29:53 +08:00
    @zealinux #48
    真就嘴硬,snowflake 这类 id 生成规则可控懂吗?

    搜订单 id,看是 string 还是 int64 。
    https://open.oceanengine.com/doc/index.html?key=ad&type=api&id=1696710607541263
    RyanOne
        54
    RyanOne  
       2021-09-06 10:31:28 +08:00
    1.uuid 占用空间大,同样的空间能存放 int 或者 bigint 的值更多,索引能更多的加载到内存中,查询效率更高
    2.mysql 插入主键,强制会进行排列,从小到大排列,如果你插入的不是自增,那么 mysql 还需要额外做排列操作(比如节点分裂,树平衡操作等)
    3.自增查找效率更高,因为如果要查询范围的,那么如果是自增的,只需要找到最开始和结束即可,如果不是自增,那么你找到的最后一个根本不知道是不是最后,还需要扫描节点
    shenjinpeng
        55
    shenjinpeng  
       2021-09-06 10:37:31 +08:00
    uuid 对性能的影响微乎其微, 将来负载均衡 集群 分表, 读写分离, 也很容易做 .
    8.0 之前自增值可能会存在回溯问题 .
    liuzhihang
        56
    liuzhihang  
       2021-09-06 10:45:58 +08:00
    前段时间刚好遇到这个问题,这边不是 UUID,是使用了别的订单号作为唯一索引(老系统),随着数据量的增多,开始很卡。这时候考虑对流水归档。

    新表仅保留一个月数据,新增了 ID 列当自增主键,之前的流水号就还是唯一索引。

    判断唯一的时候就得多表判断了,业务控制。

    1. UUID 换成唯一索引,新增自增主键列。
    2.看 SQL 如何写的
    3. 数据量小就无所谓了
    4. 影响这个我了解不多,都是看的资料,聚簇索引,叶子节点是双向链表,UUID,会插入到中间,造成页分裂,自增主键是持续往后添加,再往深了讲那就需要专业人士回答了。
    keepeye
        57
    keepeye  
       2021-09-06 10:46:13 +08:00
    盲猜 大概字符串索引比较耗内存
    8355
        58
    8355  
       2021-09-06 10:57:58 +08:00
    我觉得你可能只是觉得不习惯吧.代码并没有跑不动... 收益大还是雷大
    hhjswf
        59
    hhjswf  
       2021-09-06 11:14:46 +08:00
    mysql b+树怎么建立 uuid 这种乱七八糟的索引。。。
    jswh
        60
    jswh  
       2021-09-06 11:15:06 +08:00
    除了强迫症,其实一般没事得。
    lzfnb
        61
    lzfnb  
       2021-09-06 11:18:22 +08:00
    做事要有边界,不要做这种费力不讨好的事
    qdzzyb
        62
    qdzzyb  
       2021-09-06 11:22:58 +08:00
    问题不大 我司存链上数据 主键都是随机的 hash 值 最大的表几亿条数据了
    tairan2006
        63
    tairan2006  
       2021-09-06 11:38:57 +08:00
    数据库字段本来就应该用下划线,因为很多数据库不区分大小写

    uuid 一般造成不了性能问题,除非规模非常大
    zealinux
        64
    zealinux  
       2021-09-06 11:41:14 +08:00
    @wolfie

    我们也用过 snowflake 只是用来生成业务 ID
    (当然会加上前缀,不同的业务不同前缀)。

    而数据库 ID,新的是用的 UUID,老系统用的 INT ID 。

    也就是说,MySQL 里订单一条记录中,即有 UUID,也要有业务 ID 。
    (其中 UUID 对用户不可见。)
    levon
        65
    levon  
       2021-09-06 11:48:18 +08:00
    @lizuoqiang 一口一个逗比,你还会不会说话。
    我还真就知道现在国内的某大公司,他们的项目就是 uuid 作为主键,而且很多表数据都超过 1 个亿的记录了,不也活的好好的。
    我自己做过的项目也很多是 uuid 主键,几百万记录,也没碰过什么明显的性能问题。
    chenqh
        66
    chenqh  
       2021-09-06 11:54:26 +08:00
    有个问题,一般不是再定义一个主键 id 比如 `oid` 这个吗? 原来的`id` 还是自增的吗?
    IvanLi127
        67
    IvanLi127  
       2021-09-06 12:15:45 +08:00 via Android
    mysql 用 单调递增的 uuid 做主键没啥问题,是不是字符串性能问题也不算大吧。
    我觉得,尽量想办法不参与比较实际,不然说服大家是一回事,谁负责重构之前代码又是一回事
    belin520
        68
    belin520  
       2021-09-06 12:19:28 +08:00
    拥有强迫症的空降技术小领导?
    那你说的算,改!
    lei2j
        69
    lei2j  
       2021-09-06 13:34:04 +08:00
    UUID 主键索引不好
    RichardYyf
        70
    RichardYyf  
       2021-09-06 14:07:45 +08:00
    可以看下这篇文章关于主键的部分:
    提炼下观点:
    - 自增主键只推荐用在非核心业务表,甚至应避免使用;
    - 核心业务表推荐使用 UUID 或业务自定义主键;
    自增主键的坑真的是到一定数据量之后你想要优化的时候才能感知到的。

    http://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/MySQL%E5%AE%9E%E6%88%98%E5%AE%9D%E5%85%B8/05%20%20%E8%A1%A8%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1%EF%BC%9A%E5%BF%98%E8%AE%B0%E8%8C%83%E5%BC%8F%E5%87%86%E5%88%99.md
    Nich0la5
        71
    Nich0la5  
       2021-09-06 14:09:09 +08:00
    https://www.cnblogs.com/goody9807/p/7608213.html 关于实际性能影响有多大我去查了一下翻到了这么一篇文章,性能上确实有差距但这点差距要不要优化还是看实际业务需求了。
    改主键挺蛋疼的 各种关联表都要动一遍
    huiyadanli
        72
    huiyadanli  
       2021-09-06 14:12:55 +08:00
    数据库多活的情况下。。uuid 反倒是更加好的方案
    kelvin_fly
        73
    kelvin_fly  
       2021-09-06 14:35:11 +08:00
    当遇到数据迁移等情况时,自增主键的坑就出来了
    2i2Re2PLMaDnghL
        74
    2i2Re2PLMaDnghL  
       2021-09-06 16:05:09 +08:00
    @levon 我怎么看都不觉得 youtube 是字符串主键
    你看到的 v= 参数很明显是 base64_url 出来的( URL 变种中用 -_ 替换 +/ )
    至于 amazon 的 dp* 编号,也是递增系,跟 uuid 的随机系完全不一样。

    这里我们要明确一个问题:有两个正交的区分:
    字符串 vs 数字
    递增 vs 随机
    实际上 uuid 的意义在于随机,实际上它完全可以存为 int-like 或者 char()

    字符串和数字作主键实际上没有很明显的差异,因为主键是直接查 B+ tree 的,O(log n) 几百到几亿也不过翻倍,查主键性能有差异已经不是正常数据库范畴了。
    而递增和随机有明显的差异:随机在插入时会导致页分裂,但因为是随机的关系,实际上越大的库越不容易发生页分裂。数据局部性的问题,也就是扫全表的时候,顺序读取 vs 随机读取,实际上 SSD 下影响不大。
    实际上真正碰到问题是自增 int 直接当字符串写,打个比方,写完了 1-9,然后你会发现你 10-19 全都在同一个位置插入,导致增加记录时有单一热点,越大的表越糟糕。

    当然,两个维度都不是非黑即白的,twitter 还不是搞出了雪花这种半递增半随机的 int64 但以字符串形式传递的,堪称最四不像的主键。

    不过,再说一遍,在座 80% 的人是遇不到因为具体范式选择导致的性能问题的,就好比不会因为用了 Python 导致一个请求花十秒,发生的情况都是因为错误的写法。
    zeff
        75
    zeff  
       2021-09-06 16:17:36 +08:00
    UUID 就是个垃圾,B+Tree 简历索引最好自增,这样效率会高,Twitter 的雪花算法自增数据量庞大的时候效率更高,建议说好的了解一下 B+Tree
    xupefei
        76
    xupefei  
       2021-09-06 18:25:55 +08:00 via iPhone
    没想到讨论了这么久。
    我对你讲,uuid 做主键只有一种情况会可能有性能问题:range query 。
    B+树在 uuid 上没有任何问题。
    levon
        77
    levon  
       2021-09-06 20:55:09 +08:00
    @2i2Re2PLMaDnghL 应该是,你分析的很专业,学习了。
    cedoo22
        78
    cedoo22  
       2021-09-07 09:22:18 +08:00
    好些人都是被互联网大厂技术给带偏了, 自己业务表 本来最多几万条数据,硬是要学别人几百万数据的做法,有必要吗?
    了解学习一下没问题,强行改得不偿失
    wangritian
        79
    wangritian  
       2021-09-07 10:03:34 +08:00
    uuid 全面代替 int 主键有 3,4 年了,当然要用时间戳开头的生成算法,好处太多
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6027 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 02:05 · PVG 10:05 · LAX 18:05 · JFK 21:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.