NULLS应该在代码中还是在数据库中处理?的优点和缺点?

时间:2009-11-24 20:18:02

标签: c# sql-server tsql database-design

我有几个关于何处理空值的问题。让我建立一个场景。想象一下,当提供使用空值或空字符串的原因时,我有一个包含5个varchar(50)列的表作为示例。

  1. 在代码或数据库中处理NULLS会更好吗?我的意思是,如果一个空字符串不包含任何值,或者将它更好地分配给varchar(50)并在代码中处理null,最好将它分配给varchar(50)吗?

  2. 为列分配空字符串是否会影响性能开销?

  3. 使用null与空字符串如何影响索引?

  4. 我的印象是,如果您不允许数据库包含空值,则不必在代码中处理它。这句话是真的吗?

  5. 除了v​​archars之外的其他数据类型在使用默认值时是否会产生相同的问题,或者对于字符串数据类型是否更有问题?

  6. 如果表包含空值,使用ISNULL函数的开销是多少?

  7. 其他优点/缺点是什么?

9 个答案:

答案 0 :(得分:7)

我的一般建议是将数据库中的字段声明为NOT NULL,除非您特别需要允许null值,因为对于刚接触数据库的人来说,它们往往很难处理。

请注意,空字符串和空字符串字段不一致意味着相同的事情(除非您将它们定义为)。通常null表示“未知”或“未提供”,而空字符串就是提供的已知空字符串。

允许或禁止null字段完全取决于您的需求。

答案 1 :(得分:2)

主要的优点是你可以在.NET和SQL代码中分别处理null和空字符串 - 毕竟它们可能意味着不同的东西。

缺点是你需要小心;在.NET中,你必须不在null上调用obj.SomeMethod(),而在SQL中你需要注意空值在组合时往往会传播(例如,与C#字符串连接不同)。

null和empty之间没有明显的大小差异。在.NET代码中,我希望希望它使用interned空字符串,但这并不重要。

答案 2 :(得分:2)

NULL存储得更有效(空位映射)然后是空字符串(varchar长度为2个字节,char为“n”)

Storage engine blog: Why is the NULL bitmap in a record an optimization?

我看过一些说不同的文章,但是对于char / varchar,我发现NULL很有用,并且倾向于将空字符串视为NULL。我还发现NULL在查询中比空字符串更快。 YMMV当然,我将根据它自身的优点评估每个案例。

答案 3 :(得分:2)

您正在将实现问题与逻辑数据架构问题混杂在一起。

您应该决定是否允许字段中的空值纯粹基于它是否准确地模拟您希望存储在数据库中的数据。正如其他一些人所指出的那样,混淆的部分原因是空字符串和空字符串不仅仅是存储相同信息的两种方式。

Null表示没有值或值未知 空字符串表示有一个值,它是一个空字符串。

让我举一个例子。例如,您有一个中间名称字段,需要区分尚未填充中间名称的情况和该人员没有中间名称的情况。使用空字符串表示没有中间名,并使用null表示尚未输入。

在几乎所有情况下,就数据而言,null是有意义的,它们应该在应用程序代码中处理,而不是数据库,假设数据库需要区分两种不同的状态。

短版本:不要根据数据库中的性能/存储问题选择空字符串与空字符串,选择最适合您要存储的信息的字符串。

答案 4 :(得分:0)

我认为空值和空字符串在代码和数据库中都是两个不同的东西。变量或字段为null意味着它没有值,但如果其中一个是空字符串,则它的值恰好是空字符串。

答案 5 :(得分:0)

1:非常主观,正如其他答案所指出的那样,NULL(无答案/未知)和“”(已知无效/不适用 - 即没有中间名的人)之间存在明显差异。

2:不应该这样做。

3:AFAIK(我还是一名大三学生/学习DBA,所以请大家加油)但是应该没有效果。

4:这是有争议的。理论上,如果将NOT NULL约束应用于数据库字段,则应该永远不必处理NULL值。在实践中,理论与实践之间的差距在理论上比在实践中要小。 (换句话说,即使理论上不可能,你应该仍然可以处理一个NULL。)

答案 6 :(得分:0)

我通常在设计期间默认为NOT NULL,除非另有说明 - 特别是会计中的金钱/小数列 - 通常从来都不是未知的方面。可能存在这样一种情况:资金栏是可选的(如调查或业务关系系统,您可以在其中存入您的家庭/业务收入 - 直到/如果客户经理形成关系,这可能是不可知的)。对于datetime,我永远不会允许NULL RecordCreated列,而BirthDate列允许NULL

NOT NULL列删除了大量潜在的额外代码,并确保用户无需考虑特殊处理的NULL - 尤其适用于表示层视图或数据字典以进行报告。

我认为在设计时需要花费大量时间来处理数据类型(char与varchar,nchar与nvarchar,money与decimal,int与varchar,GUID与身份),NULL / NOT NULL,主键,聚簇索引和非聚簇索引以及INCLUDE列的选择。我知道这可能听起来像数据库设计中的所有内容,但如果能够预先理解所有这些问题的答案,那么你将拥有一个更好的概念模型。

请注意,即使在没有列允许为NULL的数据库中,视图中的LEFT JOIN也可能会产生NULL

对于决策过程的具体情况,让我们看一下Address1,Address2,Address3等所有varchar(50)的简单情况 - 一个非常常见的场景(可能更好地表示为单个TEXT列,但让我们假设它以这种方式建模)。我不会允许NULL,我会默认为空字符串。原因是:

1)这不是真的未知 - 它是空白的。多列之间UNKNOWN的性质永远不会定义明确。你不太可能拥有一个已知的地址1和一个未知的地址2 - 你要么知道整个地址,要么你不知道。除非您有约束,否则请将它们留空并且不允许使用NULL。

2)一旦人们开始天真地做像Address1 + @CRLF + Address2这样的事情 - NULL开始NULL整个地址!除非您打算将它们包装在ISNULL的视图中,或者更改ANSI NULL设置,否则为什么不让它们为空 - 毕竟,这是用户查看它们的方式。

对于中间名或中间名,我可能会使用相同的逻辑,具体取决于它的使用方式 - 没有中间名的人或不知名的人之间是否存在差异?

在某些情况下,我可能甚至不允许空字符串 - 我会通过约束来做到这一点。例如,患者的姓名,客户的公司名称。这些永远不应该是空白的,也不应该是空的(或所有空格或类似的)。这些约束越多,数据质量越好,越早发现导入问题,NULL传播等愚蠢错误。

答案 7 :(得分:0)

伪造数据(字符串数据为空字符串,数字为0,日期为某些荒谬的日期)而不是数据库中的null几乎总是一个不好的选择。那些伪造的值并不意味着相同的东西,特别是对于数值数据,很难得到与实际值不同的伪造值。当您输入错误的数据时,您仍然需要围绕它编写代码以确保正确处理事情(例如不返回那些没有结束日期的记录),这样您实际上就不会在开发方面保存任何内容。

如果在插入记录时无法知道数据,则null是最佳选择。也就是说,如果知道alawys的数据,请尽可能使用null。

答案 8 :(得分:0)

你应该看看第六种正常形式。 6NF是专门为解决使用NULLS引起的问题而发明的。 SQL的三值逻辑(真,假,未知)以及程序员常用的两个有价逻辑使得很多问题变得更糟。

在6NF中,每次必须将行/列交集标记为NULL时,只需省略该行即可处理该情况。

但是,我通常不会在数据库设计中尝试6NF。大多数情况下,NULLable列不会用作搜索条件或连接条件的一部分,并且NULLS的问题不会浮出水面。