nice one
Zahid, July 31, 2006 - 4:33 am UTC
well demonstration of tricks/tips & techniques.
What is the methodology behinf compression !!
Prashant, July 31, 2006 - 3:10 pm UTC
Hello Tom,
This trick is Superb..Can you please throw some light on Strategy to compress table's data and select data from compressed table, as i know it takes time during insertion...
Thanks
July 31, 2006 - 8:46 pm UTC
table compression works when you do direct path operations (insert append, direct path load, alter table move... ) not during normal insert/update/delete.
It works by removing repetitive data and storing it once per block instead of once per occurrence per block.
Column Compression
A reader, July 31, 2006 - 9:24 pm UTC
Tom-
I wish Oracle adds column level compression soon. This would be very useful in Data Warehouse environments where repeated code values (low cardinality columns) can be compressed in the block header.
August 01, 2006 - 7:01 am UTC
we have had that since version 9ir2.
It is called a compressed table. Any column, in fact any set of columns, that have repeated values are compressed.
If you have a table with:
first_name
middle_name
last_name
street
city
and you have Allen as a first_name, middle_name, last_name, street, city - either on the same row or across rows - we'll store Allen once.
Adding a column to an existing, populated table
SC, August 21, 2006 - 11:06 am UTC
When adding a column to an existing compressed table that contains data, does the table have to be decompressed as part of the process (either explicitly or under the covers)? This was the case with 9i and so sufficient diskspace had to be provisioined to cater for this? Are there any restrictions to adding a new column? I've read that it is not possible to specify a default value for example.
August 27, 2006 - 9:50 am UTC
it depends on the release.
And the data didn't have to be decompressed if you use CREATE TABLE AS SELECT as demonstrated above.
Adding Column in compressed table in Rel 9.2.0.1.0
Sanjay, August 31, 2006 - 3:45 pm UTC
Tom,
1) Can you show me how can I add column to compressed table ?
2) I was able to add column to the table by exporting it, dropping it, creating table without the compress option, importing the data and adding a column. Is this the correct option.
NB: The table in question is a huge table.
>>Except of the sql session, I cannot add column to a compressed table.
SQL*Plus: Release 9.2.0.1.0 - Production on Thu Aug 31 15:39:09 2006
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
Connected to:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production
SQL> create table My$table as select * from all_objects
2 /
Table created.
SQL> alter table my$table compress ;
Table altered.
SQL> alter table my$table add col1 varchar2(20) ;
alter table my$table add col1 varchar2(20)
*
ERROR at line 1:
ORA-22856: cannot add columns to object tables
SQL> alter table my$table nocompress ;
Table altered.
SQL> alter table my$table add col1 varchar2(20) ;
alter table my$table add col1 varchar2(20)
*
ERROR at line 1:
ORA-22856: cannot add columns to object tables
SQL>
Thanks,
Sanjay
boston,MA
August 31, 2006 - 7:06 pm UTC
you can:
create table new_table COMPRESSED
as
select t.*, <new column here> from old_table t;
drop old_table;
rename new_table to old_table;
that'll be about it in 9i, or upgrade to 10g - you are already 6 patchsets off of supported software as it is...
very veru helpful
Charit, October 13, 2006 - 10:37 am UTC
good work mate...
its very helpful for me
Sravan, December 12, 2006 - 9:16 am UTC
I searched in google and found the link to this website.. i was happy to see this link, I got confidence that my problem got resolved. Thanks a lot for providing needy information with examples.
Datatype
A reader, January 05, 2007 - 3:43 pm UTC
create table new_table COMPRESSED
as
select t.*, <new column here> from old_table t;
How can the datatype and size of the new column(s) be specified using this technique?
Thanks
January 06, 2007 - 8:58 am UTC
ops$tkyte%ORA9IR2> create table t1 as select * from all_users;
Table created.
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> create table t2
2 compress
3 as
4 select cast(username as varchar2(40)) username,
5 cast(user_id as number(10,2)) user_id,
6 created
7 from t1
8 /
Table created.
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> desc t1
Name Null? Type
---------------------------------------- -------- ----------------------------
USERNAME NOT NULL VARCHAR2(30)
USER_ID NOT NULL NUMBER
CREATED NOT NULL DATE
ops$tkyte%ORA9IR2> desc t2
Name Null? Type
---------------------------------------- -------- ----------------------------
USERNAME VARCHAR2(40)
USER_ID NUMBER(10,2)
CREATED NOT NULL DATE
Datatype
A reader, January 06, 2007 - 2:14 pm UTC
Not quite. We need to add columns to a compressed table T. Similar to doing ALTER TABLE T add (new_col varchar2(10))
The ALTER TABLE is not supported in 9iR2 so you suggested doing a CTAS and including the new columns to it.
If I do
create table t2 compress as
select t.*,'xxx' new_col from t;
I get new_col as CHAR(3) and not VARCHAR2(3) and also it contains that dummy data xxx that I don't really need.
What I really need is a CTAS where I can specify EMPTY columns with the datatype/size I need, just as if I were doing a ALTER TABLE ADD COLUMN
Help? Thanks
January 07, 2007 - 8:05 pm UTC
same answer - use cast????
ops$tkyte%ORA9IR2> create table t2
2 compress
3 as
4 select cast(username as varchar2(40)) username,
5 cast(user_id as number(10,2)) user_id,
6 created,
7 cast( null as char(3) ) new_column ,
8 cast( null as varchar2(3) ) new_column2
9 from t1
10 /
Table created.
Elapsed: 00:00:00.05
ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> desc t1
Name Null? Type
---------------------------------------- -------- ----------------------------
USERNAME NOT NULL VARCHAR2(30)
USER_ID NOT NULL NUMBER
CREATED NOT NULL DATE
ops$tkyte%ORA9IR2> desc t2
Name Null? Type
---------------------------------------- -------- ----------------------------
USERNAME VARCHAR2(40)
USER_ID NUMBER(10,2)
CREATED NOT NULL DATE
NEW_COLUMN CHAR(3)
NEW_COLUMN2 VARCHAR2(3)
and of course, you can always:
a) create table using just "create table ( .... ) compress"
b) then - insert /*+ append */ into
to load it.
Is the index reusable?
kpanchan, February 03, 2007 - 10:25 pm UTC
Tom
Your solution to add column solution very useful for my requirement.
I need to add column to Oracle9i.
If I am follow your solution, When I rename T2 as T1, I will be loosing my indexes.
Is that right? If yes, Can I save Indexes on T1 and create those indexes on T2 later.
I want to retain same indexes on T2 table also.
February 04, 2007 - 8:41 am UTC
you would add any indexes to you wanted - you would not "lose" any - indexes stay with a table, if you want T2 to have some indexes, just create them
Cast with union all
Robert Koltai, February 05, 2007 - 6:03 am UTC
Hello Tom,
I wanted to use cast as you suggested in CTAS with union all.
I need number (38) column, but I get number.
This is what I do:
** OK **
create table testOK as
select cast (1 as number(38)) c from dual;
desc testOK;
SQL>
C NUMBER(38)
** NOT OK **
create table testNOTOK as (
select cast (1 as number(38)) c from dual
union all
select cast (2 as number(38)) c from dual
);
desc testNOTOK;
SQL>
C NUMBER
So why does union all "conflict" with the cast?
I did not find the reason in any documentation.
Thanks,
Rob
February 05, 2007 - 9:39 am UTC
it doesn't really - you just need to use cast at the top level
ops$tkyte%ORA9IR2> create table testNOTOK as
2 select cast(c as number(38)) c
3 from ( select cast (1 as number(38)) c from dual
4 union all
5 select cast (2 as number(38)) c from dual
6 )
7 /
Table created.
ops$tkyte%ORA9IR2> desc testNOTOK;
Name Null? Type
---------------------------------------- -------- ----------------------------
C NUMBER(38)
Can add to Partition table?
kpanchan, February 05, 2007 - 10:09 am UTC
Tom
Using CAST, can I able to add new column to COMPRESSED PARTITIONED table?
From your solution, We can add new column to COMPRESSED table.
Table T1 is Partitioned and Compressed.
Tried to create table T2 with CAST as given below.
CREATE TABLE T2 as SELECT t1.*, CAST(null as VARCHAR2(10)) C1 FROM t1;
Table T2 was created, but it was not partitioned.
Is it possible to copy partition details to T2 from T1?
Thanks for your reply.
February 05, 2007 - 10:38 am UTC
you would have to explicitly put that into the create table as select - the partition details.
ops$tkyte%ORA10GR2> create table t1
2 PARTITION BY RANGE (dt)
3 (
4 PARTITION part1 VALUES LESS THAN (to_date('13-mar-2003','dd-mon-yyyy')) ,
5 PARTITION part2 VALUES LESS THAN (to_date('14-mar-2003','dd-mon-yyyy')) ,
6 PARTITION junk VALUES LESS THAN (MAXVALUE)
7 )
8 COMPRESS
9 as
10 select * from t;
Table created.
Thanks!!!
kpanchan, February 05, 2007 - 1:12 pm UTC
Tom
Thanks very much for your quick response.
Adding a column to a table
Sourabh, August 28, 2007 - 8:45 am UTC
Hi Tom,
I have a scenario where i need to add a column to a fact table which has more than 2000 million records.
I performed a small calculation for 1 million records.
Records : 1000000
Time taken : 70 seconds
If i have to perform on 2000 million records
Records : 2000 * 1000000
Time taken : 2000 * 70 => 140000 sec => 2333 minutes => 38 hours
What according to you would be the fastest method to do it?
Regards
September 04, 2007 - 1:38 pm UTC
big_table%ORA10GR2> select count(*) from big_table;
COUNT(*)
----------
25000000
big_table%ORA10GR2> set timing on
big_table%ORA10GR2> alter table big_table add x number;
Table altered.
Elapsed: 00:00:00.06
big_table%ORA10GR2>
it should be instantaneous - if not, you must be using a "default" value in which case you can:
a) add column without default
b) alter table t modify newcol default <value>; -- for new inserts
c) update it where it is null (this will still permit concurrent inserts into the table, but of course - the update will prevent updates and deletes to the existing rows)
d) commit;
Alexander, April 24, 2008 - 4:38 am UTC
Hi, Tom!
I tried to follow your steps, but I've got this error:
SQL> CREATE TABLE t AS SELECT * FROM all_objects;
Table created.
SQL> SELECT COUNT(1) AS cnt FROM t;
CNT
----------
40779
SQL> DROP TABLE t;
Table dropped.
SQL> CREATE TABLE t COMPRESS AS SELECT * FROM all_objects;
Table created.
SQL> SELECT COUNT(1) AS cnt FROM t;
CNT
----------
40779
SQL> ALTER TABLE t ADD (v VARCHAR2 (30));
Table altered.
SQL> ALTER TABLE t SET UNUSED (v);
Table altered.
SQL> ALTER TABLE t DROP UNUSED COLUMNS;
ALTER TABLE t DROP UNUSED COLUMNS
*
ERROR at line 1:
ORA-12996: cannot drop system-generated virtual column
SQL> SELECT * FROM v$version WHERE ROWNUM = 1;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - Prod
Could you explain, why this error is raised?
Thank you!
April 28, 2008 - 11:21 am UTC
looks like they withdrew that for 10g, but it is in 11g
ops$tkyte%ORA11GR1> CREATE TABLE t COMPRESS AS SELECT * FROM all_users;
Table created.
ops$tkyte%ORA11GR1> ALTER TABLE t ADD (v VARCHAR2 (30));
Table altered.
ops$tkyte%ORA11GR1> ALTER TABLE t SET UNUSED (v);
Table altered.
ops$tkyte%ORA11GR1> ALTER TABLE t DROP unused columns;
Table altered.
ops$tkyte%ORA11GR1> SELECT * FROM v$version WHERE ROWNUM = 1;
BANNER
-------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
it is sort of "not necessary" of course in this case - in fact, I'd say dropping a column from a compressed table probably should be done via 'alter table t move' anyway (in order to, well, compress the data on the block again...)
DROP COLUMN DOES NOT WORK ON TABLE WITH FEW COMPRESSED PARTITIONS AND FEW UNCOMPRESSED
jenith, August 27, 2009 - 9:46 am UTC
Hi Tom
I have scenario where we have table T1 with partition's P1,p2 compressed p3,p4 uncompressed in this case i am able to make column unused but alter table T1 drop unused columns; fail's
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
August 28, 2009 - 4:51 pm UTC
not until 11g with advanced compression option - this is true, but, if you have a compressed table (save space), dropping a column without a reorg (waste space) seems "not sensible"
just make it unused and if you want to reclaim the space - reorganize those segments, you should probably have just been using set unused from the get go in this case.
A reader, September 16, 2009 - 12:56 am UTC
Tom - in your Followup above;
"table compression works when you do direct path operations (insert append, direct path load, alter
table move... ) not during normal insert/update/delete."....
Does 11g "COMPRESS FOR ALL OPERATIONS" means it's not true?
September 16, 2009 - 10:06 am UTC
correct, 11g Release 1 introduced the advanced compression option which permits compression for inserts and updates using conventional path.
so, as with many things, it means "it is not true anymore"
A reader, September 16, 2009 - 11:01 am UTC
Hello tom,
Is there is any performance issue when doing indert/update/delete on compressed table
Thanks
September 16, 2009 - 4:43 pm UTC
well, there would be a couple of cases to be considered - lots of them actually
there is direct path compression and conventional path compression.
direct path:
o insert (not direct path insert) will not be affected
o delete will not be
o update might be. If you update compressed data, it'll likely decompress and migrate the row. If you update non-compressed data, no affect
conventional path:
o most inserts will not be impacted, only the insert that takes the block over "pctfree" and would normally take it off the freelist would. Instead of just taking it off freelist, it first compresses the block and if that freed enough space - it just inserts into the block. If that did not free enough space - the block is taken off the freelist. So, everynow and then and insert will "feel the pain"
o deletes should not be affected
o updates - see insert in this section. If the update would cause the block to exceed pctfree and be removed from the freelist, the compression is done first.
In general, compression negatively impacts loading - in the hopes of reducing storage needs and improving the speed of retrieval.
Useful Tips
Prasanna, September 30, 2009 - 2:14 am UTC
Thanks a lot
How compressed is a 'compressed' table?
Mike, November 09, 2009 - 2:55 pm UTC
> If you update compressed data, it'll likely decompress and migrate the row.
Is there any way to determine what % of blocks are actually compressed, in a table or partition that has compression enabled?
(short of forcibly moving it and seeing a change in the space used)
November 11, 2009 - 2:40 pm UTC
no, there is not.
well, not truly, you could do something like using dbms_rowid.rowid_block_number to get an ESTIMATE of the number of rows/block and then bin them up in some ranges to get an idea of how many blocks have 0..100 rows, 101..200 and so on.
The ones with "high rows/block" would likely be compressed data blocks
Not 100% accurate by any means, but a good guess.
In 11gr2 - there is a tool to analyze a table and estimate how well it would compress, that is new.
just to clarify
Jiri, November 14, 2009 - 3:36 pm UTC
reader asked "I wish Oracle adds column level compression soon. This would be very useful in Data Warehouse
environments where repeated code values (low cardinality columns) can be compressed in the block
header."
tom responded "we have had that since version 9ir2. It is called a compressed table. Any column, in fact any set of columns, that have repeated values are compressed."
I'm not sure if reader asked for this, but I don't think Oracle does true column level compression. Correct me if I'm wrong, my understanding is that Oracle does block compression only. Other systems like Teradata allow true column level compression (compression of a single column or even specific set of values in a single column) - this decreases compression level but can be faster in insert/delete/update operations.
nope
jiri, November 16, 2009 - 9:55 pm UTC
nope, I'm talking about classic relational database compression here
Teradata has column level compression (you can compress individual columns)
http://www.teradataforum.com/l020829a.htm here is sample teradata DDL
CREATE TABLE Properties (
Address VARCHAR(40),
City CHAR(20) COMPRESS (‘Chicago’),
StateCode CHAR(2)
);
November 23, 2009 - 12:39 pm UTC
... Customers using Teradata compression in V2R4 have experienced up to 50% capacity savings and scan performance increases up to 35%....
we meet or exceed that with block level compression. We have columnar compression (exadata version 2.0) and block level compression (since 9iR2) - and it meets or exceeds that savings...
... In Teradata V2R4, one value in each column can be compressed out of the row body....
that doesn't seem to generally useful, unless you have a column with one value that is very very very wide and repeats a heck of a lot.
but their statements about block level compression - are not really true. If they were - I'd expect that they'd have numbers somewhere demonstrating them.
come on
Jiri, November 28, 2009 - 10:50 am UTC
With all the respect, you are really not being professional here. I don't want to argue about oracle vs any other database and compare compression methods, but ...
first you said that oracle had column level compression since 9R2, when I corrected it, you said that I really don't know what I'm talking about by saying "actually, I think you are speaking of columnar compression ala sybase IQ, vertica - but not teradata", when I corrected that, you threw comment like this?
Is this really Tom who is responding to these discussions? I'm simply surprised by kinda rude childish responses with no "thank you", no "you are correct", "I am sorry" ... but hey I have no clue what I'm talking about, I'm just OCP, MSDBA, MCSE and Teradata Certified Professional.
Is this enough information about field compression in Teradata?
http://www.teradata.com/t/WorkArea/DownloadAsset.aspx?id=1432
November 28, 2009 - 4:07 pm UTC
It sounded like you were talking columnar compression to me, especially what the reader wrote - the original poster.
And if you slow down and read what I wrote it is:
we meet or exceed that with block level compression. We have columnar compression (exadata version 2.0) and block level compression (since 9iR2) - and it meets or exceeds that savings...
where did I say "first you said that oracle had column level compression since 9R2,"
And your ordering of the timeline is quite strange.
You say "first you said" - however, I wrote that AFTER you said column compression.
Then you said I said "I don't know what your talking about" - the only way you get that order is if you read the page from the bottom up.
You wrote "column compression - like teradata" (and remember, I know nothing about you, your background, your level of experience with Oracle, teradata, anything - you know about me - I know *nothing* about you. without references (links, context, something) I have to guess many times at what people are referring to and the levels of people that come here range from - well, the entire spectrum is represented)
I wrote "I think it was columnar compression like Sybase IQ, Vertica, and Exadata" (given that this is what the industry has been working on for a while, this is where the real compression comes from )
You wrote "No, this <link to tersdata, which I read>"
And I wrote "Ok, we meet or best those numbers with block compression - it doesn't see to be worth it, we would achieve at least that level with our block compression" and "exadata goes a step further" - so I don't see your point, it doesn't seem to me to have any advantages over what we already had, what we've had for many releases.
Yes, this is Tom
And so what about teradata, I've already said we meet or beat that in ever case? Can you tell us mathematically how this is not true?
True, I misunderstood what you meant when you said column compression - but only because the columnar compression is what really achieves massive compression and the column compression that teradata has there, frankly, doesn't seem to be very impressive.
Maybe I'm missing something, feel free to point it out.
Very Strange - works in 10.2.0.3 as well as 11.1.0.6 but not in 11.1.0.7
Devanshi Parikh, December 09, 2009 - 12:06 pm UTC
ops$tkyte%ORA11GR1> CREATE TABLE t COMPRESS AS SELECT * FROM all_users;
Table created.
ops$tkyte%ORA11GR1> ALTER TABLE t ADD (v VARCHAR2 (30));
Table altered.
ops$tkyte%ORA11GR1> ALTER TABLE t SET UNUSED (v);
Table altered.
ops$tkyte%ORA11GR1> ALTER TABLE t DROP unused columns;
Table altered.
ops$tkyte%ORA11GR1> SELECT * FROM v$version WHERE ROWNUM = 1;
BANNER
-------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
Tried this same sequence on my 11.1.0.7 database. Here are the results.
SQL> drop table t;
Table dropped.
SQL> CREATE TABLE t COMPRESS AS SELECT * FROM all_users;
Table created.
SQL> ALTER TABLE t ADD (v VARCHAR2 (30));
Table altered.
SQL> ALTER TABLE t SET UNUSED (v);
Table altered.SQL> ALTER TABLE t DROP unused columns;
ALTER TABLE t DROP unused columns
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
SQL> SELECT * FROM v$version WHERE ROWNUM =1;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
So, seems like this way of modifying a compressed table is not consistent across 11gR1 releases.
December 10, 2009 - 2:32 pm UTC
that is correct, this ability is part of the OLTP table compression - sorry, they fixed it in 11gR1, it would be:
ops$tkyte%ORA11GR1> CREATE TABLE t COMPRESS for all operations AS SELECT * FROM all_users;
Table created.
ops$tkyte%ORA11GR1> ALTER TABLE t ADD (v VARCHAR2 (30));
Table altered.
ops$tkyte%ORA11GR1> ALTER TABLE t SET UNUSED (v);
Table altered.
ops$tkyte%ORA11GR1> ALTER TABLE t DROP unused columns;
Table altered.
ops$tkyte%ORA11GR1> SELECT * FROM v$version WHERE ROWNUM = 1;
BANNER
-------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - Production
ORA-12296
MM, June 08, 2010 - 6:57 am UTC
Tom,
I have a partitioned table and when I try to drop the unused columns I am getting ORA-12996: cannot drop system-generated virtual column. My oracle version 10g Enterprise 10.1.0.2.0
How can the unused column be dropped?
Thanks
June 09, 2010 - 8:49 am UTC
give example.
example
MM, June 09, 2010 - 9:12 am UTC
It is the same one as the post on April 24th 2008 above.
sql>select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.1.0.2.0 - Prod
PL/SQL Release 10.1.0.2.0 - Production
CORE 10.1.0.2.0 Production
TNS for 32-bit Windows: Version 10.1.0.2.0 - Production
NLSRTL Version 10.1.0.2.0 - Production
sql>create table my_objs compress as select * from dba_objects;
Table created.
sql>alter table my_objs set unused column status;
Table altered.
sql>alter table my_objs drop unused columns;
alter table my_objs drop unused columns
*
ERROR at line 1:
ORA-12996: cannot drop system-generated virtual column
I am getting the same error in the partitioned table too. Is there any other way to drop the unused column.
Thanks
June 10, 2010 - 11:58 am UTC
I would need the step by steps to reproduce that exact error.
A reader, June 10, 2010 - 8:22 am UTC
The reason is that your db is 10g R1.
See the copy from Tom's 1st response 3 years ago.
ops$tkyte%ORA10GR2> alter table t drop column x;
alter table t drop column x
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
but make it "disappear"
ops$tkyte%ORA10GR2> alter table t set unused column x;
Table altered.
yes, which if you ask me is OK since you would have to rewrite the entire segment to
truly get rid of the data anyway (and recompress it). So follow that with:
ops$tkyte%ORA10GR2> alter table t drop unused columns;
Table altered.
Example
MM, June 10, 2010 - 1:49 pm UTC
Tom,
I have given the script of exactly what I did. I tried the same in release 2. I am having the same issue unable to drop the unused columns. Here it is.
SQL>select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for 64-bit Windows: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
SQL>create table my_objs compress as select * from dba_objects;
Table created.
SQL>alter table my_objs set unused column status;
Table altered.
SQL>alter table my_objs drop unused columns;
alter table my_objs drop unused columns
*
ERROR at line 1:
ORA-12996: cannot drop system-generated virtual column
However, I am not able to recreate the issue with a partitioned table! But, I still have the issue with my existing partitioned table.
Interestingly enough, when I tried to create the table first and then insert values (instead of creating and inserting at the same time) I am not getting the issue.
SQL> create table my_ob compress as select * from all_objects where 1=0;
Table created.
SQL>insert into my_ob select * from all_objects;
49286 rows created.
SQL>
SQL>commit;
Commit complete.
SQL>alter table my_ob set unused column status;
Table altered.
SQL>
SQL>alter table my_ob drop unused columns;
Table altered.
I am not sure if there is a solution for this. But,thanks for your time.
June 11, 2010 - 6:52 am UTC
I saw this:
... I am getting the same error in the partitioned table too. ...
and looked at the example and said to myself "hmm, no partitioning - partitioning question - missing information". In other words, the red herring you threw in there confused me.
It is the compress.
ops$tkyte%ORA10GR2> create table t compress as select * from all_objects where rownum=1;
Table created.
ops$tkyte%ORA10GR2> alter table t set unused column status;
Table altered.
ops$tkyte%ORA10GR2> alter table t drop unused columns;
alter table t drop unused columns
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
the error is wrong in your older release, but the cause is the same:
$ oerr ora 39726
39726, 00000, "unsupported add/drop column operation on compressed tables"
// *Cause: An unsupported add/drop column operation for compressed table
// was attemped.
// *Action: When adding a column, do not specify a default value.
// DROP column is only supported in the form of SET UNUSED column
// (meta-data drop column).
Also, if your goal is to COMPRESS, dropping a column doesn't make sense - setting unused is as good as you get.
Since you do not insert and reuse space in a compressed table like that - you don't need to drop the column.
If you want to reclaim the space, you'd have to REORGANIZE the object, just alter table move it.
Error Not consistent
MM, June 11, 2010 - 8:18 am UTC
Tom,
The error is not consistent. Here is the second example in my previous post, where I create the compressed table and then populate it with data, then I can drop the unused columns without any errors.
SQL> create table my_ob compress as select * from all_objects where 1=0;
Table created.
SQL>insert into my_ob select * from all_objects;
49286 rows created.
SQL>
SQL>commit;
Commit complete.
SQL>alter table my_ob set unused column status;
Table altered.
SQL>
SQL>alter table my_ob drop unused columns;
Table altered.
Either I should be able to drop the columns from a compressed table all the time or not drop the columns at all. Bug?!!
Thanks
June 22, 2010 - 6:36 am UTC
it is pretty consistent for me.
ops$tkyte%ORA10GR2> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - Prod
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for Linux: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production
ops$tkyte%ORA10GR2> create table my_ob compress as select * from all_objects where 1=0;
Table created.
ops$tkyte%ORA10GR2> insert into my_ob select * from all_objects;
50080 rows created.
ops$tkyte%ORA10GR2> commit;
Commit complete.
ops$tkyte%ORA10GR2> alter table my_ob set unused column status;
Table altered.
ops$tkyte%ORA10GR2> alter table my_ob drop unused columns;
alter table my_ob drop unused columns
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
every single time. If you can reproduce your issue, please utilize support.
But again, it doesn't really matter, if you went out of your way to compress a table your goal must be to minimize space - hence you would be doing a full reorganization - not a drop column - in order to repack the compressed data on blocks.
Add column
TB, September 09, 2013 - 12:19 pm UTC
Hi Tom,
There are some restriction when adding a column to a compressed table:
Adding and Dropping Columns in Compressed Tables
The following restrictions apply when adding columns to compressed tables:
■ Basic compression—You cannot specify a default value for an added column.
■ OLTP compression—If a default value is specified for an added column, then the
column must be NOT NULL. Added nullable columns with default values are not
supported.
I use basic compression. Is there any trick you can suggest to add a column with default value (and not null claues for fast update)?
Thanks
September 10, 2013 - 9:42 am UTC
you would want to create table new as select ...., 'x' x from old;
alter x to be default 'x'
drop old
rename new
think about it, for basic compression which ONLY works during direct path operations - if we added the column to the compressed table - every row would have to be uncompressed, migrated to a new block, have 'x' added to it, and then stored uncompressed. You'd end up with an uncompressed table with every row migrated and lots of apparently empty blocks where the compressed data used to be.
you just want to do a direct path operation here - create table new as select from old.
question on licence
A reader, February 22, 2017 - 1:55 pm UTC
hi
some of owr database have no "Advanced compression" licence.
so to frop unused column on a table having the compress BASIC,
is it permitted to do :
alter table t compress for all operations;
alter table t drop unused columns;
alter table t compress basic;
?
February 23, 2017 - 2:45 am UTC
I'm not sure, but I would not drop unused columns like that anyway (assuming your table is large).
I would do:
create table new_copy compress as select ...
A 'drop unused' is a very expensive operation.
Follow up
A reader, February 23, 2017 - 6:06 am UTC
I've experienced some issues in 11g that exchange partition will fail even when setting unused cols.
Is that still true sometimes and when?
February 25, 2017 - 12:26 am UTC
adding the column with Default and non null clause
Rajeshwaran Jeyabal, January 09, 2023 - 8:30 am UTC
When we add a new column with a default value as “literal” it works. But not with “function” calls, why so ?
demo@ATP19C> create table t
2 COMPRESS
3 as
4 select * from all_objects
5 where rownum <=10;
Table created.
demo@ATP19C> alter table t add X number default 55 not null;
Table altered.
demo@ATP19C> alter table t add Y timestamp default systimestamp not null;
alter table t add Y timestamp default systimestamp not null
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
January 16, 2023 - 3:21 am UTC
I suspect that is a limitation that will be lifted
19c
====
SQL> create table t
2 COMPRESS
3 as
4 select * from all_objects
5 where rownum <=10;
Table created.
SQL>
SQL> alter table t add X number default 55 not null;
Table altered.
SQL>
SQL> alter table t add Y timestamp default systimestamp not null;
alter table t add Y timestamp default systimestamp not null
*
ERROR at line 1:
ORA-39726: unsupported add/drop column operation on compressed tables
21c
=======
SQL> create table t
2 COMPRESS
3 as
4 select * from all_objects
5 where rownum <=10;
Table created.
SQL>
SQL> alter table t add X number default 55 not null;
Table altered.
SQL>
SQL> alter table t add Y timestamp default systimestamp not null;
Table altered.