UNUSED COLUMNS и дисковое пространство

Источник: oracle

На написание этого небольшого материала автора подтолкнул очередной вопрос разработчиков о том, каково влияние операции 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.


Страница сайта http://185.71.96.61
Оригинал находится по адресу http://185.71.96.61/home.asp?artId=24055