NULL与NOT NULL的性能差异

3

最近我在查看我们的SQL表时发现了以下情况。

    [FooColumn] CHAR (1) DEFAULT ('N') NOT NULL,

您可以看到,FooColumn始终默认为'N',但仍指定了“NOT NULL”。

将列设置为“NOT NULL”而不是“NULL”,是否会有一些存储/性能差异?

SQL Server如何处理“NOT NULL”和“NULL”列之间的区别?

注意:这仅适用于SQL,而不涉及外部执行NULL检查的开销。


3
“NULL”或“NOT NULL”应该有其存在的原因。不要担心性能或存储差异。 - jarlh
1
为什么不关注性能或存储呢? 每一位都很重要。 - Bernard Walters
2
一个设计不当的数据库比浪费一点或一纳秒的时间更糟糕。 - jarlh
数据库设计师可能不希望任何人这样做:INSERT INTO Table (foo) VALUES (null);。与空值工作可能非常麻烦。空引用的发明者称其为“十亿美元的错误”(参考链接)。 - David Rushton
5
@destination-data - SQL中的NULL只与空引用共享一个名称,它们并不是同一回事。 - Damien_The_Unbeliever
显示剩余3条评论
4个回答

7
只有在有理由时(例如UI所需的必填字段或后端关系),您才应该使用NOT NULL。 NOT NULL与NULL性能相比可以忽略不计,并且根据2016年(SQL SERVER)的这篇文章,在决定NOT NULL vs NULL时,性能不应成为考虑因素。
即使该字段默认为“N”,如果允许空值,则命令仍然可以将其设置为NULL。问题在于NULL是否是该列的有效数据。 编辑 在数据驱动的技术应用程序中,根据我的经验,这些是我们使用的一些指南:
  • 对于数字字段,NULL对用户来说是未知的,所有数字都具有意义。
  • 对于字符串字段,NULL和""对用户来说是相同的,因此取决于您的后端应用程序。
  • 我知道您的问题排除了ISNULL检查,但如果您正在进行大量的检查,则可能是一个代码异味,如果可能的话,这些字段应该是NOT NULL,因为它们可能会变得昂贵。

我同意“它归结为NULL是否是该列的有效数据”,但是我发现很少有情况是真实的。如果您有一个描述某些内容的数据结构,它应该是完全填充的,即使您使用“未知”而不是null值。 - RegBes
2
我们有一些数字字段,负数、0或正数都是有效的技术数据。虽然在初始保存时不需要这些数据,但稍后可能会输入。在这种业务情况下,由于数据在输入之前是未知的,并且没有其他有效的替代品,因此这些数据是有效的。 - Gander7
1
@RegBes,我希望数据完全被填充,但很遗憾,这并不总是现实。特别是,外键如果关系存在与否可能会有所不同。 - Gander7

4

这是一个复杂的“辩论”。

NULL表示未知。与0或空字符串不同。

NOT NULL表示您需要在其中插入一个值,即使它是空字符串或0也是如此。许多设计师认为这是更好的设计。其他人认为使用NULL值没有问题。不同的软件公司将强制执行不同的规则。

具有“默认”值意味着当您创建新记录而没有指定值时,它将使用默认值。无论字段是否为NULL或NOT NULL。

具有NULL值可能会对性能产生影响(因为DBMS需要处理这种特殊情况),这将取决于您使用的DBMS,版本,配置等...您需要使用自己的设置进行基准测试以了解情况。

这是一篇好文章:http://www.itprotoday.com/microsoft-sql-server/designing-performance-null-or-not-null


0
由于问题的提出方式是:“NULL vs NOT NULL 性能差异”,答案必须基于行的存储结构以及在出现 Null 时对行的处理的差异。答案是:没有区别。以下是讨论 SQL Server 行结构的文章链接: https://www.red-gate.com/simple-talk/sql/database-administration/sql-server-storage-internals-101/ https://aboutsqlserver.com/2013/10/15/sql-server-storage-engine-data-pages-and-data-rows/ 在这里,该列被定义为 CHAR(1),因此它是一个固定大小的列。在行结构信息中检查空字符串和 Null 之间的差异。在存储 Null 或空字符串时没有结构空间节省;结构信息不随约束定义而改变。如果你正在寻找与数据结构相关的性能问题,那么你需要寻找其他方面。

在我看来: 定义为CHAR(1)的列通常包含具有少量不同值的编码信息。 这种列通常通过FK指向“翻译”表。 因此,如果它是“2状态指示器值”,则可以使用BIT类型,知道所有此类型的列都分组在同一个字节中。 如果需要更多不同情况(更多不同的值),则tinyint类型也将占用1个固定大小的字节,但不需要验证排序以处理关系。(注意:TinyInt比CHAR(1)提供更多的值)

另外,如果您还没有FK约束,则必须平衡考虑。


-1
 [FooColumn] CHAR (1) DEFAULT ('N') NOT NULL,

它比NCHAR(1), VARCHAR(1)或NVARCHAR(1)要好得多! (对于MySQL,请检查FooColumn CHARACTER SET)

但是,根据您的RDBMs和现有开发情况,调查是否可以使用BIT或TinyInt(无排序规则)

与“NULL”相比,需要检查“NOT NULL”的额外成本非常非常小。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接