زمانی که دستور drop column را اجرا می کنیم، اوراکل باید تمامی بلاکهای جدول را به حافظه منتقل کرده و اطلاعات مربوط به ستون را از همه رکوردهای حاضر در بلاک حذف کند.
در کنار عملیات I/O و پردازش رکورد، جدول هم به صورت exclusive قفل خواهد شد و مضاف بر آن، حدف ستون منجر به ایجاد redo و undo هم می شود. در نتیجه حذف ستون از یک جدول حجیم می تواند کار بسیار پرهزینه و زمانبری باشد.مثال زیر را ببینید:
–تعداد بلاکهای جدول:
SQL> select blocks,bytes from dba_segments where segment_name=’MYTBL’;
BLOCKS BYTES
———- ———-
34816 285212672
–تعداد بلاکهای جدول در buffer cache قبل از انجام عملیات drop column:
SQL> select count(distinct l.BLOCK#) from v$bh l where objd=(select l.object_id from dba_objects l where l.object_name=’MYTBL’);
COUNT(DISTINCTL.BLOCK#)
———-
0
–حذف فیزیکی ستون c1 از جدول MYTBL:
SQL> alter table MYTBL drop column c1 ;
Table altered
Executed in 45.906 seconds
–تعداد بلاکهای جدول در buffer cache بعد از انجام عملیات drop column:
SQL> select count(distinct l.BLOCK#) from v$bh l where objd=(select l.object_id from dba_objects l where l.object_name=’MYTBL’);
COUNT(DISTINCTL.BLOCK#)
———————–
34184
به این شیوه از حذف ستون، حذف فیزیکی گفته می شود. با بازنگری تعداد بلاکها و حجم جدول MYTBL خواهیم دید که حذف ستون منجر به کم شدن فضای تخصیص داده شده به جدول نمی شود:
SQL> select blocks,bytes from dba_segments where segment_name=’MYTBL’;
BLOCKS BYTES
———- ———-
34816 285212672
و برای برگرداندن فضای خالی، باید جدول بازسازی شود:
SQL> alter table MYTBL move parallel 10;
Table altered
SQL> select blocks,bytes from dba_segments where segment_name=’MYTBL’;
BLOCKS BYTES
———- ———-
25032 205062144
همانطور که ملاحظه شد، حذف ستون c1 از جدول MYTBL حدودا 45 ثانیه زمان برده است که این زمان برای جداول حجیم می تواند بسیار طولانی تر شود.
حجم redo و undo تولید شده را هم با کمک پرس و جوی زیر می بینیم:
SQL> select name, round(value / 1024 / 1024) “SIZE_MB”
from v$mystat, v$statname
where v$mystat.statistic# = v$statname.statistic#
and (v$statname.name = ‘redo size’ or
v$statname.name = ‘undo change vector size’);
NAME SIZE_MB
———————————- —————
redo size 2170
undo change vector size 756
توجه: با پرس و جوی زیر می توان حجم Active undo را زیر نظر داشت کرد:
select tablespace_name, status, sum(blocks) * 8192/1024/1024 MB from dba_undo_extents group by tablespace_name, status;
پیشرفت اجرای دستور drop column را می توان با دستور زیر نظارت کرد:
SQL> select sofar,totalwork, round(sofar/totalwork*100) “% Complete” from v$session_longops p where target=’USEF.MYTBL’;
SOFAR TOTALWORK % Complete
———- ———- ———-
13144 33947 39
حذف منطقی ستون
اوراکل از نسخه 8i برای این مسئله راهکار دیگری ارائه داده است که ان هم حذف منطقی ستون، قبل از حذف فیزیکی آن می باشد. با کمک این قابلیت می توان، ستون را به unused علامت زده و عملیات حذف فیزیکی را در زمانی خارج از پیک کاری دیتابیس انجام داد.
با این کار ستون حذف شده از دید کاربر مخفی خواهد ماند و تمامی ایندکسها و محدودیتهای ایجاد شده بر روی این ستون هم حذف خواهند شد و حتی می توان ستون جدیدی با این نام برای جدول ایجاد کرد:
SQL> select count(distinct l.BLOCK#) from v$bh l where objd=(select l.object_id from dba_objects l where l.object_name=‘MYTBL’);
COUNT(*)
———-
0
SQL> create index dfgdf on MYTBL (c1);
Index created
SQL> select count(*) from user_indexes where table_name=’MYTBL’;
COUNT(*)
———-
1
SQL> alter table usef.MYTBL Set Unused(c1);
Table altered
Executed in 0.083 seconds
SQL> select count(*) from user_indexes where table_name=’MYTBL’;
COUNT(*)
———-
0
SQL> desc MYTBL
Name Type Nullable Default Comments
—- ———– ——– ——- ——–
C3 VARCHAR2(7) Y
SQL> select count(distinct l.BLOCK#) from v$bh l where objd=(select l.object_id from dba_objects l where l.object_name=’MYTBL’);
COUNT(DISTINCT L.BLOCK#)
———————–
239
توجه! دستور alter table set unused قابلیت برگشت پذیری ندارد!!!
لیست جداولی که ستونی از آنها صرفا به صورت منطقی حذف شده را می توان از طریق ویوی DBA_UNUSED_COL_TABS و DBA_PARTIAL_DROP_TABS مشاهده کرد:
SQL> SELECT * FROM DBA_UNUSED_COL_TABS;
OWNER TABLE_NA COUNT
—– ——– ———-
USEF MYTBL 1
در نهایت برای حذف فیزیکی این ستون می توان(در زمانی خارج از پیک کاری سیستم) دستور زیر را اجرا کرد:
SQL> alter table MYTBL drop unused columns;
Table altered
Executed in 55.936 seconds
SQL> SELECT * FROM DBA_UNUSED_COL_TABS;
no rows selected
همانطور که می بینید، حذف فیزیکی این ستون، حدودا به 50 ثانیه زمان نیاز دارد.
مشاهده جزییات بیشتری از وضعیت بلاک بعد از حذف منطقی ستون
در ادامه با مشاهده محتویات بلاکهای جدول خواهیم دید که اطلاعات ستونها کماکان در بلاکهای جدول موجود هستند:
SQL> alter table MYTBL Set Unused(c3);
Table altered
Executed in 0.02 seconds
SQL> alter table MYTBL Set Unused(c2);
Table altered
Executed in 0.02 seconds
SQL> SELECT * FROM DBA_UNUSED_COL_TABS;
OWNER TABLE_NA COUNT
—– ——– ———-
USEF MYTBL 2
SQL> select column_name,
data_type,
column_id,
hidden_column,
segment_column_id seg_cid,
internal_column_id internal_cid
from dba_tab_cols
where owner = ‘USEF’
and table_name = ‘MYTBL’;
SQL> select dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block#,c3 from MYTBL where rownum<=1;
FILE# BLOCK# C3
———- ———- ——-
2 130331 ONLINE
SQL> alter system dump datafile 2 block 130331;
System altered
SQL> SELECT p.tracefile FROM v$session s JOIN v$process p ON s.paddr = p.addr WHERE s.sid =(SELECT sid FROM v$mystat WHERE ROWNUM = 1);
TRACEFILE
————————————————————–
/oracle19c/base/diag/rdbms/oracledb/oracledb/trace/oracledb_ora_23630.trc
با مشاهده محتویات فایل تریس، اطلاعات ستونهای در حالت Unused هم قابل مشاهده هستند:
block_row_dump:
tab 0, row 0, @0x1f68
tl: 24 fb: –H-FL– lb: 0x0 cc: 3
col 0: [ 6] 4f 4e 4c 49 4e 45
col 1: [ 6] 4f 4e 4c 49 4e 45
col 2: [ 6] 4f 4e 4c 49 4e 45
tab 0, row 1, @0x1f50
tl: 24 fb: –H-FL– lb: 0x0 cc: 3
col 0: [ 6] 4f 4e 4c 49 4e 45
col 1: [ 6] 4f 4e 4c 49 4e 45
col 2: [ 6] 4f 4e 4c 49 4e 45
tab 0, row 2, @0x1f38
tl: 24 fb: –H-FL– lb: 0x0 cc: 3
col 0: [ 6] 4f 4e 4c 49 4e 45
col 1: [ 6] 4f 4e 4c 49 4e 45
col 2: [ 6] 4f 4e 4c 49 4e 45
ستونهای UNUSED را حذف می کنیم:
SQL> alter table MYTBL drop unused columns;
Table altered
اطلاعات بلاک را بازبینی می کنیم:
SQL> alter system dump datafile 2 block 130331;
System altered
محتویات بلاک:
block_row_dump:
tab 0, row 0, @0x1f68
tl: 10 fb: –H-FL– lb: 0x2 cc: 1
col 0: [ 6] 4f 4e 4c 49 4e 45
tab 0, row 1, @0x1f50
tl: 10 fb: –H-FL– lb: 0x2 cc: 1
col 0: [ 6] 4f 4e 4c 49 4e 45
tab 0, row 2, @0x1f38
tl: 10 fb: –H-FL– lb: 0x2 cc: 1
col 0: [ 6] 4f 4e 4c 49 4e 45
نکته: استفاده از ویژگی alter table set unused با محدودیتهای روبرو می باشد برای مثال، نمی توان ستونی که جزیی از partition key هست را حذف کرد.
استفاده از عبارت checkpoint
در زمان حذف فیزیکی ستونی که در حالت UNUSED قرار دارد، ممکن است sessionای که دستور را اجرا کرده به دلایلی چون کرش کردن دیتابیس، kill شود در این صورت نیاز است تا عملیات drop column مجددا اجرا شود.
در کنار این خطر احتمالی، حذف فیزیکی یک ستون می تواند منجر به افزایش ACTIVE undo و متعاقب آن، سرریز شدن فضای undo tablespace شود.
به این جهت اوراکل عبارت checkpoint n را به دستور alter table .. drop unused columns اضافه کرد که با پردازش هر n رکورد توسط دستور drop column، عملیات انجام شده، commit خواهد شد.
با هر بار انجام commit توسط دستور، ACTIVE undo به UNEXPIRE undo تغییر خواهد کرد در نتیجه حجم کلی ACTIVE undo از حد مشخصی بیشتر نخواهد شد.
بنابرین عدد تعیین شده برای عبارت checkpoint، تعداد رکوردها را مشخص خواهد کرد که این کار می تواند مدت زمان انجام عملیات حذف را بسیار افزایش دهد:
SQL> alter table usef.MYTBL Set Unused(c1);
Table altered
Executed in 0.02 seconds
SQL> alter table MYTBL drop unused columns Checkpoint 250;
Table altered
Executed in 65.147 seconds
همانطور که می بینید، زمان حذف از 45 ثانیه به 65 ثانیه رسیده است.
توجه: در صورت استفاده از عبارت checkpoint، پیشرفت عملیات drop column در ویوی v$session_longops نمایش داده نخواهد شد.
DROP COLUMNS CONTINUE
اگر دستور drop column Checkpoint به هر دلیلی با خطا متوقف شود، اجرای دستورات DDLای و DMLای با خطا مواجه خواهد شد(به جز TRUNCATE TABLE) و عملا جدول در وضعیت unusable قرار خواهد گرفت:
SQL> alter table MYTBL drop unused columns Checkpoint 250;
ORA-01013: user requested cancel of current operation
SQL> delete MYTBL where rownum<=1;
ORA-12986: columns in partially dropped state. Submit ALTER TABLE DROP COLUMNS CONTINUE
SQL> select count(*) from MYTBL;
ORA-12986: columns in partially dropped state. Submit ALTER TABLE DROP COLUMNS CONTINUE
در این صورت، تنها راهکار، اجرای دستور ALTER TABLE DROP COLUMNS CONTINUE خواهد بود:
SQL> ALTER TABLE MYTBL DROP COLUMNS CONTINUE;
Table altered
SQL> delete MYTBL where rownum<=1;
1 row deleted
#در حاشیه
———————————————————————————————————-
نامرئی کردن یک ستون از جدول
با invisible کردن یک ستون هم می توان آن ستون را از دید کاربران و برنامه مخفی نگه داشت با این تفاوت که این تغییر قابل برگشت خواهد بود:
SQL> ALTER TABLE MYTBL MODIFY c1 INVISIBLE;
Table altered
SQL> desc MYTBL;
Name Type Nullable Default Comments
—- ———– ——– ——- ——–
C2 VARCHAR2(7) Y
C3 VARCHAR2(7) Y
C1 VARCHAR2(7) Y
SQL> select * from MYTBL where rownum<=1;
C2 C3
——- ——-
ONLINE ONLINE
SQL> insert into MYTBL values(‘test’,’test’);
1 row inserted
برای برگرداندن این تغییر، کافیست دستور زیر را اجرا کنیم:
SQL> ALTER TABLE MYTBL MODIFY c1 VISIBLE;
Table altered
SQL> select * from MYTBL where rownum<=1;
C2 C3 C1
——- ——- ——-
ONLINE ONLINE ONLINE