给数据库字段添加唯一性的字段约束有什么弊端吗 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
rqxiao
V2EX    程序员

给数据库字段添加唯一性的字段约束有什么弊端吗

  •  1
     
  • &nbp; rqxiao 2019-11-15 15:40:46 +08:00 6395 次点击
    这是一个创建于 2159 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如说普通的插入数据 员工表里有主键 员工编号

    员工编号就是唯一的

    这一步唯一性的校验 放在代码里判断 和 数据库里做约束 都有什么利弊吗

    24 条回复    2019-11-16 22:36:05 +08:00
    looplj
        1
    looplj  
       2019-11-15 15:46:36 +08:00
    这个不要考虑,肯定是数据库加唯一索引的。
    代码做也是要加锁的。
    reself
        2
    reself  
       2019-11-15 15:49:08 +08:00   1
    原子性
    saulshao
        3
    saulshao  
       2019-11-15 15:50:49 +08:00
    在关系数据库出现之前,我估计世界上所有的数据都是用固定格式的文本 /二进制文件存储的。
    那时都是在代码里判断唯一性。直到关系数据库出现......
    taogen
        4
    taogen  
       2019-11-15 15:56:32 +08:00
    放在代码里判断的情况

    1. 并发。要自己实现,要控制并发和加锁。
    2. 索引。唯一性的校验取出的数据没有索引,没有数据库效率高。
    3. 性能。每次插入更新之前都要查一次数据库,好像也没有减少数据库的性能消耗。还不如让数据库系统自己校验。
    mcfog
        5
    mcfog  
       2019-11-15 15:56:54 +08:00   6
    数据库做唯一的一个风险是跟不上业务,想改回代码里处理的时候有点儿蛋疼

    就比如说你举的例子就很经典,员工工号似乎是唯一的,甚至能当主键,但比如明天的业务需求就可能变成:离职员工回归后新开账号(原有数据不继承)但工号仍使用原来的工号

    如果你仍然坚持用数据库的唯一来处理工号,就得改全部有关联数据的地方增加重新入职的清理逻辑,可是很多数据甚至是不能清理的,一地鸡毛。如果是代码里的逻辑,直接再插一条数据完事儿,原来的唯一检查改成入职状态下工号唯一就行了
    FaceBug
        6
    FaceBug  
       2019-11-15 15:58:56 +08:00
    插入遇到重复时会造成自增不连续
    levon
        7
    levon  
       2019-11-15 16:01:23 +08:00 via iPhone
    @taogen 让数据库自己校验,代码不用校验了吗
    stramkismet
        8
    stramkismet  
       2019-11-15 16:04:34 +08:00
    数据库里加唯一索引比代码中加校验要更安全和简单一点。不需要考虑并发的问题。
    在代码里校验的话千万别用“where 员工编号=员工编号” 来校验, 数据多了之后特别慢
    tubimasky
        9
    tubimasky  
       2019-11-15 16:14:40 +08:00   1
    @mcfog #5 这种加个 禁用标识位 使用联合约束呢
    mcfog
        10
    mcfog  
       2019-11-15 16:41:43 +08:00 via Android
    @tubimasky 离职 2 次呢,至少 MySQL 肯定没有 partial unique index 这么高级的
    superrichman
        11
    superrichman  
       2019-11-15 18:29:35 +08:00 via iPhone
    @mcfog 同一公司离职两次还招进来了,是这个员工厉害还是公司牛 p ?
    chendy
        12
    chendy  
       2019-11-15 18:42:14 +08:00
    代码判断要做,有问题直接报错返回
    数据库约束也要加,遇到并发 /业务漏洞可以兜底
    员工编号不建议作主键,做个唯一约束就行
    RedBeanIce
        13
    RedBeanIce  
       2019-11-15 20:17:31 +08:00
    @superrichman 万一,现实就是这么残酷呢。。。。
    optional
        14
    optional  
       2019-11-15 20:20:54 +08:00 via iPhone
    @mcfog 离职两次当然是改成 integer 的标志位
    optional
        15
    optional  
       2019-11-15 20:22:07 +08:00 via iPhone
    @mcfog 忘记了
    Tneciv
        16
    Tneciv  
       2019-11-15 20:34:02 +08:00
    @superrichman 实际上发生的概率很小 但是测试肯定会这么测
    srx1982
        17
    srx1982  
       2019-11-15 22:43:58 +08:00
    如果 mysql 想分区,你那个唯一键的字段就要当主键
    crclz
        18
    crclz  
       2019-11-16 07:58:10 +08:00
    代码判断(×),代码判断+唯一索引(×),唯一索引(√)

    我来解释一下。代码判断无法完全避免键冲突的并发。而不管有没有代码判断,数据库内部都会再做一次唯一性的判断。所以如果使用两者的话,会多一层性能损失。
    可以使用捕获异常,或者更规范一点,postgres 的 insert ... on conflict(条件) do nothing returning id,再判断 id 是否为 null。mysql 的不知道怎么做。


    @mcfog 做数据库模型变更,一地鸡毛,只能说明开发水平不够高。避免一地鸡毛的方法就是在领域层和基础设施层之间加一层转换层。或者传统的项目在 orm 里面改代码,让数据库迁移不过多“污染”业务代码。这层转换层一方面能保持原来的业务代码不需要更改,一方面在保存数据时如果发现是旧的数据模型,则附带做数据迁移。
    mcfog
        19
    mcfog  
       2019-11-16 08:23:41 +08:00 via Android
    @crclz 如果你觉得写代码无法做到完全避免并发冲突,那数据库代码是怎么写出来的?

    不同项目的需求又不一样,我不认为这个问题有唯一正确答案,我按照楼主的标题提出了一个弊端而已

    问题确实都有解决的方法,你说的数据转换层也许可以解决某些问题,但为此增加的成本和风险仍然是“弊端”,仍然需要考量如果只为了这么个事情引入一层架构是否合算。而且如果问题在于整个系统的假设(比如工号唯一)蔓延到多个模块以后被打破,可不是什么抽一层数据访问就能解决的
    leeg810312
        20
    leeg810312  
       2019-11-16 10:22:07 +08:00 via Android
    @mcfog 数据库系统的唯一性检查是在数据库系统里做的,你再怎么做并发检查,只要不在数据库系统里做,理论上还是有重复,你写的代码就是不可能避免并发冲突
    mtrec
        21
    mtrec  
       2019-11-16 10:25:02 +08:00 via Android
    mysql 里唯一约束的写入性能会差 因为要保证唯一性 不在内存的数据涉及随机 io 无法使用 change buffer
    arnoldFu
        22
    arnoldFu  
       2019-11-16 10:56:16 +08:00
    还是要在代码里做的吧,最经典的例子就是 name 不允许重复,但是允许用户做删除(系统逻辑删),这个时候数据库里 deleted 和 name 字段相同的数据就会有很多,这个时候 name 或者 name+deleted 作为唯一索引都不行,
    这种情况大家在开发中都是怎么解决的?
    wysnylc
        23
    wysnylc  
       2019-11-16 11:43:21 +08:00
    数据库唯一约束,分表无法使用
    要做严格唯一约束就弄个 redis 之类的内存校验或者从业务上允许重复
    单机环境爱咋搞咋搞,就那样
    Inside
        24
    Inside  
       2019-11-16 22:36:05 +08:00
    前面说利用数据库唯一索引的各位,应该考虑一下唯一索引为什么存在?我认为诸如唯一索引、外键等等约束,是因为在关系数据库诞生早期,是人工用 SQL 直接去操作数据库的,为了防止人为失误,所以建立了严格的约束。
    现在操作数据库的大都是自动化代码,这些事情代码都能干,而且表达能力更强。

    至于“再怎么做并发检查,只要不在数据库系统里做,理论上还是有重复”这样的观点,我只想说,难道关系数据库不是人写出来的?哪怕是不用数据库,只用各大语言的标准库去实现,也能轻松做到唯一索引这样的玩意,做不到还是别自称会写代码了。

    如果现代的程序员们做不到前辈们能做到的事情,那前辈们会对我们非常失望以及感到悲哀吧。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2727 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 15:14 PVG 23:14 LAX 08:14 JFK 11:14
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86