1800x
V2EX  ›  数据库

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

  •  
  •   1800x · Dec 29, 2022 · 5331 views
    This topic created in 1404 days ago, the information mentioned may be changed or developed.

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

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

    那么有两种解决方案:

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

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

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

    42 replies  •  2023-04-11 14:29:45 +08:00
    root000
    root000
    Dec 29, 2022
    1
    2
    Xhack
    Xhack
    Dec 29, 2022
    2
    is null And is not null 是不会走索引的
    isora
    isora
    Dec 29, 2022
    3
    iseki
    iseki
    Dec 29, 2022 via Android
    4
    依业务需求而定,数据库不能好好处理就说明该换数据库了
    Xhack
    Xhack
    Dec 29, 2022
    5
    @Xhack 我说错了
    imv2er
    imv2er
    Dec 29, 2022
    6
    业务逻辑设计上选 1
    有查询需求的 选 2
    securityCoding
    securityCoding
    Dec 29, 2022
    7
    2
    tf2
    tf2
    Dec 29, 2022
    8
    mysql 还是别用 null 了。
    CodeCodeStudy
    CodeCodeStudy
    Dec 29, 2022❤️8
    9
    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

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

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

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

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

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

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

    另外,mysql 早就支持 null 走索引了,知识要及时更新啊。
    iseki
    iseki
    Dec 29, 2022❤️1
    39
    不要用 0 来表达没有,更不要自己搞出个 -1 来,这是在挖大坑;
    数据库该用 NULL 就用 NULL ,数据库不好处理,就换数据库;
    keenkiller
    keenkiller
    Dec 30, 2022
    40
    如果大部分用户都有企业,那用啥都可以。
    如果大部分用户都没有企业,可以考虑搞个关联表,数据比较少。
    co2fe
    co2fe
    Dec 30, 2022❤️1
    41
    为什么企业 id 要放在用户表里面,为什么不用关系表存储?
    万一你业务以后允许一个用户待在多个企业,你怎么搞。
    而且使用中间表,我觉得可以解决你这个纠结 null 还是 0 的问题。
    wi666
    wi666
    Apr 11, 2023
    42
    选 1 ,并将企业名称字段加索引
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   5190 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 87ms · UTC 00:20 · PVG 08:20 · LAX 16:20 · JFK 19:20
    ♥ Do have faith in what you're doing.