You are on page 1of 4

Dropping a Column from a Table Administration Tips

Dropping a Column from a Table

Dropping a column directly can only be done in 8i or above (see below for a workaround in
earlier versions). The basic command is:

ALTER TABLE BLAH DROP COLUMN BLAHCOL;

That command is a piece of DDL -so there's an implied commit after it, and its effects
cannot therefore be reversed. It will cause a complete read of the referenced table, with
each row having the offending piece of data physically removed from it, before being
written back to disk. It's therefore going to cause a significant performance hit on your
database as it runs (all that I/O being performed), and is likely to take an age to complete
if the table is reasonably large. On the plus side, you are actually physically removing data
from the table, so when the whole thing's finished, the table really will be smaller than it
was originally.

Unfortunately, dropping a column from a large table generates a lot of redo (the before
image of the column being dropped, and the after image of, practically, nothing)... and
potentially, you could have an Instance crash in the middle of the operation. Instance
Recoveries require all redo to be re-performed after the time of the last checkpoint -so if
you're generating stacks of redo during a 'drop column' operation, there could be a
significant Instance Recovery awaiting you.

To minimise that danger, the drop column syntax allows you to request additional
checkpoints after every so-many rows. For example:

ALTER TABLE BLAH DROP COLUMN BLAHCOL CHECKPOINT 1000;

...Now, after processing every 1000 rows, a checkpoint will be issued, thus keeping
potential Instance Recoveries down to something manageable.

Another thing to watch out for: You can't drop a column that is used as the parent of a
foreign key relationship. Doing so would create orphan records, and that's not allowed.
However, you can use this syntax:

ALTER TABLE BLAH DROP COLUMN BLAHCOL CHECKPOINT 1000 CASCADE CONSTRAINTS;

...and that will drop the foreign key constraints for you, and thereby allow the now-
standalone column to be dropped without further protest. (You can use the 'cascade
constraints' clause without the 'checkpoint' clause, of course, and vice versa).

Notice that in all these examples, the command is "drop column" -in the singular. You
cannot drop more than one column at a time using this syntax. That's extremely
unfortunate, because it means that the second and third (and so on) drop column

Copyright © Howard Rogers 2001 10/17/2001 Page 1 of 4


Dropping a Column from a Table Administration Tips

statements will have to completely re-perform the full table scan that the first one
occasioned. You could therefore expect to be there until Christmas waiting for the thing
to finish.

Fortunately, but slightly confusingly, you could issue the following command to achieve a
multi-column drop in one pass:

ALTER TABLE BLAH DROP (BLAHCOL, BLAHCOL2, BLAHCOL3);

Notice that the keyword "column" is missing from this syntax. However, you can add in the
'cascade constraints' or the 'checkpoint X' clauses, as before.

In all these cases, data is physically removed from the table -and that's a relatively
expensive operation. This is not the sort of command you'd want to let loose on a big
table during the middle of a busy day -your Users will almost certainly notice the massive
slow-down in database performance. Fortunately, there is a cheaper alternative:

ALTER TABLE BLAH SET UNUSED COLUMN BLAHCOL;

This simply marks a column as being unusable in the data dictionary. Again, there is a
multi-column variant:

ALTER TABLE BLAH SET UNUSED (BLAHCOL1, BLAHCOL2);

...which sets 2 columns unused with one command (and again, confusingly, misses out the
"column" keyword).

The only effect of the command is to make a small change to the data dictionary, and
therefore, however enormous the table you are altering might be, the command completes
in about a second. No full table scans are performed, no massive reading and writing from
disk thus ensues, and the whole thing is over before you know it. Since the data is not
physically removed, though, don't expect to free up any space by performing such an
operation. That comes later!

Setting a column unused is also a piece of DDL -so it is just as irreversible as physically
dropping it. And no, there is not a 'set used' command to reverse it, either. As soon as the
command is issued, all subsequent selects on that table will not be able to read the data in
that column (even though, physically, it's still there in all the rows). Nor will any User be
able to insert values into that column. It is as good as non-existent.

Just as with actually dropping the column, therefore, you can't 'set unused' a column which
is the parent in a foreign key relationship -unless you use the 'cascade constraints' variant:

ALTER TABLE BLAH SET UNUSED COLUMN BLAHCOL CASCADE CONSTRAINTS;

Copyright © Howard Rogers 2001 10/17/2001 Page 2 of 4


Dropping a Column from a Table Administration Tips

Now the real neat trick comes with the following command:

ALTER TABLE BLAH DROP UNUSED COLUMNS;

What this does is to now physically remove from the table all columns which have been
previously marked as unused, in one pass of the table. It's just as expensive as a single
drop column would be, because it's genuinely having to read all rows, remove the affected
column data, and write it back to disk. But since it's removing all unused columns in one
pass, it is no more expensive than a single column drop would be.

The trick to dropping multiple columns as cheaply as possible, therefore is to mark them
all unused first (and performance won't be affected at all, so you can do that at any time
of the day). Then, at some unearthly hour when no-one will be affected by a sudden surge
in I/O activity, run a single 'drop unused columns' job.

Incidentally, just as when you dropped a single column you were able to induce additional
checkpoints to minimise a subsequent Instance Recovery, so you can with the 'drop unused'
command:

ALTER TABLE BLAH DROP UNUSED COLUMNS CHECKPOINT 1000;

There is no 'cascade constraints' clause, though -since those were dropped when you set
the column to be unused in the first place.

Versions of Oracle before 8i

Since there was no 'drop column' command in 8.0 or 7.x, you have to use the CTAS (Create
Table ... As Select...) command to achieve something similar:

CREATE TABLE NEWBLAH (COL1, COL2, COL3)


AS SELECT COL1,COL2,COL4 FROM OLDBLAH;

That example creates a new 3-column table, grabbing the information out of the old table
-but skipping the old table's third column. Notice that you don't define data types for the
new table's columns (you'll get an error if you try) -the types are going to be determined by
whatever data types the relevant columns in the original table happen to be.

Having achieved the extraction of the right columns, you'll probably want to perform the
following three actions:

DROP TABLE OLDBLAH;

Copyright © Howard Rogers 2001 10/17/2001 Page 3 of 4


Dropping a Column from a Table Administration Tips

CREATE TABLE OLDBLAH AS SELECT * FROM NEWBLAH;


DROP TABLE NEWBLAH

That gets us back to having what is effectively a brand new table, but with exactly the
same name as the original.

So the end result can be achieved, but it's not exactly cheap: dropping the "oldblah" table
after the first CTAS means Users can't access the data until the entire process (and the
second CTAS to get the old name back again) has completed. And all the usual caveats
about CTAS apply, too: no constraints, apart from NOT NULLS, come along for the ride, so
they have to be re-defined. No indexes come along for the ride, so they need to be re-
created from scratch. And no permissions go along for the ride, either, so they all have to
be re-granted (even when, at the end of the entire process, the net effect is that the table
name hasn't changed).

Copyright © Howard Rogers 2001 10/17/2001 Page 4 of 4

You might also like