在这种特定情况下,在 MySql 结构中使用 NULL 的优缺点是什么?

What are the pros and cons of Using NULL in MySql Structure in this specific case?

我有一个 table 结构,如下所示,包含角色结构 Table 我采用:

让它成为一个 "roles" table 包含一些与用户角色相关的记录。 现在,我在这里选择了一个专栏 "is_archived(int)",我用它来了解该角色仍然存在或已删除。

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

我的 table 最大记录将包含此列的 "NULL" 值,默认值也是 "NULL"。

现在我进退两难,因为我使用的是 "NULL" 而不是“0”,所以在这种情况下是否存在任何性能问题。

我需要知道这个案例的优缺点(比如"Search Performance"、"Storage"、"indexing"等)。

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

我的意见是 NULL 是为了 "out of band",而不是为了拼凑一个 in-band 值。如果有任何性能或space差异,那是微不足道的。

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

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

NULL 表示 "not yet known" 或您还不能说 "true" 或 "false" 的任何其他情况。 (因为你可能总是知道它是否是 'archived',NULL 在这里没有位置。

甚至可以使用ENUM('male', 'female', 'decline_to_state', 'transgender', 'gay', 'lesbian', 'identifies_as_male', 'North_Carolina_resident', 'other')。 (注意:这只是部分列表;最好为其设置 table 和 JOIN。)

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

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

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

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

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

那么索引只会是half-useful。 WHERE 子句无法搜索索引中的第二列。

但如果您使用实数值,则查询如下:

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

将使用索引中的两列。


关于 NULL 存储的评论:

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

但是,我建议您简化数据管理并在您想要 false 时使用 false。不要将 NULL 用作您的值之一。我想如果您以每行保存一个字节很重要的规模管理数据,那么会有一个例外。例如,如果您管理着数百亿行。

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

换句话说,InnoDB 页面只填满了每个数据页的 15/16。因此,InnoDB 页面格式的开销可能大于您从 micro-optimizing 布尔存储中获得的节省。