Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question.

Asked: March 05, 2005 - 5:44 pm UTC

Last updated: November 25, 2019 - 11:57 am UTC

Version: 8.1.6

Viewed 1000+ times

You Asked

Is this true that putting null-common columns at the end of rows saves space in oppose to columns that are being put before the end?

and Tom said...

Ahh, a chance to have a wildly exaggerated example, excellent....


ops$tkyte@ORA9IR2> declare
2 l_stmt long := 'c1 int';
3 begin
4 for i in 2 .. 999
5 loop
6 l_stmt := l_stmt || ', c' || i || ' int';
7 end loop;
8
9 execute immediate 'create table t1 ( x int, ' || l_stmt || ')';
10 execute immediate 'create table t2 ( ' || l_stmt || ', x int )';
11 end;
12 /

PL/SQL procedure successfully completed.

ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> insert into t1 (x) select object_id from all_objects;

27812 rows created.

ops$tkyte@ORA9IR2> insert into t2 (x) select x from t1;

27812 rows created.

ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> exec show_space( 'T1' );
Free Blocks............................. 2
Total Blocks............................ 48
Total Bytes............................. 393,216
Total MBytes............................ 0
Unused Blocks........................... 3
Unused Bytes............................ 24,576
Last Used Ext FileId.................... 8
Last Used Ext BlockId................... 489
Last Used Block......................... 5

PL/SQL procedure successfully completed.

ops$tkyte@ORA9IR2> exec show_space( 'T2' );
Free Blocks............................. 5
Total Blocks............................ 4,224
Total Bytes............................. 34,603,008
Total MBytes............................ 33
Unused Blocks........................... 98
Unused Bytes............................ 802,816
Last Used Ext FileId.................... 8
Last Used Ext BlockId................... 5,129
Last Used Block......................... 30

PL/SQL procedure successfully completed.


wow, 400k, versus 34MEG


So, what happened -- well, Oracle will store "trailing null columns" in a table using zero bytes. If the last column in the table is NULL, nothing, if the last and second to last are NULL -- two nothings and so on...

So, here we have 1,000 columns (most you are going to have). In case 1 -- one not null column followed by 999 "nothings"

In case 2 -- 999 nothings followed by one column -- in this case, each of the nothings took a byte (null flag -- to say "column 42 isn't here, it is null")


Take a couple thousand rows with 999 bytes -- versus the same without them and it adds up.


So, yes -- but remember -- this was total exaggeration here. But if you have 1,000,000 rows and know that the "last column or two" are mostly null -- you can save a meg or two (not much).


Now you know how it works though, it is true that

o putting columns you frequently access "near the front"
o putting columns that are mostly NULL last
o putting columns you infrequently access nearer to the end of the table

will derive mostly marginal improvements in speed and space usage.


Rating

  (4 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Clear as crystal now

Yoni, March 05, 2005 - 6:48 pm UTC

Thanks for your quick response, Tom !
Right to the point.


A reader, March 06, 2005 - 1:53 am UTC

Hi Tom,

How can "reorder" the columns in table definition? i.e. move column from column 1 to column 10. I heard that there is some scripts (from Oracle) that can be used to "reorder" the columns, is this true?

Thanks
David

Tom Kyte
March 06, 2005 - 7:31 am UTC

you rebuild the table - create table new_table as select <columns in order> from old_table

index, grant, constrain -- and then rename.

or use dbms_redefinition (search for that for examples on this site)



null_columns

Jon Eveland, March 06, 2005 - 1:41 pm UTC

Great affirmation of something I was taught over and over again, but never proved

Test

Dariusz Olczyk, November 25, 2019 - 8:53 am UTC

Hi,
I performed this test using your scripts (100 columns).
I created table T1 and T2 and inserted 10000 rows.
But when I run show_space procedure I'm totally confused:
T1: Total Bytes .... 10485760
T2: Total Bytes .... 2097152
It's completely different result then yours.
Table T1 is 5 times bigger then T2.

Can you explain this?

My database version is 12.1.0.2.0

Chris Saxon
November 25, 2019 - 11:57 am UTC

What exactly is the script you ran?

Running on 19c and 11.2 I get results consistent with Tom's - T2 is significantly bigger than T1:

declare
  l_stmt long := 'c1 int';
begin
  for i in 2 .. 999 loop
    l_stmt := l_stmt || ', c' || i || ' int';
  end loop;

  execute immediate 'create table t1 ( x int, ' || l_stmt || ')';
  execute immediate 'create table t2 ( ' || l_stmt || ', x int )';
end;
/

insert into t1 (x) select object_id from all_objects;

insert into t2 (x) select x from t1;
commit;

select segment_name, bytes from user_segments
where  segment_name in ( 'T1', 'T2' );

SEGMENT_NAME        BYTES      
T1                 917504 
T2               88080384 

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library