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


12

我们的公司正在与另一个软件公司进行联合项目,有人告诉我们,如果不应显示特定值,则应传递-5000(它们的任意哨兵值);原因是在Oracle数据库(现在是以前的Oracle开发人员)的建议下,Oracle数据库中没有number列支持空值。该公司还用VB6编写了他们的绝大多数代码(慢慢地过渡到VB.NET,这是另一天的话题...)。出于纯粹的好奇心,此建议是否有任何正当理由?我想不起我这边。

-编辑

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


2
您的意思是,除了“这就是他们的API指定的内容”之外?
罗伯特·哈维

是的,我很好奇为什么他们的API首先要指定它;为什么?是否有这种做法的原因,或者这只是一些疯子?

3
最高秩序的精神!
Philᵀᴹ

Answers:


17

实际上,这个要求是疯狂的。但是,像所有伟大的疯狂想法一样,它可能是基于对潜在基本合理性的理解,这些潜在合理性是由根本不了解基本原理的人们从上下文中获取的。

设计一个数据库架构NULL以使之不允许任何值可能是合理的。但是,如果执行此操作,那么您将致力于规范化级别,其中每个不需要的元素都分解为一个单独的表,并带有适当的外键引用返回给父级。在实践中通常不这样做,但是在有意义的情况下,可能会有好处。

如果要设计一个数据库架构,NULL以不允许使用任何值,那么让它更不用说要求不可思议的值来表示未知的事物是没有意义的。这就引入了允许NULL值具有的所有问题,并增加了额外的代码来检查必须重复出现的魔术值。不管数据库的设计如何,开发一个需要传递魔术值的API都是没有意义的-如果您要通过检查魔术值来使代码混乱,那么您真的不应该让这种精神错乱传播到其他系统。


+1和用于检查魔术值的附加代码无法使用众所周知的功能,例如COALESCE()-,因此变得更加复杂。
ypercubeᵀᴹ

值需要存储在该列的任何索引中。索引不必存储空值。
Tripp Kinetics 2014年

15

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

 SELECT c1, c2 FROM t1 WHERE c3 < 30;

当这没有返回他们期望的结果时,他们意识到它不包含NULL,因此需要编写以下代码:

SELECT c1, c2 FROM t1 WHERE c3 < 30 OR c3 IS NULL;

他们不想写或将来忘记写这个,所以他们想出了使所有NULLS -5000都可用的解决方案。神奇的是,它们的原始查询无需更改即可处理NULL。他们没有意识到的是,现在想要排除这些值的人必须编写以下代码:

SELECT c1, c2 FROM t1 WHERE c3 < 30 AND c3 <> -5000;

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

SELECT c1, c2 FROM t1 WHERE c3 > 40 OR c3 = -5000;

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

SELECT c1, c2 FROM t1 WHERE c3 IS NULL;

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

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


8

这简直是​​疯狂,没有正当理由。NULL被创建以表示不存在值,并使用实际值(例如-5000是傻瓜)。

通常,我不会这么简短地给出答案,但是问题应该成为dba.se上最明显的问题之一,答案越多越好。


5

我考虑了一下,试图肯定,并证明需要使用任意值而不是null,并且(至少在我看来)没有合理的理由,除非在封闭的数据挖掘数据集中以改善和简化性能和查询,然后仅在数字不是可能会使数据倾斜的值的情况下。即使这样,也必须仔细考虑。在所有现实世界中,将值设为null都不是一个好习惯。因为这不是真的,所以这会将NOT NULL列定义从您的朋友变成了敌人。

说我们的应用程序不应该为某些(甚至所有)列接受NULL值是完全不同的事情。这是明智的做法,并且有很好的记录在案的好处是不允许使用空值(例如键和索引以及统计计算)。但是,将值分配给null的“ sit in the place”根本不同。它是您的后盾,因为您必须首先选择一个永远不会使用的值,像对待null一样过滤掉该值,并记住不要在计算和汇总中使用它,并将其从外部数据源中删除。这至少与使用null表示实际值(这是您要告诉自己要避免的,但并非要避免的)相同。

一旦了解,就可以解决大多数由null引起的问题(更好的规范化,基于函数的索引或位图索引,或者简单的WHERE x IS NOT NULL)。您是否认为某个大型电信公司或亚马逊在每月一次的性能会议上概述了一项伟大的计划,即“通过将null替换为任意值(例如-5000或类似值)来加快对其庞大数据集的查询,我很看重价值……”。还是您认为他们花时间在更好的应用程序设计之间,以过滤掉不需要的空值,并根据得到实际数据进行查询优化?好的,也许每月一次的会议可能有点乐观,但是无论何时发生,我都可以向您保证“用-5000(或其他任何值)替换null以获取更好的API”不是一个议事日程。

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

如果没有答案(或NULL)不是对输入请求的有效响应,则不要在应用程序或数据库中允许它,如果响应良好,则必须在应用程序和数据库中都允许它并进行处理作为有效的回应。如果它是一组有效响应的一部分,则必须将您的数据库设计为存储它。毕竟您不要说嘿,数字字段是如此无聊,因此可以将数字存储在斑点中,并使用野生动物的图片来表示每个数字,因为这很令人毛骨悚然(很酷但很疯狂)。我们还没有确定我们不喜欢字母B,并且像芝麻街的一场恶梦一样,在数据中将其替换为#。如果B不是响应,我们希望告诉用户“嘿,您不能在此处放置B”。那么为什么要区别对待null?

因此,请避免在应用程序级别上不想要的空值,并在您接受它们的数据库中进行处理,否则肯定会因为长颈鹿+长颈鹿=河马而导致毫无意义的数据混乱会给您带来麻烦。


2
我的父母并不懒惰,而且我也没有中间名。并非所有人都生活在美国。
ypercubeᵀᴹ

1
这只是一个轻松的例子,并不意味着冒犯。当然,有许多人没有中间名(第一点),这是出于许多充分正当的理由(要点)。此列中的Null不会告诉您它为什么丢失。不确定您的地缘政治角度-我不住在美国,但实际上有个中间名。我猜很难根据丢失的数据做出假设。

没有冒犯。我实际上支持您的回答。我认为您的主要观点是,不接受/不允许数据库中的Null和用魔术值替换Null之间存在区别。
ypercubeᵀᴹ

5
如果我的中间名是“ -5000”,我会喜欢的!:d
Philᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.