借口,我熟悉 NULL 值和空字符串之间的语义差异。
我有一个 MySQL 表,我在其中存储了许多主机名及其 IP 地址(作为字符串),并且想知道如果无法解析主机名,什么看起来更自然(或有效的存储方式)。
NULL 值或空字符串(在这种情况下,它可能应该是 VARCHAR 而不是 CHAR)
我倾向于使用 NULL 值,但我希望确认或取消确认。
借口,我熟悉 NULL 值和空字符串之间的语义差异。
我有一个 MySQL 表,我在其中存储了许多主机名及其 IP 地址(作为字符串),并且想知道如果无法解析主机名,什么看起来更自然(或有效的存储方式)。
NULL 值或空字符串(在这种情况下,它可能应该是 VARCHAR 而不是 CHAR)
我倾向于使用 NULL 值,但我希望确认或取消确认。
在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()
完全按照它的行为行事。
首先:仔细考虑NULL和Empty-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 ,因为它有一些微妙的缺点。
甲骨文解决了这个问题并解释两者相同。
Mysql 没有,我不是在评判它,但我个人不喜欢它,因此尽可能多地使用 NULL 来“标准化”我的代码。
另外,从关键字的意义来看,NULL 正是您想要的,因为它在数据库语义中意味着“未知”。(如我错了请纠正我)
我建议您使用NULL
,而 NULL 的类型与字符串不同。例如,更容易过滤掉具有此值的行或检测该字段中的值类型等。