Oracle中的NULL存储

dan*_*ang 15 sql oracle

我在Oracle 11g Standard One Edition中有一个表:

表格1

col1 col2 col3 col4 col5 col6 col7 col8       col9 col10 col11
1    NULL 2    3    4    5    NULL NULL       19   21    22
1    NULL 2    3    4    5    NULL 1 Jan 2009 19   21    22
1    NULL 2    3    4    5    NULL NULL       19   21    22
1    9    2    3    4    5    A    NULL       19   21    22
1    NULL 2    3    4    5    B    NULL       19   21    22
Run Code Online (Sandbox Code Playgroud)

表格desc是:

Name                 Null Type          
-------------------- ---- ------------- 
COL1                      NUMBER        
COL2                      NUMBER        
COL3                      NUMBER        
COL4                      NUMBER       
COL5                      NUMBER        
COL6                      NUMBER        
COL7                      VARCHAR2(255) 
COL8                      DATE          
COL9                      DATE  
COL10                     DATE        
COL11                     VARCHAR2(255) 
Run Code Online (Sandbox Code Playgroud)

我需要找出表消耗的存储百分比是多少?

示例:使用的table1存储空间为1 GB,其中的NULL消耗100MB,因此,NULL占用存储空间的10%.

另外,ORACLE中是否有NULL的替代表示?

Jon*_*ler 26

表中的NULL可能只占存储空间的1.75%.

但这个数字毫无意义,即使它是基于下面可重现的测试用例.更重要的是要理解NULL很小(只有一个字节).除极端情况外,"实际"尺寸应该是无关紧要的.如此微小以至于担心替代表现几乎总是浪费时间.


最佳案例测试案例(实践中的空间使用)

让我们使用您的表定义创建1GB的数据.首先,让我们创建表.

create table test1(
COL1  NUMBER,
COL2  NUMBER,
COL3  NUMBER,
COL4  NUMBER,
COL5  NUMBER,
COL6  NUMBER,
COL7  VARCHAR2(255),
COL8  DATE,
COL9  DATE,
COL10 DATE,
COL11 VARCHAR2(255)
) pctfree 0 /* Let's assume no updates or deletes, and pack the data tightly */;
Run Code Online (Sandbox Code Playgroud)

现在创建一千兆字节的数据.每个值都使用该数据类型的最大可能值.

begin
    for i in 1 .. 15 loop  --Magic number to generate exactly 1GB.
        insert into test1
        select
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            .0123456789012345678901234567890123456789,
            lpad('A', 255, 'A'),
            sysdate,
            sysdate,
            sysdate,
            lpad('A', 255, 'A')
        from dual
        connect by level <= 95000;    --Magic number to generate exactly 1GB.
        commit;
    end loop;
end;
/
Run Code Online (Sandbox Code Playgroud)

这些查询显示它使用1GB的空间用于1,425,000行.

select count(*) from test1;
select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1';
Run Code Online (Sandbox Code Playgroud)

现在创建第二个表,具有相同的行数,但NULL每列中都有一个.

create table test1_null as
select col1+null c1, col2+null c2, col3+null c3, col4+null c4, col5+null c5, col6+null c6,
    cast(null as varchar2(255)) c7, col8+null c8, col9+null c9, col10+null c10,
    cast(null as varchar2(255)) c11
from test1;
Run Code Online (Sandbox Code Playgroud)

新的细分市场规模仅为0.0175GB,即1.75%.

select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1_NULL';
Run Code Online (Sandbox Code Playgroud)

为什么该测试用例具有误导性

虽然这可能听起来像一个简单的问题,但完全回答它需要整本书或水晶球.获得真正的存储大小非常复杂.你至少需要考虑这些问题:

  1. 可变宽度数据.大多数Oracle数据类型仅使用存储数据所需的空间量.因此,用于该NULL字节的存储百分比完全取决于其他列中的内容.无论数据如何,只有少数数据类型使用静态存储量,例如CHAR,NCHAR,DATE,TIMESTAMP等.
  2. 尾随空值. 行末的所有连续NULL都存储在一个字节中.除非启用基本压缩,否则每个NULL再次使用一个字节.
  3. 行开销. 每行都有开销,这取决于列和配置.表越精细,行开销越占空间,因此NULL使用的百分比将波动.
  4. 阻止开销.这取决于行数,设置PCTFREE,如前一行是否被删除,上次重组表的时间,块大小等.
  5. 分段开销.空间被分配为扩展区块.范围管理可以使用默认算法(我认为分配为1MB到64MB的块),或者它可以是任何自定义值.根据数据量,这种开销变得不太相关.表空间可能设置为一个巨大的统一扩展区大小,例如10GB,这可能会浪费大量空间而不管列值如何.
  6. 其他I/O开销. ASM,操作系统,SAN等也可能浪费空间.

行块的格式(理论上的空间使用)

下图来自"概念指南"的" 逻辑存储结构"一章:

在此输入图像描述

列数据由一系列列长度和列值组成.如果值为NULL,则"列长度"设置为0,"列值"不使用任何空格.这就是为什么NULL总是只使用1个字节,数字0.

大多数数据类型是可变的,因此长度将至少使用1个字节,如果非NULL,则该值将使用至少1个字节.静态数据类型,例如DATE,仍将使用1个字节作为长度,然后使用7个字节作为值.同样,除非日期为NULL,否则长度设置为0,值为空.

此图像还可以解释"尾随NULL"存储技巧.当存在尾随空值时,Oracle可能会将列数设置为较低,将最后一个列长度保留为0,并推断其余列也为NULL.

替代表述?

现在我开始怀疑了.询问NULL的替代表示会让人联想到四种人:

  1. 绝望的理论人士抱怨违反关系模型并建议使用模糊工具而不是几十年来一直工作良好的工具.
  2. 认为一个巨大的实体 - 属性 - 值表的数据架构师总是答案."嘿,我的PDF看起来不错,关心是否无法查询?"
  3. 那些对SQL有点新意并且对NULL工作方式感到沮丧的人.
  4. Stackoverflow用户过多地阅读了问题.(如果我离开,请随时添加有关此问题背景的信息!)

是的,NULL有点奇怪.但它很快就会有意义.不要太担心空间,或者完全避免NULL的方法.您为NULL支付的价格与您为完全避免它们的反模式支付的价格相比毫无意义.