Oracle中的NULL存储

时间:2016-05-10 16:40:19

标签: 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

表格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) 

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

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

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

2 个答案:

答案 0 :(得分:25)

表中的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 */;

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

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;
/

这些查询显示它为1,425,000行使用1GB空间。

select count(*) from test1;
select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1';

现在创建第二个表,其行数相同,但每列中都有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;

新细分大小仅为0.0175GB,即1.75%。

select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1_NULL';

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

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

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

    以下图片来自Logical Storage Structures chapter of the Concepts Guide

    enter image description here

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

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

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

    替代陈述?

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

    1. 绝望的理论人士抱怨违反关系模型并建议使用模糊的工具而不是那些已经工作了好几十年的工具。
    2. 认为一个巨大的实体 - 属性 - 值表的数据架构师总是答案。 &#34;嘿,我的PDF看起来不错,谁在乎它是否无法查询?&#34;
    3. 那些对SQL有点新意并且对NULL工作方式感到沮丧的人。
    4. Stackoverflow用户过多地阅读了问题。 (如果我离开,请随时添加有关此问题背景的信息!)
    5. 是的,NULL有点奇怪。但它很快就会有意义。不要过多担心空间,或者完全避免使用NULL的方法。您为NULL支付的价格与您为完全避免它们的反模式支付的价格相比毫无价值。

答案 1 :(得分:2)

首先取决于表属性(分区,索引,数据类型,lob字段等),文件系统和其他一些因素。 在过去,我有一个类似的任务oracle 11.以下是我采取的步骤(因为大小不需要非常精确 - 数据库有超过3000个表):

我的算法

  1. 创建没有空值(1000条记录)的表副本;
  2. 仅使用空值(1000条记录)创建副本;
  3. 计算每列的空值(这可以自动执行,以便检查哪些列的空值更高)

    SELECT COUNT(*)FROM YourTable WHERE YourColumn IS NULL

  4. 仅根据最后一次测量(1000条记录)创建副本;

  5. 分析结果。

    希望他会帮助你。

    注意:至少在我的情况下,目标是分析数据库使用情况并进行清理。

    关于这个主题的一些读物:

    Do NULL values increase storage space?

    How to calculate row size in a table?