在 Oracle 中不使用可为空数字的原因?

12 null oracle database-design

我们公司正在与另一家软件公司进行联合项目的接口,我们被告知,如果不应该显示特定值,我们应该传入 -5000(他们的任意标记值);原因是他们的 Oracle 数据库中没有数字列支持空值,这是根据他们(现在是前任)Oracle 开发人员的建议。这家公司还在 VB6 中编写了绝大多数代码(慢慢过渡到 VB.NET,这是另一天的另一个话题......)。出于纯粹的好奇,这个推荐有什么正当理由吗?我想不出任何站在我这边的人。

- - 编辑

感谢大家的反馈。我在 CodeProject.com(链接)上提出了同样的问题,并收到了非常相似的反馈。似乎唯一一次可以开始证明这种做法是与外键有关的,我可以声明它们在系统中的任何地方都没有使用外键。做出此决定的开发人员(我曾经在该公司工作)的经验比我多得多,因此我想确保在遭到嘲笑之前没有正当理由。

Jus*_*ave 17

实际上,要求是疯狂的。然而,像所有伟大的疯狂想法一样,它可能是基于一些潜在的合理性,而这些人对潜在的基本原理一无所知。

将数据库模式设计NULL为不允许使用任何值是合理的。但是,如果您这样做,您将致力于标准化级别,其中每个非必需元素都被分解到一个单独的表中,并带有一个适当的外键引用返回到父级。在实践中并不经常这样做,但在有意义的情况下,可能会有好处。

如果您打算设计一个NULL不允许使用任何值的数据库模式,那么允许更不用说需要魔术值来指示某些内容是未知的是没有意义的。这引入了允许NULL值所带来的所有问题,并添加了额外的代码来检查必须在所有地方重复的魔术值。不管数据库设计如何,开发一个要求传递魔法值的 API 是没有意义的——如果你打算用检查魔法值来阻碍你的代码,你真的不应该让这种疯狂传播到其他系统.


Lei*_*fel 15

没有使用魔法值而不是 NULL 的有效理由。这可能是制造这种混乱的人的思考过程。他们这样写:

 SELECT c1, c2 FROM t1 WHERE c3 < 30;
Run Code Online (Sandbox Code Playgroud)

当这没有返回他们期望的结果时,他们意识到它不包括 NULL 并且需要这样写:

SELECT c1, c2 FROM t1 WHERE c3 < 30 OR c3 IS NULL;
Run Code Online (Sandbox Code Playgroud)

他们不想写或者以后忘记写这个,所以他们想出了让所有NULLS为-5000的解决方案。神奇的是,他们的原始查询无需任何更改即可处理 NULL。他们没有意识到,现在想要排除这些值的人必须这样写:

SELECT c1, c2 FROM t1 WHERE c3 < 30 AND c3 <> -5000;
Run Code Online (Sandbox Code Playgroud)

或者,如果他们想要这些值并且正在搜索更高的范围:

SELECT c1, c2 FROM t1 WHERE c3 > 40 OR c3 = -5000;
Run Code Online (Sandbox Code Playgroud)

他们也可能没有意识到以下内容不再有意义:

SELECT c1, c2 FROM t1 WHERE c3 IS NULL;
Run Code Online (Sandbox Code Playgroud)

相反,一个人必须记住魔法值。对于使用的每种数据类型,他们必须记住更多的魔法值,例如 1/1//1900、“Z”、-5000。此外,当魔法值在数据中时,他们还必须记住替代魔法值。

因此,对于一种特定情况,它以牺牲其他情况为代价使代码更简单,更不用说磁盘空间、索引大小、查询解析、一致性等。


Phi*_*lᵀᴹ 8

这完全是疯狂的,没有任何理由。NULL被创建来表示没有值 & 使用像 -5000 这样的实际值是疯子。

通常我不会写这么短的答案,但这个问题应该是 dba.se 上最明显的问题之一,答案越多越好。


小智 5

我想了一下,试图肯定并证明需要使用任意值而不是 null 并且似乎(至少对我而言)没有正当理由,除非可能在封闭的数据挖掘数据集中改进和简化性能和查询,然后仅在数字不是可能会扭曲数据的值的情况下。即便如此,也必须仔细考虑。在所有现实世界的情况下,给 null 一个值都不是好的做法。这会将 NOT NULL 列定义从您的朋友变为您的敌人,因为它确实不是真的。

说我们的应用程序不应该接受某些(甚至所有)列的 NULL 值是完全不同的事情。这是明智且良好的做法,并且有据可查的不允许空值(例如键和索引以及统计计算)的好处。但是,为 null 的“原地”赋值完全不同。它是您自己的后盾,因为您必须首先选择一个永远不会使用的值,像过滤空值一样过滤掉该值,并记住不要在计算和摘要中使用它并将其从外部数据馈送中删除. 这至少与使用 null 表示实际值一样糟糕,这是您告诉自己要避免的,但实际上并没有。

一旦理解了空值导致的大多数问题,就可以处理(更好的规范化、基于函数或位图索引或使用简单的 WHERE x IS NOT NULL)。您是否认为在某些大型电信公司或亚马逊的月度绩效会议上,某些 DBA 正在概述一项伟大的计划,以通过将 null 替换为任意值(例如 -5000 或其他值)来稍微加快对其庞大数据集的查询速度——我对价值持开放态度......”。或者您是否认为他们将时间花在更好的应用程序设计以过滤掉不需要的空值和基于他们获得实际数据的查询优化之间??好吧,也许月度会议有点乐观,但无论何时发生,我都可以向您保证“用 -5000(或其他)替换空值以获得更好的 API”不是议程项目。

对我来说,可以说我不会接受丢失的数据(您必须有年龄或价格或地区代码或其他任何内容),有时甚至可以说对于此列有一个默认值,如果你不放别的东西。留出一个值来表示 null 是不好的。以中间名字段为例。有时这些将不存在,因为父母懒得填写所有方框。我们是否在数据中添加“无”、“缺失”或“未知”以改进搜索?不,因为可能会有奇怪的人将他们的名字更改为这些值,因此当我们打印出数据时,我们不知道是否必须包含它。这是一个简单但影响深远的例子。我们知道 NULL 并且有可预测的内置函数来处理它。您无法对此进行更好的编码。

如果没有答案(或 NULL)不是对您的输入请求的有效响应,则不要在应用程序或数据库中允许它,如果它是一个好的响应,那么您必须在应用程序和数据库中都允许它并处理它作为一个有效的回应。如果它是一组有效响应的一部分,则必须将数据库设计为存储它。毕竟你不会说嘿,数字字段太无聊了,让我们将数字存储在 blob 中并使用野生动物的图片来表示每个数字,因为这很疯狂(很酷但很疯狂)。我们也不认为我们不喜欢字母 B,而是像一些残酷的芝麻街噩梦一样在我们的数据中用 # 替换它。如果 B 不是我们想要的响应,我们告诉用户“嘿,你不能把 B 放在这里”。那么为什么要区别对待 null 呢?

因此,避免在应用程序级别避免您不想要的空值,并在您接受它们的数据库中处理它们,否则就像长颈鹿 + 长颈鹿 = 河马一样,毫无意义的数据争吵会给您带来麻烦。

  • 如果我的中间名是“-5000”,我会喜欢的!:D (5认同)
  • 我的父母并不懒惰,顺便说一下,我没有中间名。并非所有人都生活在美国。 (2认同)