На написание этого небольшого материала автора подтолкнул очередной вопрос разработчиков о том, каково влияние операции SET UNUSED COLUMN на последующий расход дискового пространства. Вопрос вовсе не праздный, если учесть современные объемы данных и время, потребное для их реорганизации. Поэтому автор решил продемонстрировать, а что же собственно происходит, когда выполняется операция SET UNUSED COLUMN.
Начнем с того, что весьма распространено заблуждение, гласящее, что unused column удаляется из словаря данных. Разумеется, это не так, и существуют представления ..._TAB_COLS, позволяющие увидеть, что происходит с полями, помеченными как UNUSED.
SQL> CREATE TABLE table1(x int primary key);
Table created.
SQL> CREATE TABLE table2(x int, y int default 0,
2 constraint y_c1 primary key(y),
3 constraint y_c2 foreign key(y) references table1(x),
4 constraint y_c3 check (y > 0));
Table created.
SQL> col data_default format a10
SQL> col nullable format a10
SQL> col column_name format a30
SQL> col hidden_column format a10
SQL> select column_name, data_default, nullable, hidden_column
2 from user_tab_cols where table_name = 'TABLE2';
COLUMN_NAME DATA_DEFAU NULLABLE HIDDEN_COL
------------------------------ ---------- ---------- ----------
X Y NO
Y 0 N NO
SQL> select constraint_name, constraint_type from user_constraints
2 where table_name = 'TABLE2';
CONSTRAINT_NAME C
------------------------------ -
Y_C3 C
Y_C1 P
Y_C2 R
SQL> alter table table2 set unused column y;
Table altered.
SQL> select column_name, data_default, nullable, hidden_column
2 from user_tab_cols where table_name = 'TABLE2';
COLUMN_NAME DATA_DEFAU NULLABLE HIDDEN_COL
------------------------------ ---------- ---------- ----------
X Y NO
SYS_C00002_09100918:16:50$ Y YES
SQL> select constraint_name, constraint_type from user_constraints
2 where table_name = 'TABLE2';
no rows selected
В-общем, этого можно было ожидать - Oracle переименовал колонку, присвоив ей сгенерированное системой имя, и - что существенно - отменил наложенное на нее ограничение NOT NULL и значение по умолчанию DEFAULT. Кроме того, исчезли все ограничения, связанные с этой колонкой - PRIMARY KEY, FOREIGN KEY и CHECK. Осталась скрытая от конечного пользователя колонка с системным именем, допускающая хранение NULL-величин и не имеющая значения по умолчанию. Логично предположить, что при операциях вставки это поле неявным образом будет учитываться при формировании физической записи внутри блока -несмотря на то, что разработчик более не имеет с ним дела явно. В противном случае Oracle потребовалось бы каким-то образом отличать "старые" записи - когда поле было еще "живым", от новых, когда поле уже "умерло". Этакий кот Шредингера внутри базы данных...
Давайте выполним несколько простых манипуляций и посмотрим на содержимое блока таблицы после их завершения.
SQL> CREATE TABLE T_EXP (x int, y varchar2(254))
2 /
Table created.
SQL> insert into T_EXP values(1,'a');
1 row created.
SQL> commit;
Commit complete.
SQL> alter table t_EXP set unused column y;
Table altered.
SQL> insert into T_EXP values(2);
1 row created.
SQL> commit;
Commit complete.
SQL> alter table t_exp add (y varchar2(255));
Table altered.
SQL> insert into T_EXP values(3,'b');
1 row created.
SQL> commit;
Commit complete.
SQL> select distinct dbms_rowid.rowid_relative_fno(rowid) "file",
2 dbms_rowid.rowid_block_number(rowid) "block"
3 from T_exp;
file block
---------- ----------
9 599
SQL> alter system dump datafile 9 block 599;
System altered.
Дамп блока содержит следующую информацию
tab 0, row 0, @0x1f90
tl: 8 fb: --H-FL-- lb: 0x0 cc: 2
col 0: [ 2] c1 02
col 1: [ 1] 61
tab 0, row 1, @0x1f8a
tl: 6 fb: --H-FL-- lb: 0x0 cc: 1
col 0: [ 2] c1 03
tab 0, row 2, @0x1f81
tl: 9 fb: --H-FL-- lb: 0x1 cc: 3
col 0: [ 2] c1 04
col 1: *NULL*
col 2: [ 1] 62
Итак, наши подозрения вполне подтвердились - поле, помеченное как unused ведет себя как самое обычное nullable - поле со значением по умолчанию NULL. И если это поле не является последним в словарном списке колонок таблицы (в соответствии со значением поля COLUMN_ID), то при внесении каждой новой записи или изменении старой оно будет добавлять 1 байт, содержащий значение 0xFF, к общему содержимому записи в блоке - при условии, если хотя бы одна колонка, следующая за ней, принимает значение, отличное от NULL.
Ссылки по теме