V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gkiwi
V2EX  ›  程序员

大家用 mysql 做项目的时候,是否用外键呢?

  •  
  •   gkiwi · 2014-08-20 18:38:32 +08:00 · 8071 次点击
    这是一个创建于 3508 天前的主题,其中的信息可能已经有所发展或是发生改变。
    目前公司倾向于用外键.个人倾向于不用外键,而将约束控制变更到代码逻辑里面进行控制(其实即使用了外键,该判断的大多还是会有的):

    个人关于不用外键的理解:
    1.方便模型的变更.(由模型导成sql,然后进行重建表很方便,而加上外键单独重建表只能挨个字段改了CRUD更方便)
    2.性能会更好些

    这里有篇文章介绍的文章http://www.cnblogs.com/tearer/archive/2010/07/25/1784896.html
    ===
    求各抒己见.
    第 1 条附言  ·  2014-08-21 11:51:29 +08:00
    外键毫无疑问会提高数据完整性.这点大家应该没啥疑问.
    在性能问题上,我没有过测试,也是听别人说的;

    参照:
    http://www.xiaoxiaozi.com/2009/07/12/1158/
    33 条回复    2019-05-18 12:50:44 +08:00
    maga
        1
    maga  
       2014-08-20 19:41:35 +08:00
    智商一直够不到使用外键-.- 外健一起好难理解
    wingoo
        2
    wingoo  
       2014-08-20 19:48:34 +08:00
    不用,控制如你所说在代码里
    loading
        3
    loading  
       2014-08-20 20:00:04 +08:00 via Android
    个人不用


    但有人喜欢用教科书的什么范式考我~

    有一次数据库结构不是我定,虽然应用不需要考虑性能(访问和数据量少),没有索引,实质数据列精简到极限,无一个相同,很多时候 on都涉及到超级长的 a.uuid=b.uuid
    maemual
        4
    maemual  
       2014-08-20 20:33:01 +08:00 via Android
    公司明确规定不让用外键
    Mac
        5
    Mac  
       2014-08-20 21:12:44 +08:00
    公司平台第一版的时候用过外键,但随着表结构的不断复杂,就开始改用JOIN了,另一个重要原因是备份比较简单。
    mahone3297
        6
    mahone3297  
       2014-08-20 21:59:37 +08:00
    用了symfony,entity之间的关联,doctrine直接使用外键。。。
    之前我也不太推荐用外键。。。现在有点倾向外键。。。
    ps:ror应该也是用外键的吧?
    wengang285
        7
    wengang285  
       2014-08-20 22:10:47 +08:00
    之前在学校读书的时候,做项目,按照教科书上的东西,表设计的时候都用到外键;后来发现外键其实没必要,在逻辑层控制就好了,表耦合性太大也不好
    mengzhuo
        8
    mengzhuo  
       2014-08-20 22:10:51 +08:00
    根本就没有理由不用外键
    所有说辞只有一个原因---懒
    嫌麻烦的,请用ORM和Model迁移程序

    就不说性能上的提升,建索引的效率提升
    工程上
    外键解决了程序员意外删column的可能
    瞬间能理清关系,方便后来的人导出ER图,不存在盲区
    gkiwi
        9
    gkiwi  
    OP
       2014-08-20 22:35:05 +08:00
    @mengzhuo

    "懒"这个字用的好.

    划去各种性能限制不说,毫无疑问,外键稍多一些,来回删除修改数据会非常的浪费时间.而我现在项目刚起步,常常要变更表结构,改动时候,单个表的sql根本无法拿出来执行(因为必须修改/删除一些主键),而无主键的时候,直接删表重建就好了.

    楼上#5 提到备份之类的问题,数据导入时候先后顺序都需要一定顺序.

    这些都得浪费不少时间,而且常常是重复性的机械劳动,这个都是时间啊(人月)!!
    ===
    另外像你说的,几点就是涉及到: 表,er图,model三部分的生成问题.是先哪部分,再哪部分的.从直观性来讲,最简单的就是先做ER图,毕竟图形的好设计,而不是直接写sql再导出成er图.

    我不反对在er图上设立外键,但是从er图到table时候,更倾向于忽略外键,直接出表.
    lyragosa
        10
    lyragosa  
       2014-08-20 22:39:52 +08:00
    不用

    所有的跨表约束全部在程序上解决。
    XadillaX
        11
    XadillaX  
       2014-08-21 00:52:20 +08:00 via Android
    我也不喜欢,都喜欢在程序解决
    konakona
        12
    konakona  
       2014-08-21 04:25:51 +08:00 via Android
    不用。
    lightening
        13
    lightening  
       2014-08-21 05:47:41 +08:00
    ActiveRecord 会自动用的……
    tonghuashuai
        14
    tonghuashuai  
       2014-08-21 08:57:56 +08:00
    个人不用,hold 不住
    cxh116
        15
    cxh116  
       2014-08-21 08:59:59 +08:00
    @mahone3297
    @lightening

    ROR也没有用到外键约束,就一普通的int字段而已
    删除数据时方便,需要级联删除自己在程序里配置好逻辑

    不过像用户名这种字段的唯一约束推荐加上,碰到几次手机端连续点击,并发导致数据出现重复
    RangerWolf
        16
    RangerWolf  
       2014-08-21 09:34:27 +08:00   ❤️ 1
    个人项目我也不用~ 同楼主说的各种变动太多了~
    后来我直接用mongo了 代码逻辑层想干嘛就干嘛 哈哈!
    odirus
        17
    odirus  
       2014-08-21 09:34:58 +08:00
    表设计的字段一致,在开发过程中使用外键,生产环境中取消外键,自己跑测试用例的时候能够发现是否写糊涂了。
    wintersun
        18
    wintersun  
       2014-08-21 09:46:36 +08:00   ❤️ 1
    一分为二的看:
    1、企业应用强调数据强一致性,性能因为规模的关系,不是主要考虑因素,建议用外键;
    2、互联网应用则通常相反,强调性能而相对不着重数据强一致性(只是相对),不用外键对数据操作有性能提升助力,搜索问题则通常采用第三方搜索引擎系统效率更高。

    场景不同,着重点不同,采取的策略不同!
    6711411
        19
    6711411  
       2014-08-21 09:55:59 +08:00
    @lightening ActiveRecord 没有用外键.
    csensix
        20
    csensix  
       2014-08-21 09:57:12 +08:00
    没用过
    est
        21
    est  
       2014-08-21 09:57:24 +08:00
    项目变得快就不用。

    需要级联删除的就用。
    lyazure
        22
    lyazure  
       2014-08-21 11:10:36 +08:00
    @mengzhuo

    不喜欢用外键的人,应该比较经常在数据库里手工操作数据和表结构吧,不能直接删不爽……不用外键删虽然能删了,删完后数据库里一堆断肢残臂真的好么……

    用外键跟程序里能不能处理好逻辑关系不大,外键就是反映实体间引用包含关系,定义正确的外键跟定义正确的主键一样,反映了整个设计的逻辑合理性,是设计和实现人员的沟通工具

    另外也可以把外键当做“施工保护”,避免有人对设计理解错误或者不小心弄出bug……

    楼主说的两个理由:
    1.模型变更,删除建立/启用禁用外键可以弄一组sql语句,对这种影响完整性的操作,可以先禁用或者删除,改完后再恢复,不过设计好模型之后,出现影响完整性的变更应该是比较少的
    2.外键影响性能…………楼主真的遇到过这个情况吗?
    gkiwi
        23
    gkiwi  
    OP
       2014-08-21 11:50:05 +08:00
    @lyazure

    现在刚开项目,模型变更比较大,所以改来改去很烦躁;
    性能问题是道听途说的(也一直如此认为).刚刚搜了下(参照:http://www.xiaoxiaozi.com/2009/07/12/1158/),部分情况确实有性能问题,但在部分情况下却也会优化性能.在完整性上面有益处.

    其实在线上运行时候,我并不反对有外键(性能问题我们还早着呢).但是在开发时候,外键会影响开发效率倒是真的.
    knightluffy
        24
    knightluffy  
       2014-08-21 12:03:22 +08:00
    ER图搞外键是可以的,但是开发的时候搞外键,感觉有点多余,有时候字段还没定下来删起来都麻烦,虽然不知道跟性能是否有挂钩。。
    lijingyu68
        25
    lijingyu68  
       2014-08-21 12:29:38 +08:00
    设计的时候需要外键来表明表之间的关系,实际开发的时候就不用了。
    lightening
        26
    lightening  
       2014-08-21 16:51:28 +08:00
    @cxh116 哦,我知道了。这里说的是用 MySQL 的外键约束关系。我刚才想那个 int 字段不就叫做 foreign key 么。
    cxh116
        27
    cxh116  
       2014-08-21 17:13:53 +08:00   ❤️ 1
    @lightening
    比如 user_id 这个字段,没有加外键约束的时候,你可以把它设置为0,或设置为不存在的user的id

    但如果加了外键约束,user_id的只能为user表里面有的数据的ID

    Rails的关系字段在业务意义上来说是外键,但对数据库来说,就是一普通的int字段
    Biwood
        28
    Biwood  
       2014-08-21 21:16:49 +08:00
    我对后台不是很熟,以前学.NET时听说过外键,还有三大范式、关系表什么的,我以为凡是设计数据库必须用到这些呢
    lygmqkl
        29
    lygmqkl  
       2014-08-21 22:32:49 +08:00
    用代码来模拟FK 我直能说,你对数据还不够敏感,你写的代码再好能赶上数据库层的数据操作?

    醒醒吧不要给自己找借口了,越是大的程序对数据完整性要求越高。

    要是有300张表的项目,你算过你所谓的控制代码需要额外写多少吗?
    就算是100张你算过数量级吗?
    还有因此给团队管理带来的麻烦吗?
    huobazi
        30
    huobazi  
       2014-08-23 00:42:03 +08:00 via iPhone
    @lygmqkl 表再多再多些,分布在不同数据库你就不这么认为了
    looly
        31
    looly  
       2014-08-23 14:05:31 +08:00
    看需求。如果你做一个业务比较复杂,表之间关系也很复杂的项目,建议你用外键。用代码来保持数据的完整性会让你崩溃。例如你有一张学生表、学院表、学校表、城市表,依次关联,中间删一条数据你的下面的数据就全断了,数据就完全乱了。

    但是,如果你做的项目就几张表,且关联很小(或者是弱关联),性能要求还很高,就不要用外键了。其实你看现在的nosql没有外键的概念,就是为了摆脱外键舒服,提高性能。
    lygmqkl
        32
    lygmqkl  
       2014-08-25 15:02:42 +08:00
    @huobazi “吃人不吐骨头” 已经达到重构需求级别的项目?或许这种项目我没遇到过吧,但是我不觉得应该把这种放在一般项目开发或者常规项目开发的范畴内,你是不是有一点以偏概全了?
    hunterhug
        33
    hunterhug  
       2019-05-18 12:50:44 +08:00
    外键在某些情况必须用,否则你必须防止幻读,需要使用最强事务隔离,序列化隔离来做级联。

    比如有两张表:爸爸表和儿子表,儿子的表带上了爸爸的 ID,是外键,但是你没用这个关键字。

    你开启了事务 1:

    删除老爸
    删除儿子们

    提交事务 1

    你在另外一个窗口开启了事务 2:

    查询老爸(因为事务 2 是事务 1 提交前进入的,就算事务 1 在之后 comit 了,但老爸在 MVCC 模式下可重复读)
    插入儿子

    提交事务 2

    你会发现,老爸不见了,但是莫名其妙多了一个儿子出来。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   978 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 21:56 · PVG 05:56 · LAX 14:56 · JFK 17:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.