8

借口,我熟悉 NULL 值和空字符串之间的语义差异。

我有一个 MySQL 表,我在其中存储了许多主机名及其 IP 地址(作为字符串),并且想知道如果无法解析主机名,什么看起来更自然(或有效的存储方式)。

NULL 值或空字符串(在这种情况下,它可能应该是 VARCHAR 而不是 CHAR)

我倾向于使用 NULL 值,但我希望确认或取消确认。

4

4 回答 4

5

MyISAM MYSQL 中,您每行保存一位而不使用 NULL。正如这里所说:

将列声明为 NULL 可以减少允许的最大列数。对于 MyISAM 表,NULL 列需要在行中有额外的空间来记录它们的值是否为 NULL。每个 NULL 列多占用一位,四舍五入到最接近的字节。

也看看这里

此外,虽然 NULL 本身不需要任何存储空间,但如果表定义包含任何定义为 NULL 的列,NDBCLUSTER 每行保留 4 个字节,最多 32 个 NULL 列。(如果 MySQL Cluster 表定义有超过 32 个 NULL 列,最多 64 个 NULL 列,则每行保留 8 个字节。)

此外,它还使数据库此处所述的工作更快(取自stackoverflow - @DavidWinterbottom 链接对我不起作用,我添加了一个不同的来源)

MySQL 更难优化引用可空列的查询,因为它们使索引、索引统计和值比较更加复杂。可为空的列使用更多的存储空间,并且需要在 MySQL 内部进行特殊处理。当一个可为空的列被索引时,每个条目需要一个额外的字节,甚至可以导致固定大小的索引(例如单个整数列上的索引)在 MyISAM 中转换为可变大小的索引。

在大多数情况下,非 NULL 值在与COUNT()其他聚合函数结合使用时表现得更可预测,但您也可以根据需要看到 NULL 的行为。

如此处所述并非所有组(聚合)函数都会忽略 NULL,例如,COUNT()会为您提供与COUNT(*)包含 NULL 值的列不同的结果。

另一方面,正如其他人指出的那样,NULL 更好地反映了条目的含义——它是一个未知值,如果你想计算所有主机,你可能会COUNT()完全按照它的行为行事。

于 2013-05-05T15:02:38.850 回答
2

首先:仔细考虑NULLEmpty-String的不同语义。

  • 第一个最好解释为:
    此字段有一个有效值,但该值未知
  • 第二个总是意味着:
    该字段的有效值是已知的,并且正是 ""

第二:认识到索引和过滤在Empty-String 上比在NULL上工作得更好、更有效,所以当你真正指的是前者时,不要使用后者。

第三:认识到所有使用NULL的表达式都容易受到三值逻辑的非直观性的影响,除非 NULL 首先被虔诚地合并为Empty-String(或其他一些上下文有效的值)。特别是,排中律不再适用,因此每当对A的求值需要对NULL项求值时,表达式A 或 ~A就不再是重言式的。忘记这一点可能会导致非常微妙且难以定位的错误。

不等于运算符定期公开这一点:

When A has the value NULL:
   The expression A = 0 returns false; 
   The expression A <> 0 returns false; and
   The expression A OR NOT A returns false!

更新
我想我的观点的本质是它们不是同一种生物,而是非常不同的野兽。每个都有它的位置。第二个地址字段应始终为非空(除非您打算允许输入部分或不完整的地址),并且它的默认值应始终是 Empty-String 的有效和已知值。NULL 应仅限于稍后将提供有效且已知值的情况,并且实际上表示某种必须解决的验证失败。

从下面的OP:

不会更新行。在插入时,要么有 IP 地址,要么没有(因为无法解析)。

回复:

然后我建议使用Empty-String作为默认值,并使该字段为 NON-NULL。仅在必须时使用NULL ,因为它有一些微妙的缺点。

于 2013-05-05T15:46:33.983 回答
1

甲骨文解决了这个问题并解释两者相同。

Mysql 没有,我不是在评判它,但我个人不喜欢它,因此尽可能多地使用 NULL 来“标准化”我的代码。

另外,从关键字的意义来看,NULL 正是您想要的,因为它在数据库语义中意味着“未知”。(如我错了请纠正我)

于 2013-05-05T14:59:39.667 回答
0

我建议您使用NULL,而 NULL 的类型与字符串不同。例如,更容易过滤掉具有此值的行或检测该字段中的值类型等。

于 2013-05-05T15:00:05.387 回答