在数据库中过度使用可空列是“代码味道”吗?

时间:2009-06-23 20:19:15

标签: sql

我只是进入一个项目,它有一个相当大的数据库后端。我已经开始挖掘这个数据库了,95%的字段都可以为空。

这是数据库世界中的常规做法吗?我只是一个卑微的程序员,而不是DBA,但我认为你会想把可空字段保持在最低限度,只有它们才有意义。

如果大多数列可以为空,它是否是“代码味道”?

17 个答案:

答案 0 :(得分:16)

根据我的经验,默认值通常是例外,NULL是常态。

是的,空值很烦人。

它也非常有用,因为null是“NO VALUE”的最佳指标。具体的默认值非常具有误导性,您可能会丢失信息或引起混乱。

答案 1 :(得分:13)

任何开发数据输入应用程序的人都知道在输入时某些字段是多么常见 - 即使是对于业务至关重要的列,也要知道@Chris McCall的答案。

然而,“代码味道”仅仅是指示可能以邋way方式编码的指示符。你使用气味来识别需要更多调查的东西,而不一定是必须改变的东西。

所以,是的,如果你如此一致地看到可以为空的列,那你就是可疑的。 可能表示有人在懒惰,或者害怕明确地声明NOT NULL列。你可以证明你自己的分析是合理的。

答案 2 :(得分:9)

我是Extreme NO阵营:我一直避免使用NULL。暂不考虑他们实际意味着什么(因为与不同的人交谈,你会得到不同的答案,如“没有价值”,“未知价值”,“失踪”,“我的姜猫叫做Null”),这是最糟糕的问题NULL的原因是它们经常以神秘的方式破坏你的查询。

我已经失去了调试某人查询的次数(好吧,可能是9次),并将问题追溯到针对NULL的联接。如果你的代码需要ISNULL来修复连接,那么你也有可能失去索引的适用性和性能。

如果您执行必须存储“missing / unknown / null / cat”值(并且这是我更愿意避免的),最好明确一下。

熟练掌握NULL的人可能不同意。 NULL使用倾向于将SQL人群分散到中间。

根据我的经验,重度使用NULL与数据库滥用正相关,但我不会将其作为一些自然法则刻入石碑中。我的经验只是我的经历。

编辑:额外的想法。那些像我一样的反空种族主义者可能会比那些支持NULL的人更加兴奋。我不认为狂犬病归一化器会对他们的桌子上可能带有NULL的粗糙边缘感到满意。很多空值可能表明数据库开发人员没有进行大规模的标准化。因此,不是NULL表示代码是“坏”,它可能会建议开发人员在规范化上的哲学立场。也许这是达成的。只是一个想法。

答案 3 :(得分:7)

不知道我是否认为它总是一件坏事,但是如果要添加列是因为单个记录(或者可能是少数)需要有值而大多数没有,那么它表示一个非常平坦的表结构体。如果您看到列名称如“addr1”,“addr2”,“addr3”,那么它会发臭!

我敢打赌,您拥有的大多数列都可以删除并在其他表中表示。您可以通过外键关系找到“非空”的。这将增加你将要做的连接,但是做一个“不是col1为空的地方”可能更具信息性。

答案 4 :(得分:6)

我认为应该避免可以为空的列。只要域的语义使得可以使用明确指示缺失数据的值,就应该使用它而不是NULL。

例如,让我们想象一个包含Comment字段的表。大多数开发人员会在此处放置一个NULL来表示列中没有数据。 (并且,希望是一个不允许零长度字符串的检查约束,以便我们有一个众所周知的“值”来表示缺少值。)我的方法通常是相反的。 Comment列为NOT NULL,零长度字符串表示缺少值。 (我使用检查约束来确保零长度字符串实际上是一个零长度字符串,而不是空格。)

那么,我为什么要这样做呢?有两个原因:

  1. NULL需要SQL中的特殊逻辑,这种技术可以避免这种情况。
  2. 许多客户端库都有特殊值来表示NULL。例如,如果您使用Microsoft的ADO.NET,则常量DBNull.Value表示NULL,您必须测试它。在NOT NULL列上使用零长度字符串可以满足需要。
  3. 尽管如此,在很多情况下NULL都没问题。事实上,我不反对在上面的场景中使用它们,虽然这不是我喜欢的方式。

    无论你做什么,都要善待那些会使用你的桌子的人。 保持一致。允许他们自信地 SELECT让我解释一下我的意思。我最近参与了一个项目,其数据库不是我设计的。几乎每列都可以为空,没有任何限制。什么代表没有价值,没有一致性。它可能是NULL,一个零长度的字符串,甚至是一堆空格,而且经常是。 (我不知道那些价值观如何到达那里。)

    想象一下开发人员必须编写的丑陋代码,以便在此方案中查找缺少Comment字段的所有记录:

    SELECT * FROM Foo WHERE LEN(ISNULL(Comment, '')) = 0
    

    令人惊讶的是,尽管存在可能的性能影响,但开发人员认为这是完全可以接受的,甚至是正常的。更好的是:

    SELECT * FROM Foo WHERE Comment IS NULL
    

    或者

    SELECT * FROM Foo WHERE Comment = ''
    

    如果您的表格设计得当,可以依赖上述两个SQL语句来生成高质量的数据。

答案 5 :(得分:4)

简而言之,我会说是的,这可能是代码味道。

列是否可以为空是非常重要的,应该仔细确定。应该针对每一栏评估这个问题。我不相信NULL的单一“最佳做法”默认值。对我来说,“最佳实践”是在设计和/或重构表格时彻底解决可空性问题。

首先,您的主键列都不可为空。然后,我强烈倾向于NOT NULL以获取任何外键。

我考虑的其他一些事情:

应强烈避免使用NULL的标准: money列 - 真的是否有可能无法获得此金额?

NULL最常见的标准: datetime列 - 没有保留日期,因此NULL实际上是您的最佳选择

其他数据类型: char / varchar列 - 代码/标识符 - NOT NULL几乎完全是 int列 - 主要是NOT NULL,除非您想要区分未知响应的“孩子数量”。

答案 6 :(得分:2)

不,字段是否应该可以为空是数据概念,不能是代码气味。 NULL是否令代码烦恼与拥有可空数据字段的用处无关。

答案 7 :(得分:2)

它们是一种(很常见的)气味,我很害怕。查看有关该主题的C.J.日期着作。

答案 8 :(得分:1)

我是这么认为的。如果您不需要这些数据,那么这对您的业务并不重要。如果它对您的业务很重要,则应该是必需的。

答案 9 :(得分:1)

根据我的经验,当Null和Not Null与所需字段/非必需字段不匹配时,这是一个问题。

可能的是那些真的都是可选字段。如果您在业务层或UI层中发现需要这些字段,那么我认为这意味着数据模型已经偏离业务对象模型,并且是过度保守的DB更改策略或监督的标志。

如果您对数据运行示例数据生成器,然后尝试根据SQL加载有效的数据,那么如果规则匹配,您会马上发现。

答案 10 :(得分:1)

这完全取决于项目的范围和要求。我不会单独使用多个可空字段作为编写糟糕的代码或设计代码的指标。看一下业务领域,如果那里有许多可以在文件中可以为空的非可空字段,那么你就会遇到一些问题。

答案 11 :(得分:1)

作为最佳实践,如果列不应该为空,则应将其标记为可以为空。但是,我不相信这样的事情完全疯了。

答案 12 :(得分:0)

这似乎很多,这可能意味着你至少应该进行调查。请注意,如果这是包含大量数据的成熟产品,则说服任何人改变结构可能会很困难。在设计阶段的早期阶段,您可以更容易地修复所有相关代码以调整更改。

他们使用空值是否不好将取决于允许空值的列是否应该是相关表(家庭电话,手机,商务电话等应该位于相同的电话表中)或者它们是否相似喜欢可能不适用于所有记录的东西(可能是一对一关系的相关表),或者在数据输入时可能不知道(可能没问题)。我还会检查它们实际上是否确实有一个值(如果商业逻辑确实需要这些信息,那么你可以改为不为空)。如果您有一些空

的记录

答案 13 :(得分:0)

根据我的经验,像你这样的大型数据库中很多可以为空的字段是非常正常的。考虑到它可能被不同人编写的许多应用程序使用。使列可以为空是令人讨厌的,但它可能是保持应用程序健壮的最佳方法。

答案 14 :(得分:0)

将继承(例如c#对象)映射到数据库的许多方法之一是在层次结构顶部为类创建表,然后为所有其他类添加列。当不同子类的对象存储在数据库中时,列必须是可为空的。这称为Single-table inheritance mapping(或Map Hierarchy To A Single Table),是标准设计模式。

单表继承映射的副作用是大多数列都可以为空。


同样在Oracle中,空字符串(0长度)被认为是null,因此在某些公司中,即使在SqlServer上,所有字符串列也都可以为空。 (仅仅因为第一个客户想要SqlServer上的软件并不意味着第二个客户没有不会让SqlServer进入网络的Oracle DBA)

答案 15 :(得分:0)

在那里抛出相反的意见。数据库中的每个字段都应该可以为空。没有什么比使用数据库更令人沮丧的了,在每个插件上抛出一个关于必需的或需要的异常。什么都不需要。

有一个例外,密钥。显然,所有主键和外键都应该强制存在。

应用程序的工作应该是验证数据和数据库,以便简单地存储和检索您提供的内容。让它处理验证逻辑即使像null或非null一样简单也会使项目的维护变得更加复杂,因为不同的规则会分散在所有内容上。

答案 16 :(得分:0)

正如其他人所提到的,前置数据输入应该允许省略许多字段。人们如何解释NULL三级性质(例如,空还是丢失)使问题变得复杂。

因此,我只回答数据库设计的一个方面:外键。

general 中,外键不受业务逻辑的任意影响,因此看到这些允许NULL的列肯定是一种代码味道。< / p>

例如,如果您有一个[Person]表,则在任何情况下都不会有一个[Person].[FatherID]故意为{em> 的NULL值。

>

对于大型数据库,由于错误的不可避免性,有时可能会尝试将NULL保存到这样的列中,而通过使用{{1 }}约束。因此,对于版本1 或表格,您绝对不应在没有理由的情况下允许可空列

但是,在不断发展的代码库中,事情变得更加棘手,尤其是那些保持在线状态并因此需要迁移脚本升级的代码库。特别是,您稍后可能会发现可为空的列添加到表中,因为根据集成过程的不同,将它们适当地添加为不可为空可以quite hard

此外,可视表设计器(例如SQL Server Management Studio和Visual Studio中的默认表)默认允许NOT NULL,因此这可能只是代码审查不足的问题。


我不想为标志(即boolean)列尝试一个正确的答案,但是我强烈建议考虑在不使用NULL的情况下如何实现它们,因为我通常已经找到避免这种情况的方法。即使在业务逻辑的约束下也为空。