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

两个含有大量重复字段的表需要设计成一张表吗

  •  
  •   V2XEX · 2019-01-08 23:52:18 +08:00 · 3827 次点击
    这是一个创建于 2151 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一个简单的场景:
            业务需要两个对象:学生教师,两者均含姓名、性别、生日等大量重复属性,但是学生有个“学号”属性,教师有个“科目”属性,如果将这两者同时设计成一张 user 表,那么非这两个属性的拥有者的该字段将为 null 值,而且需要设立一个 role 字段以区分两者身份。
    但是如果如果分开设计,那么大多数属性都是重复的,这样似乎较为浪费空间,而且业务层多了 “判断用户角色” 的逻辑代码
    怎样设计表才是最佳实践呢?

    20 条回复    2019-01-09 09:53:58 +08:00
    katsusan
        1
    katsusan  
       2019-01-09 00:02:43 +08:00 via iPhone
    分开设计为什么会浪费空间呢,而且将来用户量大的时候用户类型也是水平拆分的手段之一吧,个人理解。
    Darren9276
        2
    Darren9276  
       2019-01-09 00:09:21 +08:00 via Android
    我的理解是如果老师的权限只是学生权限的超集,那么设计成一个表,添加角色以区分,如果两者的权限几乎不重叠那么设计成两个表也无所谓,不过还是推荐前者
    qiayue
        3
    qiayue  
       2019-01-09 00:09:24 +08:00
    现在都什么年代了,硬盘不值钱了,别想着省空间
    liunull
        4
    liunull  
       2019-01-09 00:09:57 +08:00 via Android
    你合在一起才浪费空间吧
    lhx2008
        5
    lhx2008  
       2019-01-09 00:10:01 +08:00 via Android
    拆一个公共表就行了
    公共表是含义是成员,有每个人的基础信息
    然后再是教师表和学生表,每个教师引用一个成员的 id,然后再添加老师专用字段
    lhx2008
        6
    lhx2008  
       2019-01-09 00:11:28 +08:00 via Android
    对应到编程语言就是父类和子类的概念
    lhx2008
        7
    lhx2008  
       2019-01-09 00:12:13 +08:00 via Android
    mysql 官方例子就是这么搞的
    zjp
        8
    zjp  
       2019-01-09 00:12:49 +08:00
    非要用将学生和教师视为一种特定 user 可以用数据库的表继承
    saulshao
        9
    saulshao  
       2019-01-09 00:20:30 +08:00
    应该把共有的字段拆出来,变成一个表,然后用关联到学生和老师 2 个表上。
    dumbunny
        10
    dumbunny  
       2019-01-09 00:23:20 +08:00 via Android
    直接两张表不就挺好的
    d3vil
        11
    d3vil  
       2019-01-09 00:24:28 +08:00   ❤️ 2
    分开表,并不会占用更多的空间,因为每个人就是占用一条记录;
    不分开表,也就是楼主所说的前者的实现方式,这是最 Low 的实现方式,弊病你自己也明白,不仅仅会造成空字段,并且会在写代码上造成不方便;
    #5 楼所说的父表与子表的方案,这个方案在逻辑上是最具有层级关系的,就是它在逻辑性、系统性这两个方面来说,是最好的,最规范的。(适合大型、复杂、非常需要考虑扩展性的业务),但是他的方案不管是在空间上、时间上(查询),都是最为难受的选择,想要整个系统的高要求,不管是空间上还是时间上,你都无法避免需要进行牺牲,所以,楼主的问题其实应该自己告诉自己,因为你最明白你这个业务的预算是多少,做一个工程,你自己得做评估、预算,有了这个,别人才能够根据你的实际情况来推荐具体的解决方案,否则,便是无源之水,无根之木。
    d3vil
        12
    d3vil  
       2019-01-09 00:29:28 +08:00
    所以初步的结果就是:
    如果楼主的业务如果是中型以下,可以选择设计两个表,也就是学生一张表,教室一张表。
    如果楼主的业务如果是中型以上,那么则应该规范设计,将公共字段独立为一张表,然后每一个 Role 去创建一个新表来存储 its own distinct filed。
    d3vil
        13
    d3vil  
       2019-01-09 00:35:46 +08:00
    #12 打错字了,教室改为“教师”。想在中型以下那一行多加一句:如果业务不大,其实设计两张表真的是最优选择,多一个 Table 真不会多占用多少空间= =好好想想吧,怎么会有“分开设计,那么大多数属性都是重复的,这样似乎较为浪费空间”这种说法?道理在哪里?赐教一下?这到底怎么浪费空间了?只是另外腾出一个动态空间来存放东西而已,只是多贴了一个标签而已,多少条记录就是多少条记录的空间啊,就是多了一个“标签”的空间而已啊,不过遥想我们当初学 SQL SERVER 2008 的时候,创建一个数据库好像要为两个文件(记得好像是 mdb 和 log 文件)给定一个固定的大小....MySQL 应该不存在这样的吧?空间都是动态增长、占用的吧?
    lhx2008
        14
    lhx2008  
       2019-01-09 00:45:02 +08:00 via Android
    @d3vil
    写的不错哈哈。
    一张表肯定不行的,无法应对业务的变化
    两张表原则来说问题也不大,但是主要也是考虑到业务的实际情况。比如到时候学生和老师都要登录,那是不是还要加一个 id 判断的逻辑?或者由用户自己选择自己是老师还是学生,这样都是不友好的。所以本质上还是抽出一个成员的概念应对业务变化。
    至于性能真的不是问题,就是一个简单的连表查询,主键索引速度很快的。还没到谈到什么预算的问题。不过具体到 ORM 可能配置起来还是有一点点麻烦。
    msg7086
        15
    msg7086  
       2019-01-09 00:47:46 +08:00
    一种做法,STI。
    另一种做法,公共表(例如 UserProfile 表同时被 Student 和 Teacher 引用)。
    d3vil
        16
    d3vil  
       2019-01-09 00:58:31 +08:00
    “ id 判断的逻辑”是什么?不同的角色登录,去操作不同的表就可以了,然后让前端后端在代码上配合做区分,我并不认同你所说的“不友好的”,因为我就举个例子吧,阿里云有免费邮箱和企业邮箱,他们都是邮箱吧?但是他们的登录地址却不同,一个是 mail.aliyun.com ,一个是 qiye.aliyun.com ,用户登录不同的邮箱竟然还要跨子域耶!这是不是也是不友好呢?我觉得不能有这样的强迫症= =。

    你要想在前端做好看一点,不要有类似上面的选择框,你就可以学阿里邮箱用不同子域管理不同的角色的业务(学生和老师的职能、业务的确是有很大的不同的),要么你就在前端做区分,对一个问题钻牛角尖,只会让自己手足无措的,而永远无法到达一个彼岸的,也没有一个实际的方案能给到你。
    简单的连表查询...一个再简单的操作,面对起以后业务的量级,都会有极明显的差异,比如一个表有三百万的数据,你要进行三百万条记录的 Join,这和单表查询的绝对耗时能比吗?肯定会有性能差异的。
    那没谈到预算的问题,那就什么方案都行呗,那不就是做外包一样的,怎样实现来得快来得简单,就怎样做,那随便怎么做都行的,实现的方法那么多种,随便选个呗,要是有预算,那就不一样了。要是你不考虑性能,那你就往规范的方向做呗,选择规范设计。
    lrxiao
        17
    lrxiao  
       2019-01-09 05:00:39 +08:00
    额 不能 IS-A 一样做 weak entity 吗
    reus
        18
    reus  
       2019-01-09 08:29:36 +08:00
    三个表,users, students, teachers,后面两个表里有个 user_id
    lhx2008
        19
    lhx2008  
       2019-01-09 09:02:46 +08:00 via Android
    @d3vil
    不跟你谈表的问题了。
    首先,哪有业务量级呀,一个学校能有多少 QPS,单机都随便跑了。就算有再多钱,也要分析下具体情况,事实上,大部分业务都做不到大公司的量级。就算没有钱,没啥访问量的话,一个 join 查询也不能用了吗?

    我也没有否认可以做到微信量级的可能。即使未来达到大公司量级,我们还有读写分离,集群,缓存这么多方法应对量级的增长,单单只是少用一个 join 我觉得有点削足适履了。

    join 的性能没有这么差,特别是这种一对一关系,先不说有没有 300 万条,就算有 300 万条,如果你了解数据库的 b+树,就知道你指定一个 id 查是很快的,join 不过是以很快的速度再用 id 查一遍。而且数据库大多都有缓存池优化,包括用 hash 表。

    设计规范只是为了将来好改动,如果是自己的项目,自己怎么爽怎么来。
    V2XEX
        20
    V2XEX  
    OP
       2019-01-09 09:53:58 +08:00
    @d3vil
    感谢您的回答,工程的问题涉及到方方面面,有时可能需要将视野放宽才能解决。
    至于我说的“浪费空间”的空间,也许我的表达不太准确……我并是不指浪费了物理意义上的空间,而是设计了两张包含大量的重复字段的表让我有种“ repeat your self ”的冗余之感,当然设计表不同于写代码,也许这么设计也没问题?


    此项目确实只是个小项目而已,但如果不加思考闭着眼睛那就是真的 it 民工了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5182 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 03:47 · PVG 11:47 · LAX 19:47 · JFK 22:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.