V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
1800x
V2EX  ›  数据库

sql 表设计问题:需索引的可选字段应该允许 null 吗?

  •  
  •   1800x · 2022-12-29 10:16:35 +08:00 · 3997 次点击
    这是一个创建于 698 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如一个用户表,中间一个字段,表示用户所属的企业。

    用户可能不属于任何企业。

    那么有两种解决方案:

    1. 企业字段允许为 null 。用户不属于企业时,企业字段为 null 。
    2. 企业字段不允许为 null ,默认 0 。用户不属于企业时,企业字段为 0 。

    再叠加一个需求,用户表的企业字段需要加索引。

    那么,应该选择哪个方案?或者有没有更好的方案?

    42 条回复    2023-04-11 14:29:45 +08:00
    root000
        1
    root000  
       2022-12-29 10:20:40 +08:00
    2
    Xhack
        2
    Xhack  
       2022-12-29 10:22:37 +08:00
    is null And is not null 是不会走索引的
    isora
        3
    isora  
       2022-12-29 10:24:20 +08:00
    iseki
        4
    iseki  
       2022-12-29 10:25:54 +08:00 via Android
    依业务需求而定,数据库不能好好处理就说明该换数据库了
    Xhack
        5
    Xhack  
       2022-12-29 10:26:56 +08:00
    @Xhack 我说错了
    imv2er
        6
    imv2er  
       2022-12-29 10:33:19 +08:00
    业务逻辑设计上选 1
    有查询需求的 选 2
    securityCoding
        7
    securityCoding  
       2022-12-29 10:34:16 +08:00
    2
    lambdaq
        8
    lambdaq  
       2022-12-29 10:50:27 +08:00
    mysql 还是别用 null 了。
    CodeCodeStudy
        9
    CodeCodeStudy  
       2022-12-29 10:59:06 +08:00   ❤️ 8
    mysql 字段不使用 null 的理由

    1 、比如文章点击量加 1 ,column_name = column_name + 1 ,如果把字段设成 null ,并且插入数据时没指明 column_name = 0 ,那么+1 操作不起作用;
    2 、count(column_name)时,null 的列不包含在内,count(*)则包含 null 的列在里面
    3 、计算多列时,如 SELECT id, click1+click2 as click FROM `foo` 如果两个点击量有一个为 null ,那么相加结果就是 null
    4 、如果有比较条件,比如 where < 10 ,如果为 null 的话则不包含在内
    5 、min(column_name), max(column_name)如果字段有值,则用值比较,如果字段没有值,都是 null 的时候,则为 null

    总结:不能运算,不能比较,慢
    jarvanluo
        10
    jarvanluo  
       2022-12-29 11:06:10 +08:00
    mysql 我一般都是有默认值,不允许 null 的。text 除外。
    bthulu
        11
    bthulu  
       2022-12-29 11:11:24 +08:00
    我反正是这么来的, 所有表字段都必须设置不允许为 null.
    这样在 java 里会减少很多 NPE.
    aichunya
        12
    aichunya  
       2022-12-29 11:29:31 +08:00
    现在项目里面,除了类似'收货时间'这种具有业务意义的 date 类型的字段允许为 null 以外,其它类型字段都会设置默认值
    makelove
        13
    makelove  
       2022-12-29 11:41:47 +08:00   ❤️ 2
    别听楼上的瞎 bb ,这种情况明显用 null
    oneisall8955
        14
    oneisall8955  
       2022-12-29 11:43:32 +08:00
    某些 datetime 含业务含义和 text 类型的允许 null ,其余都 not null 了
    clockwork1122
        15
    clockwork1122  
       2022-12-29 12:18:21 +08:00
    @oneisall8955 datetime 是真让我最讨厌的玩意,一般查询的场景都只需要 date 就行,数据库用 datetime 给自己增加查询难度。
    cpstar
        16
    cpstar  
       2022-12-29 12:37:34 +08:00
    @CodeCodeStudy 9# 你这些数值比较的字段,不应该把字段设置为数值类型的同时默认值是 0 ?

    oracle 的 varchar2 类型,空值即为 null 。
    meshell
        17
    meshell  
       2022-12-29 13:09:21 +08:00
    我说个其它的,在使用 ORM 的 one many 的时候 null 和 0 区别对待的。0 是找不到企业报错,null 没有企业
    yfwl
        18
    yfwl  
       2022-12-29 13:16:08 +08:00
    如果你要给这个列创建索引,那就不能 null ,因为 null 不走索引的,正常的列是允许 null 的
    seth19960929
        19
    seth19960929  
       2022-12-29 13:23:28 +08:00   ❤️ 4
    楼上的是不是都要更新知识了? MySQL null 列可以走索引.
    我的建议还是你用 null, 毕竟 null 和 0 还是不一样的.
    至于加不加索引和 null 不 null 无关, 取决于你的用户是否大多数有企业.
    比如你一百万用户就一百个有企业, 别加了. 如果大多数都有, 那就加
    seth19960929
        20
    seth19960929  
       2022-12-29 13:24:55 +08:00
    再补充一个, 取决于你的业务需求, 如果你业务代码都是.
    1. 先去查找用户 -> 然后在通过用户的企业主键去查找企业 = 不用加索引
    2. 找用户 -> join 企业 = 加索引
    3. 找这个企业下的用户 = 加索引
    Konys
        21
    Konys  
       2022-12-29 13:26:04 +08:00
    null 是可以走索引的
    cokar
        22
    cokar  
       2022-12-29 13:28:53 +08:00
    使用空字符串不是更好吗?
    zhangtest
        23
    zhangtest  
       2022-12-29 14:26:04 +08:00
    @Xhack 大哥们,你们了解下 mysql 不同版本的区别吧,别总把古董版本的特性带到目前常用的版本。
    BQsummer
        24
    BQsummer  
       2022-12-29 15:48:10 +08:00
    有些业务场景 0 和 null 就是有区别的, 咋办
    CodeCodeStudy
        25
    CodeCodeStudy  
       2022-12-29 16:28:13 +08:00
    @cpstar #16 是啊,应该设为设置型,默认值为 0 ,用 0 来表示特殊的含义,而不是 null
    Soler
        26
    Soler  
       2022-12-29 16:47:12 +08:00   ❤️ 1
    null 是 null, 0 是 0 ,概念首先不要乱用!!!

    假设设置成 0 , 0 多了不一样走不了索引吗。
    IvanLi127
        27
    IvanLi127  
       2022-12-29 17:24:00 +08:00   ❤️ 1
    @CodeCodeStudy 其实这个不好,我觉得更好的方案是:

    创建一个缺省公司,用来给那些不属于任何企业的用户挂名的;
    然后直接不允许这个字段为 NULL 就好了。

    这个方案就是前几年讨论 NULL 有没有必要时,一种比较优雅的方案。

    不过要是我的话,如果业务不要求对这类用户做什么操作,我肯定直接设 NULL 了 哈哈
    CodeCodeStudy
        28
    CodeCodeStudy  
       2022-12-29 17:33:08 +08:00
    @IvanLi127 #27 不用创建缺省公司来挂名,这样反而会搞复杂,企业字段直接用 0 来表示就好了
    IvanLi127
        29
    IvanLi127  
       2022-12-29 17:42:10 +08:00
    @CodeCodeStudy 其实有个问题。。。你们用 0 的前提是不用外键约束吗?如果用的话应该势必创建一个缺省公司
    JKeita
        30
    JKeita  
       2022-12-29 17:43:51 +08:00
    基本都不允许 null ,能不 null 就不 null
    CodeCodeStudy
        31
    CodeCodeStudy  
       2022-12-29 17:43:59 +08:00   ❤️ 1
    用 0 或者-1 来表示该值不存在更好的理由是保持一致的数据类型,避免 null 造成 NPE ,比如 Java 和 JavaScript 的字符串的 indexOf 的返回值是 int ,用-1 来表示找不到,而不是返回 null
    CodeCodeStudy
        32
    CodeCodeStudy  
       2022-12-29 17:44:31 +08:00
    @IvanLi127 #29 不需要外键
    CodeCodeStudy
        33
    CodeCodeStudy  
       2022-12-29 17:52:26 +08:00
    @CodeCodeStudy #9 补充一下第 4 点,如果某列允许为 null 的话,那么语句 where column_name > 10 ,where column_name < 10 ,where column_name = 10 均不能把实际值为 null 的行过滤掉,因为要用 where column_name is null ,这样就会带来不必要的麻烦
    xuanbg
        34
    xuanbg  
       2022-12-29 18:06:16 +08:00
    @seth19960929 也许他们的版本还停留在 5.5 或更早吧。。。反正我知道的 5.6 版本就已经支持 is null 走索引了。
    wtfedc
        35
    wtfedc  
       2022-12-29 18:39:45 +08:00   ❤️ 2
    按逻辑来说,null 是 null ,0 是 0 ,最好是按语意来使用。
    至于 select ... where x<y ,本来就不该带上 null 的数据。
    NoKey
        36
    NoKey  
       2022-12-29 19:00:43 +08:00
    如果公司都是用数字的话,就给一个默认公司的数字例如 0 ;如果是文字的话,就创建一个默认公司名,如:NoCompany 之类的,这样也不用纠结你这个问题了,查询起来也简单
    wiix
        37
    wiix  
       2022-12-29 19:08:59 +08:00
    null 是 null ,0 是 0 ,两者的语义完全不同,该是什么就是什么。
    把 null 用 0 表示一是使数据缺少一种表达能力,二是实际并没有减少做判断的心智负担。
    很多人讨厌 null 是因为 null pointer exception ,但有错却不能 fail fast ,带病运行更可怕。
    Outshine
        38
    Outshine  
       2022-12-29 21:30:06 +08:00   ❤️ 1
    @CodeCodeStudy #9 你这些理由对于遵循数据库设计范式的来说,完全不是问题。
    比如你说的文章点击量、需要比较大小或者参与计算的列,我找不到为 null 的场景。

    另外,mysql 早就支持 null 走索引了,知识要及时更新啊。
    iseki
        39
    iseki  
       2022-12-29 22:45:57 +08:00   ❤️ 1
    不要用 0 来表达没有,更不要自己搞出个 -1 来,这是在挖大坑;
    数据库该用 NULL 就用 NULL ,数据库不好处理,就换数据库;
    tairan2006
        40
    tairan2006  
       2022-12-30 08:54:15 +08:00
    如果大部分用户都有企业,那用啥都可以。
    如果大部分用户都没有企业,可以考虑搞个关联表,数据比较少。
    co2fe
        41
    co2fe  
       2022-12-30 09:04:59 +08:00   ❤️ 1
    为什么企业 id 要放在用户表里面,为什么不用关系表存储?
    万一你业务以后允许一个用户待在多个企业,你怎么搞。
    而且使用中间表,我觉得可以解决你这个纠结 null 还是 0 的问题。
    wi666
        42
    wi666  
       2023-04-11 14:29:45 +08:00
    选 1 ,并将企业名称字段加索引
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1294 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:15 · PVG 02:15 · LAX 10:15 · JFK 13:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.