I have a table in Oracle 11g Standard One Edition:
table1
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
The table desc is:
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)
I need to find out what is the percentage of storage a table consumes with values NULL?
Example: table1 storage consumed is 1 GB, and NULLs inside it consumes 100MB, so, NULL takes up 10% of the storage.
Also, are there alternate representations of NULL in ORACLE?
The Null Storage Unit is a storage unit on a media server. The client backed up by the test policy may or may not be on the same system.
If a column in a row has no value, then the column is said to be null, or to contain null. Nulls can appear in columns of any datatype that are not restricted by NOT NULL or PRIMARY KEY integrity constraints. Use a null when the actual value is not known or when a value would not be meaningful.
Nulls are stored in the database if they fall between columns with data values. In these cases, they require 1 byte to store the length of the column (zero). Trailing nulls in a row require no storage because a new row header signals that the remaining columns in the previous row are null.
It stores an array of bits (one per column) with the data for each row to indicate which columns are null and then leaves the data for that field blank.
The NULLs in your table may consume as little as 1.75% of the storage space.
But that number is meaningless, even though it's based on the reproducible test case below. It's more important to understand that NULLs are tiny (just one byte). So tiny that the "real" size should be irrelevant except in extreme cases. So tiny that it is almost always a waste of time to worry about alternate representations.
The best case test case (space usage in practice)
Let's create 1GB of data using your table definition. First, let's create the table.
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 */;
Now create one gigabyte of data. Each value uses the largest-possible value for that data type.
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;
/
These queries show that it uses 1GB of space for 1,425,000 rows.
select count(*) from test1;
select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1';
Now create a second table, with the same number of rows, but a NULL
in every column.
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;
The new segment size is only 0.0175GB, or 1.75%.
select bytes/1024/1024/1024 gb from user_segments where segment_name = 'TEST1_NULL';
Why that test case is misleading
While this may sound like a simple question, to completely answer it would require either an entire book or a crystal ball. Getting real storage sizes is ridiculously complicated. You'll need to think about at least these issues:
PCTFREE
, if previous rows were deleted, when the table was last re-organized, block size, etc.Format of a Row Piece (space usage in theory)
The image below is from the Logical Storage Structures chapter of the Concepts Guide:
The Column Data consists of a series of Column Lengths and Column Values. If the value is NULL, the Column Length is set to 0 and the Column Value does not use any space. This is why a NULL always uses just 1 byte, for the number 0.
Most data types are variable so the length will use at least 1 byte and the value will use at least 1 byte if it's non-NULL. Static data types, like DATE
, will still use 1 byte for the length and then 7 bytes for the value. Again, unless the date is NULL, then the length is set to 0 and the value is empty.
This image may also explain the "trailing NULLs" storage trick. When there are trailing nulls, Oracle probably sets the Number of Columns lower, leaves the last Column Length as 0, and infers that the remaining columns are also NULL.
Alternative Representations?
Now I'm getting suspicious. Asking about alternative representations of NULLs brings to mind four kinds of people:
Yeah, NULLs are a bit weird. But it will make sense soon. Don't worry too much about the space, or ways to completely avoid NULLs. The price you're paying for NULLs is nothing compared to the price you'd pay for anti-patterns that completely avoid them.
First depends on the table properties(is it partitioned, indexes, datatype, lob fields etc), file systems and some other factors. In the past I had a similar task for oracle 11. Here are the steps that I took(it wasn't needed to be extremely precise because of the size - Data base had more than 3000 tables):
My algorithm
Count your nulls per column with (this can be automated in order to check which columns are with higher amount of nulls)
SELECT COUNT(*) FROM YourTable WHERE YourColumn IS NULL
Create a copy only based on last measure (1000 records);
Analyse the results.
hope that his will help you.
Note: At least in my case the goal was to analyse database usage and clean up.
Some furhter readings on this topic:
Do NULL values increase storage space?
How to calculate row size in a table?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With