当我有一个单一的表,其中两个字段仅在某些情况下才有值,从而在行中创建了许多NULL
值时,不确定处理NULL
值的最佳实践是什么。
是否应将这两个字段移动到单独的表中,从而创建两个没有NULL
值的表?
跨越这两个表的连接将返回一个与具有NULL
的原始表相同的结果,那么这有什么意义呢?
似乎将它们分开是毫无意义的,但我已经阅读了一些关于完全避免使用空值的数据库的文章。
当我有一个单一的表,其中两个字段仅在某些情况下才有值,从而在行中创建了许多NULL
值时,不确定处理NULL
值的最佳实践是什么。
是否应将这两个字段移动到单独的表中,从而创建两个没有NULL
值的表?
跨越这两个表的连接将返回一个与具有NULL
的原始表相同的结果,那么这有什么意义呢?
似乎将它们分开是毫无意义的,但我已经阅读了一些关于完全避免使用空值的数据库的文章。
从理论上讲,NULL应该表示“未知值”。因此-再次强调,从纯理论角度出发-在规范化时应设计表格,以便您无需填写NULL值来表示“不适用于此行”。然而,这一点与任何实际考虑(设计、性能或查询可读性)几乎没有关系。
从实际角度出发,有一些性能方面的考虑。以下情况下,您应将非常稀疏的数据规范化:
缩短表格具有实质性的好处(无论是IO还是空间)。NULL会占据空间,并且列越宽,性能越差。当表格具有大量行且存在许多这种稀疏列时,特别是如此。对于只有2个这样的列的较小表格,实现的好处可能不值得增加额外的连接麻烦。
您的查询在WHERE
子句中涉及到相应的列。我IRC,查询一个具有大量NULL值的列效率相当低。
另一方面,在某一点上,查询中具有额外的连接可能会损害优化器的性能(至少在Sybase上,当您的连接具有10个以上的表格时会从占用优化器运行时的CPU资源到实际上困惑优化器选择一个非常不好的计划)。解决方案是避免由于规范化而拥有太多表格(例如,不要费力将2个列拆分成单独的表格),或者强制查询计划。后者显然是不好的做法。
空值会导致查询结果不正确和不一致,并且由于需要特殊处理,通常会增加代码复杂度。出于这些原因,在数据库设计中避免或最小化空值通常是有意义的。您在查询中也不需要使用空值 - 尽管 SQL 不幸地使它们很难避免。但是,通过不在基本表中使用空值,您将确保数据模型更准确地反映现实,并为数据库用户提供更多对如何使用空值的控制。
null
值的含义很有帮助 - 不是理论上的含义,而是在您的数据中的含义。
我认为只要您清楚地知道表格中null
的含义,并且如果您确信它只表示一种含义,那么您可以就是否允许它做出明智的决策。
意见:我的经验法则是可为空的字段是可以接受的,但不应多用。
Null值在数据库中非常重要。我从未遇到过不允许null值的数据库,最终这些数据库查询起来很困难,维护也很困难(你如何确定哪个值表示我不知道答案),通常会有更多的坏数据。是的,null值需要在查询中进行特殊处理,但是像将一个较晚的日期(1/1/9999)添加为结束日期以避免出现null值等操作也需要特殊处理。
事实上,有些数据在记录插入时就无法知道,没有任何替代品可以取代null值。
现在,在您的情况下,是否应该拆分为两个表取决于表的宽度和您需要查询可空列的频率。即使有很多null值,我也不太可能将middlename列移动到另一个表中,因为它总是与基本表中的其他信息一起查询。我也不太可能移动结束日期列。但是如果这些列是一些很好了解但通常不会在查询基本数据时查询的内容(例如生日、头发颜色等),那么仅包含包含数据的记录的单独表可能是可以接受的。但请记住,当您进行查询时,如果使用内连接,您将消除第二个表中没有值的所有记录。如果我通常想要所有记录(例如中间名,我很少查询只查找具有“Mary”中间名的人),那么我倾向于将它们保留在同一个表中,除非该表变得非常宽且我通常不想查询该信息。