【问题标题】:What are the pros and cons of Using NULL in MySql Structure in this specific case?在这种特定情况下,在 MySql 结构中使用 NULL 的优缺点是什么?
【发布时间】:2017-01-31 07:26:05
【问题描述】:

我有一个如下所示的表结构,其中包含我采用的角色结构表:

让它成为一个“角色”表,其中包含一些与用户角色相关的记录。 现在,我在这里使用了一列“is_archived(int)”来了解该角色仍然存在或已删除。

所以我正在考虑该列的两个值:

  • "NULL"=> 如果该角色仍然存在(如 TRUE),
  • "1" => 如果已删除/不活动(如 FALSE)

对于我的表,该列的最大记录将包含“NULL”值,默认值也是“NULL”。

现在我处于两难境地,在这种情况下是否存在任何性能问题,因为我使用的是“NULL”而不是“0”。

我需要知道这种情况的优缺点(例如“搜索性能”、“存储”、“索引”等)。

如果有缺点,最好的选择是什么?

【问题讨论】:

    标签: mysql indexing storage


    【解决方案1】:

    我的观点是NULL 用于“带外”,而不是用于组合带内值。如果有任何性能或空间差异,那是微不足道的。

    对于真/假,使用TINYINT NOT NULL。它只有 1 个字节。你可以使用ENUM('false', 'true');也是1个字节。

    INT,不管后面的数字是多少,占用4个字节。不要将INT 用于如此低的基数。

    留下NULL 表示“未知”或任何其他您还不能说“真”或“假”的情况。 (由于您可能总是知道它是否已“存档”,NULL 在这里没有位置。

    可以甚至使用ENUM('male', 'female', 'decline_to_state', 'transgender', 'gay', 'lesbian', 'identifies_as_male', 'North_Carolina_resident', 'other')。 (警告:这只是部分列表;最好设置一个表格并JOIN 。)

    【讨论】:

    • 非常感谢 Rick,我又读到一件事,如果“varchar: NULL”包含“NULL”,则根本不会占用存储空间。那么对于地址、secondary_email 等可选的列,我们可以将默认设置为“NULL”吗?这种做法有什么缺点吗?或者这样做有什么好处?
    • 对可选数据使用NULL是相当合理的。
    • 非常感谢瑞克 :)
    【解决方案2】:

    我同意@RickJames 关于 NULL 的看法。不要在你的意思是使用像true 这样的真实值的地方使用NULL。同样,不要使用像 0 或 '' 这样的实际值来表示没有值。

    至于性能影响,您应该知道要搜索 NULL 的存在/不存在,您将使用谓词 is_archive IS [NOT] NULL

    如果您在查询中使用 EXPLAIN,您会看到该谓词算作“范围”访问类型。而搜索单个特定值,例如is_archive = 1is_archive = 0 是“ref”访问类型。

    这将对某些查询产生性能影响。例如,如果您在 (is_archived, created_on) 上有一个索引,并且您尝试执行如下查询:

    SELECT ... FROM roles 
    WHERE is_archived IS NULL AND created_on = '2017-01-31'
    

    那么索引将只有一半的用处。 WHERE 子句无法搜索索引中的第二列。

    但如果你使用真实值,那么查询如下:

    SELECT ... FROM roles 
    WHERE is_archived = 0 AND created_on = '2017-01-31'
    

    将使用索引中的两列。


    关于 NULL 存储的评论:

    是的,在 InnoDB 存储引擎中,内部每行存储一个位域,每列 1 位,其中位指示每列是否为 NULL。这些位存储紧凑,即一个字节最多包含 8 个位。位域之后是一系列列值。为 NULL 的列不存储任何值。所以是的,从技术上讲,使用 NULL 确实可以减少存储空间。

    但是,当您的意思是 false 时,我敦促您简化数据管理并使用 false。不要将 NULL 用于您的值之一。如果您以每行保存一个字节很重要的规模管理数据,我想会有一个例外。例如,如果您要管理数百亿行。

    但在比这更小的规模上,潜在的空间节省不值得您为项目增加额外的复杂性。

    从角度来看,InnoDB 页面无论如何只会填充每个数据页面 15/16。因此,InnoDB 页面格式的开销可能大于您从微优化布尔存储中获得的节省。

    【讨论】:

    • 谢谢比尔,正如 Rick 所说 "对于真/假,使用 TINYINT NOT NULL。它只有 1 个字节。你可以使用 ENUM('false', 'true');它是也是 1 个字节。”.因此,我们可以使用 BIT 数据类型,而不是使用不必要的 4/1 字节的 INT/TINYINT 来告诉 True/False,而不使用太多空间吗?
    • BIT(M) 数据类型以 1 个字节为增量使用空间。抱歉,您不能将存储空间减少到每列 1 个字节以下。
    • 非常感谢你的账单,我又读到了一件事,如果包含“NULL”,则 "varchar: NULL" 根本不会占用存储空间。那么对于地址、secondary_email 等可选的列,我们可以将默认设置为“NULL”吗?这种做法有什么缺点吗?或者这样做有什么好处?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-07
    • 2018-05-21
    • 1970-01-01
    相关资源
    最近更新 更多