大家在正式的环境里面会使用外键么 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
yeyuexia
V2EX    程序员

大家在正式的环境里面会使用外键么

  •  
  •   yeyuexia 2015-11-19 14:11:23 +08:00 13761 次点击
    这是一个创建于 3615 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近和几个同事聊及对 mysql 的使用的时候,纷纷对我们项目并不使用外键而在逻辑上维护 table 之间的关系这种事情感到不可思议,说“怎么能这么做呢,为什么不用外键?” 这件事情简直对我产生了巨大的冲击,难道还有人会在生产环境上使用外键么? 如果是的话,能否告诉我为什么要这么做,好处有哪些? 谢谢
    第 1 条附言    2015-11-19 15:05:32 +08:00
    其实我主要是想知道什么时候需要使用外键。为什么。
    在我经验来看只有银行,金融这种对数据非常敏感的地方可能需要外键。 实际情况下还有那些方面呢?

    参考:
    http://stackoverflow.com/questions/83147/whats-wrong-with-foreign-keys
    57 条回复    2019-01-24 18:50:09 +08:00
    wshcdr
        1
    wshcdr  
       2015-11-19 14:35:27 +08:00
    我不用,我是用代码来维护外键关系
    mikan
        2
    mikan  
       2015-11-19 14:38:08 +08:00
    表结构由 hibernate 维护,自带外键
    clinkzlol
        3
    clinkzlol  
       2015-11-19 15:26:08 +08:00
    如果使用 ORM 框架来处理数据层,基本上就没外键什么事了
    dong3580
        4
    dong3580  
       2015-11-19 15:27:18 +08:00
    以前经常用,现在不用了。校验在程序里。
    kafka0102
        5
    kafka0102  
       2015-11-19 15:33:42 +08:00
    不要用框架的实现来规避问题。外键是对数据一致性的约束,使用代码逻辑约束是通常的做法,个人也赞成这种做法。数据库能做很多事情,外键、触发器、存储过程等等,如果你愿意,可以把逻辑都写到数据库端,但这对数据库的维护会带来很多麻烦。如果你是使用 mongodb 等,那你也只能写到代码里。但另一方面,代码逻辑写得再好,也可能造成数据不一致的。所以,如果数据一致性很重要,那么数据库做约束可能是更好的选择。
    yeyuexia
        6
    yeyuexia  
    OP
       2015-11-19 15:39:45 +08:00
    @clinkzlol
    @mikan
    使用框架和使用外键是两回事吧?
    pythoner
        7
    pythoner  
       2015-11-19 15:47:57 +08:00
    我的经验是,在项目初期,为了快速完成功能开发,还是会按照规范添加外键。
    随着业务的发展,很多时候,我们需要按照业务功能来做垂直拆分,这个时候就必须得去掉一些外键,以及相关的 join 查询
    asj
        8
    asj  
       2015-11-19 16:10:01 +08:00   2
    我做过几年的银行业软件,就我见到的系统确实很多生产环境中是不用外键的。原因和正式代码中是否使用断言类似。理论上来说,这些约束有助于维护系统的一致性。但是问题在于,不一致了,又怎么样呢?

    在理想世界里,不论数据,代码还是输入输出都是有条有理的。而现实中却常常要面对历史遗留代码和数据,低质量的输入,以及变化无常的输出等等不那么有条理的情况。那么,比如一个系统运行到某个点时,发现某项检查与预期不一致的时候。停止整个系统真的是最好的选择么?又或者输入数据的时候某个字段不一致,因而拒绝整条数据真的是最合理的么?

    另一个问题是不方便,当需要批量表数据,调整表结构或者更改程序逻辑的时候,这些约束经常会对开发人员造成困扰。虽然一般来说各种数据库都有暂时关闭约束的机制,但是确实把问题复杂化了。
    而且,不同于 UI 上对随机的普通用户操作的校验,或者系统对恶意攻击者的安全性检查,数据库外键这类约束阻止掉的操作,来自于系统的开发和维护人员。一般来说他们最了解系统的内部结构,很清楚自己在做什么,对系统的一切有着最高的权限。这时候他们更容易觉得这种约束烦人而不是可靠。
    felixzhu
        9
    felixzhu  
       2015-11-19 16:12:51 +08:00
    外键相对来说还是可以用的,这种强一致性的约束通过代码是有可能出问题的
    主要问题感觉是后面分库分表的时候比较麻烦吧
    SmiteChow
        10
    SmiteChow  
       2015-11-19 17:11:27 +08:00
    如果没有强理由,外健是物理和逻辑上最好的选择,上面说到的数据历史问题,说明技术选型不是很对,参看 Django Migration 。
    zyAndroid
        11
    zyAndroid  
       2015-11-19 17:52:09 +08:00   1
    没有外键的话代码得写成什么样子,无法想象。
    jhaohai
        12
    jhaohai  
       2015-11-19 18:18:40 +08:00 via iPhone
    数据库里少用这些东西,太耗性能
    jsjscool
        13
    jsjscool  
       2015-11-19 20:03:53 +08:00
    WEB 开发的瓶颈多半在 IO ,需要权衡。没有哪个一定好或者一定不好。
    g67261831
        14
    g67261831  
       2015-11-19 20:24:07 +08:00
    @asj 赞同。
    JamesRuan
        15
    JamesRuan  
       2015-11-19 20:35:52 +08:00
    用外键不需要理由,不用外键才需要找理由。
    slayerdoomsday
        16
    slayerdoomsday  
       2015-11-19 20:38:06 +08:00
    我们 CTO 说,一不要用外键,二不要用 join ,把需要的数据都查出来再用程序处理
    JamesRuan
        17
    JamesRuan  
       2015-11-19 20:42:32 +08:00
    @slayerdoomsday 那还要用数据库干嘛,直接自己写入文件好了。
    xuwenhao
        18
    xuwenhao  
       2015-11-19 20:44:57 +08:00 via iPhone
    @JamesRuan 如果你要让数据库可以水平拆库扩展只能选择这么做
    Infernalzero
        19
    Infernalzero  
       2015-11-19 20:50:16 +08:00
    @JamesRuan
    上面已经有人说了, web 主要瓶颈在数据库,互联网模式一般都是只让数据库做最简单的储存,不做复杂查询,复杂的事交给 web 服务器做, web 服务器的数量是可以不断加的,而 master db 对于某个用户来说是唯一的,不可分割的,而且现在服务器的性能一般的计算根本不算什么
    bravecarrot
        20
    bravecarrot  
       2015-11-19 20:51:22 +08:00 via iPad
    涨姿势了。一直以为都用外键的!
    JamesRuan
        21
    JamesRuan  
       2015-11-19 20:57:19 +08:00
    @xuwenhao 既然要 sharding 不能重建吗?

    我一直认为 sharding 是 poor man's temporary resort ,通过增加复杂性,换取局部的优势通常都不是最佳选择。
    JamesRuan
        22
    JamesRuan  
       2015-11-19 20:59:29 +08:00
    @Infernalzero 我知道很多都这样做。就是牺牲潜在的一致性风险,换取速度和灵活性。

    那为什么不多弄弄分布式储存?无非还是成本问题咯。
    JamesRuan
        23
    JamesRuan  
       2015-11-19 21:02:12 +08:00
    @Infernalzero 只做简单储存的,是不是用持久化的 Redis 之类才是最佳选择?或者上 NoSQL 。

    用 RMDBS 不用外键都是需要找理由的。
    Lpl
        24
    Lpl  
       2015-11-19 21:09:00 +08:00 via Android
    从来没用过显式外建,关系在代码维护。为了好移植,因为没有专业 dba ,存储过程还有触发器都没有用
    rail4you
        25
    rail4you  
       2015-11-19 21:34:46 +08:00
    楼主的项目没那么复杂,不用外键可以理解。
    楼主用的技术是 sql 中的反模式,剑走偏锋,在个别环境下有效而已
    但反过来,楼主居然说用外键不可思议,这只能说明楼主不习惯用关系数据库,或者没见过复杂的关系数据库。

    对于很多大型关系数据库项目,用外键是常态,因为外键是关联表的标准技术,合理的使用外键,能减少数据冗余,避免数据表结构的逻辑错误。比如企业的 erp 项目,表和表的关联极多,不用外键维持表关联(比如删除更新关联数据),会增加极多客户端的工作量。
    HentaiMew
        26
    HentaiMew  
       2015-11-19 21:41:34 +08:00
    有外键“关系”不是绝对需要外键“约束”,可以存在有主外键关系的多张表字段但不存在约束的情况。
    Ouyangan
        27
    Ouyangan  
       2015-11-19 21:43:51 +08:00
    长姿势了,还有不用外键的啊 ,我要好好深究一下
    Infernalzero
        28
    Infernalzero  
       2015-11-19 21:45:35 +08:00
    @JamesRuan 看业务了,核心业务一般不会上 nosql 的,普通的技术团队很难保证其稳定性,redis 也多数只是用于 session 和缓存
    dawncold
        29
    dawncold  
       2015-11-19 21:49:34 +08:00
    数据库表结构也一定程度上反映业务,所以能加的外键全都会加,另外也见识过完全不用外键的某系统,国内该行业前三的公司,可能是因为性能考虑,但我感觉除非是写的不好,否则一般不会遇到性能问题,就算遇到了也不应该从这些地方入手改进
    teek
        30
    teek  
       2015-11-19 21:53:53 +08:00
    新浪现在貌似也不用外键,据说损失过数据。
    JamesRuan
        31
    JamesRuan  
       2015-11-19 22:01:58 +08:00
    @teek 这样说就有些偏颇了,就像说:“乔布斯貌似也不看西医,据说西医没有治好过肿瘤”。

    外键不会保证数据不损失,但是外键可以保证数据不会因为人为的“缺陷”而损失。这种“缺陷”,往往在逻辑稍微复杂一点的环境下非常容易发生。
    initialdp
        32
    initialdp  
       2015-11-19 22:05:00 +08:00
    从来不使用外键,原因:
    ( 1 )穷,没有专业的 DBA ;
    ( 2 )约束关系在存储过程或者代码逻辑里实现;
    ( 3 )迁移、检查、数据输入等操作都比较方便。
    teek
        33
    teek  
       2015-11-19 22:31:50 +08:00
    @JamesRuan 嗯嗯,我描述上有点问题,是造成了损失,对象不是数据。具体就不能细说吧。
    xuyinan503
        34
    xuyinan503  
       2015-11-19 22:32:39 +08:00
    添加外键,如果要改表结构,相应要改的东西太多。

    而且从业务上来讲,一般数据都不会做级联的物理删除。

    比如说,删除一个客户,不会删掉这个客户的订单。连这个客户都不会删掉,而只是变一下标志位。

    否则回头查不到自己有什么业务,跟谁发生了什么业务。
    msg7086
        35
    msg7086  
       2015-11-19 22:35:19 +08:00
    @JamesRuan 很多时候用 RDBMS 纯粹是因为运维好招罢了。
    另外很多时候生产环境的持久存储端并不是固定的一个数据库。比如可能会从 MySQL 转向 Postgres 或者 Oracle ,这种时候平台无关的好处就体现出来了。像触发器,外键这种东西,都可以在框架里用事务来实现,不再需要依赖 DBMS 本身的特性了。甚至如你所说的改用 Redis 或者 MongoDB 都是有可能的。(当然 Redis 是不太可能了)
    run2
        36
    run2  
       2015-11-19 23:15:42 +08:00
    看业务逻辑,比如你把用户删除了,他的帖子怎么办?如果是软删除的话 外键的 on delete 肯定不好用。。
    xuwenhao
        37
    xuwenhao  
       2015-11-19 23:50:42 +08:00
    @JamesRuan 如果 Model 层直接用好 ActiveRecord 的 OR Mapping 模型,本来就不存在 join ,不存在新增复杂性的问题
    xuwenhao
        38
    xuwenhao  
       2015-11-19 23:52:24 +08:00
    实际大部分互联网应用实践中,都是通过应用来维护关联,而不是数据库外键,这个有很多原因
    1. 性能损耗
    2. 迁移数据时候的一致性维护

    大部分互联网应用对于一致性要求都很低,包括大部分企业应用也是这样
    loveyu
        39
    loveyu  
       2015-11-20 00:09:04 +08:00
    为啥没人提到开发环境上外键,测试环境直接移除外键呢
    yuriko
        40
    yuriko  
       2015-11-20 08:35:30 +08:00
    即使 mysql 我怎么记得外键是只有少数引擎才支持的东西啊……
    abscon
        41
    abscon  
       2015-11-20 09:27:46 +08:00
    @clinkzlol ORM 的实现也会用外键
    exit0
        42
    exit0  
       2015-11-20 09:52:04 +08:00
    这类系统 etl 操作多,表约束成了障碍。
    lilydjwg
        43
    lilydjwg  
       2015-11-27 18:28:38 +08:00
    我一直很疑惑的是,为什么很多人不用外键不用约束,却要手工连上数据库操作?把数据改坏了怎么办?我在学校时就见过一个坏得完全没法用的数据库。

    当然 MySQL 的实现若是有问题那当我没说。
    yeyuexia
        44
    yeyuexia  
    OP
       2015-12-02 11:28:43 +08:00
    @lilydjwg
    @SmiteChow
    @rail4you
    统一回复下吧 个人觉得使用外键开保证数据一致的话,不可避免的会造成扩展性的损失。因为你依赖了大量的外部的工具来保证了你程序的逻辑完备,一旦需要数据迁移到其他数据库上时,会造成很大的麻烦。而且使用外键,实际上是将一些逻辑服务器的压力转嫁到了 mysql 上,如果你的系统只是服务于小量级的用户的话,那用用也没什么,一旦用户量变大,后果不堪设想。还有就是手动改数据库而不是用接口去改这个事情,个人表示佩服。
    rail4you
        45
    rail4you  
       2015-12-02 12:32:42 +08:00
    @yeyuexia mysql 的功能和性能也很强,不是 toy 级别的数据库。楼主总是说 mysql 只能服务小数量级用户(什么算小?),用户量变大不可想象,这些都是主观臆断。现实中 mysql 使用外键的例子太多 ,这些 mysql 应用的用户量都不小,数据库端的逻辑也没那么简单。

    数据库的迁移一直很麻烦,不单单是 mysql ,数据验证还有用户逻辑也有很多选择,有丰富经验 dba 的情况下,在数据库端做这些也无妨。

    数据库环境很复杂的,每种数据库都有自己擅长的领域。楼主的数据库经验只限于一定领域,建议把话题限制下,说明下数据库应用范围(比如 xxx 类的互联网应用),这样能减少很多争议。
    SmiteChow
        46
    SmiteChow  
       2015-12-02 15:47:29 +08:00
    数据库表的定义必然在程序里啊,现在都是 ORM ,如果楼主认为 mysql 的外健性能还不如你程序自己写的话可能楼主是撸 C 的大牛。
    zonghua
        47
    zonghua  
       2016-08-11 01:00:49 +08:00
    外键不利于集群
    ezreal
        48
    ezreal  
       2016-10-11 14:30:21 +08:00
    公司线上数据库全面禁止外键!
    ezreal
        49
    ezreal  
       2016-10-11 14:32:12 +08:00
    外键高并发下会有性能问题,以及容易造成死锁?
    rosalindest
        50
    rosalindest  
       2016-12-07 15:43:32 +08:00
    大半年前你说你在 thoughtworks ,小女子现在有一事相求!!!!!!!!
    虽然你很久不上 V2 ,看到可否回复!!!!!!!!!!!!!!!
    yeyuexia
        51
    yeyuexia  
    OP
       2016-12-08 14:04:52 +08:00
    @rosalindest 啥事?
    rosalindest
        52
    rosalindest  
       2016-12-19 14:07:49 +08:00
    啊啊啊啊居然被看到了!!抱歉现在才回复!!!我想问你还在 TW 么??
    yeyuexia
        53
    yeyuexia  
    OP
       2016-12-21 14:49:52 +08:00
    @rosalindest 在 有事私聊吧 [email protected] 我邮箱
    Pegasus
        54
    Pegasus  
       2017-02-16 00:22:13 +08:00
    最近阿里放出来的《 java 开发规范》里明确说了不用外键。
    liuxin5959
        55
    liuxin5959  
       2017-02-17 18:05:53 +08:00
    @Pegasus 看来可以终结这个问题了,马云爸爸都说不要用了。
    Mark24
        56
    Mark24  
       2017-03-01 14:35:39 +08:00
    @Infernalzero 感谢

    长知识了

    一直以为一定要外键。
    kanezeng
        57
    kanezeng  
       2019-01-24 18:50:09 +08:00
    其实对大多数量小的项目来说,我觉得用不用外键看自己吧。对于量很大的项目,很可能实施了一大堆微服务,严格来说每个微服务应该有自己背后的的数据库,这时候比如用户表和帖子表可能都在不同的数据库服务器里的,也就没有人考虑外键的问题了。不过大多这种情况下,直接 nosql 更好一点。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1075 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 102ms UTC 23:19 PVG 07:19 LAX 16:19 JFK 19:19
    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