【问题标题】:How much size "Null" value takes in SQL ServerSQL Server 中“Null”值的大小
【发布时间】:2023-03-23 23:05:01
【问题描述】:

我有一张大桌子,有 10 列。其中 4 个在大多数情况下仍然为空。我有一个查询,它的 null 值采用任何大小或没有大小(以字节为单位)。我读了几篇文章,其中一些人说:

http://www.sql-server-citation.com/2009/12/common-mistakes-in-sql-server-part-4.html

有一种误解,即如果我们在表中有 NULL 值,它就不会占用存储空间。事实上,一个 NULL 值占用空间——2 个字节

SQL: Using NULL values vs. default values

数据库中的NULL 值是一个系统值,它占用一个字节的存储空间,表示与空格、零或任何其他默认值相对的值不存在。

请您指导我关于 null 值占用的大小。

【问题讨论】:

    标签: sql-server tsql sql-server-2005 null


    【解决方案1】:

    如果字段是固定宽度,则存储 NULL 占用与任何其他值相同的空间 - 字段的宽度。

    如果字段是可变宽度的,则 NULL 值不占用空间。

    除了存储空值所需的空间之外,还有一个可以为空的列的开销。对于每一行,每个可空列使用一位来标记该列的值是否为空。无论列是固定长度还是可变长度都是如此。


    您在其他来源的信息中观察到差异的原因:

    • 第一篇文章的开头有点误导。这篇文章不是在讨论存储 NULL 值的成本,而是具有存储 NULL 的能力的成本(即使列可以为空的成本)。确实,使列可以为空会花费一些存储空间,但是一旦您这样做了,存储 NULL 所需的空间就比存储值所需的空间要少(对于可变宽度列)。

    • 第二个链接似乎是关于 Microsoft Access 的问题。我不知道 Access 如何存储 NULL 的详细信息,但如果它与 SQL Server 不同,我不会感到惊讶。

    【讨论】:

    • @Mark"确实,使列可以为空需要一些存储空间,但是一旦你这样做了,存储 NULL 所需的空间比存储值所需的空间要少(对于变量width columns)" 你的意思是说它需要 1 位作为可变数据类型在内存中占用的大小。
    • 大多数计算机系统中最小的可寻址内存单元是一个byte(通常为 8 位)。所以实际上,bit 需要byte。很好的答案马克:+1。
    • 但是,第二位和第三位,一直到第八位都适合同一个字节。
    • @Mark - 是的,这看起来更清晰。为消失的评论道歉。我打算修改它,但我的 Internet 连接在删除和提交之间中断了!它还depends a bit (From the comments section here)“对于堆和聚集索引记录,总是有一个NULL位图。对于非聚集索引,如果索引中的所有列都不是NULL,就不会有。”
    • @Martin Smith:我不知道。这使事情变得更加复杂,因为如果我理解正确,这意味着使列可为空不会增加所需的存储空间(因为空位图始终存在)除非该列也在索引中并且索引中的其他列不可为空。在这种情况下,索引现在必须包含一个空位图。
    【解决方案2】:

    From this link:

    每一行的列都有一个空位图 允许空值。如果那一行 列为空,然后在 位图为 1,否则为 0。

    对于可变大小的数据类型 实际大小为 0 字节。

    对于固定大小的数据类型,实际 size 是默认数据类型大小 字节设置为默认值(0 为 数字,'' 表示字符)。

    【讨论】:

    • 你的意思是说,对于像 nvarchar(max) varchar(max) 这样的数据类型,Null 将占用 0 个字节,而对于 int、chars 等,它会将默认大小设为它们拥有的默认值?
    【解决方案3】:

    以下链接声称如果列是可变长度的,即varchar,则NULL 占用0 个字节(加上1 个字节用于标记值是否为NULL):

    上面的链接和下面的链接都声称对于固定长度的列,即char(10)intNULL的值占据了列的长度(加上1个字节来标记它是否是NULL与否):

    例子:

    1. 如果将char(10) 设置为NULL,则占用10 个字节(清零)
    2. int 占用 4 个字节(也归零)。
    3. varchar(1 million) 设置为 NULL 占用 0 个字节(+ 2 个字节)

    注意:稍微切下,varchar 的存储大小是输入的数据长度 + 2 个字节。

    【讨论】:

    • 存储 NULL 的 varchar 会占用 0 + 2 + 1(NULL 开销)字节吗?
    • 它应该是 + 1 bit 来标记 NULL。 @Akash:不需要 2 个字节,因为位图已经将该值标记为 NULL(不会添加任何信息)。
    【解决方案4】:

    存储 NULL 值不占用任何空间。

    "事实上,一个NULL值占据了 空间 – 2 个字节。”

    这是一个误解——即每行 2 个字节,我很确定所有行都使用这 2 个字节,无论是否有任何可为空的列。

    数据库中的 NULL 值是一个系统 占用一个字节的值 存储

    这是一般的数据库,而不是 SQL Server。 SQL Server 不使用 1 个字节来存储 NULL 值。

    【讨论】:

      【解决方案5】:

      尽管这个问题被特别标记为 SQL Server 2005,但现在是 2021 年,应该指出,对于 2005 年之后的任何版本的 SQL Server,它都是一个“技巧问题”。

      这是因为如果使用 ROW 或 PAGE 压缩,如果列定义为 SPARSE,那么它将在实际行中“没有空格”存储一个“空值”。这些是在 SQL Server 2008 中添加的。

      ROW COMPRESSION (which is a prerequisite for PAGE COMPRESSION) 的实现说明:

      所有数据类型的 NULL 和 0 值都经过优化,不占用字节1

      虽然每个物理记录中的每个非稀疏列仍然存储最少的元数据(每列 4 位 +(记录开销 / 列))2,但它严格来说不是值,而是在所有情况3.

      具有 NULL 值的 SPARSE 列不占用空间,也没有相关的每行元数据(随着 SPARSE 列的数量增加),albeit with a trade-off for non-NULL values

      因此,如果不分析实际的数据库使用统计信息,就很难“计算”空间。 每行的平均字节数将根据精确的列类型、表/索引重建设置、实际数据和重复性、填充容量、有效页面利用率、碎片、LOB 使用等而有所不同,并且通常更有用的指标。​​

      1 SQLite uses a similar approach 具有有效地释放 NULL 值。

      2ROW (and thus PAGE) compression can found in "SQL Server 2012 Internals: Special Storage"中使用的技术布局简介。

      列数后面的1或2个字节是CD数组,它使用表中每一列的4位[元数据]来表示关于列长度的信息.. 0 (0×0)表示对应列为NULL。

      3 有趣的事实:使用 ROW 压缩,位列值完全存在于相应的 4 位元数据中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-02-13
        • 2019-03-18
        相关资源
        最近更新 更多