بروزرسانی Materialized Viewهای حجیم آن هم به صورت complete می تواند DBA را در جنبه های مختلفی به چالش بکشاند به ویژه آنکه دیتابیس در مود آرشیو قرار داشته باشد چرا که در این صورت، بروزرسانی MV منجر به ایجاد حجم زیادی از آرشیولاگ خواهد شد. البته اثرات منفی این مسئله، صرفا به فضای مصرفی redoها خلاصه نمی شود و از لحاظ پرفورمنسی هم می تواند بر روی عملکرد دیتابیس اثر منفی بگذارد.
در این متن بررسی می کنیم که غیرفعال کردن Logging در سطوح object، tablespace و database چه اثراتی را بر روی عملیات ساخت و بروزرسانی Materialized Viewها به همراه خواهد داشت(مطالعه مطلب “تاثیر عملیات NOLOGGING در دیتاگارد” پیشنهاد می شود).
قبل از ورود به بحث اصلی این متن، مثالی را از نحوه تاثیر غیرفعال کردن logging برای یک جدول را مشاهده خواهید کرد.
در مثال زیر می بینید که با غیرفعال کردن logging برای جدول T1 و tablespaceای که این جدول در آن قرار دارد و همچنین دیتابیس! دو حالت زیر قابل تصور است:
SQL> select force_logging from v$database; FORCE_LOGGING -------------- NO SQL> select t.logging,t.force_logging from dba_tablespaces t where t.tablespace_name='TBS1'; LOGGING FORCE_LOGGING --------- ------------- NOLOGGING NO SQL> select logging from user_tables p where table_name='T1'; LOGGING ------- NO
*درج به صورت conventional insert که سبب ایجاد redo خواهد شد:
SQL> insert into t1 select * from sys.source$; 13756 rows inserted SQL> SELECT s.name, m.value FROM v$mystat m, v$statname s WHERE m.statistic# = s.statistic# AND s.name ='redo size'; NAME VALUE ----------- ---------- redo size 2,493,140
*درج بصورت Direct-Path INSERT که در شرایط ذکر شده مانع از ایجاد redo خواهد شد:
SQL> insert /*+append*/ into t1 select * from sys.source$; 13756 rows inserted SQL> SELECT s.name, m.value FROM v$mystat m, v$statname s WHERE m.statistic# = s.statistic# AND s.name ='redo size'; NAME VALUE ---------- ---------- redo size 1,676
ساخت Materialized View
همانطور که می دانید ما به ازای هر Materialized View یک جدول هم ایجاد می شود و در هنگام ساخت Materialized View و یا حتی بعد از ایجاد آن، می توان در مورد خصیصه logging این جدول اعمال نظر کرد:
SQL> create materialized view mv_nolog 2 NOLOGGING 3 BUILD IMMEDIATE 4 REFRESH COMPLETE 5 ON DEMAND 6 AS 7 select a.* from tbl1 a, tbl2 b where a.obj#=b.obj#; Materialized view created
SQL> select logging,tablespace_name from user_tables p where table_name='MV_NOLOG'; LOGGING TABLESPACE_NAME ------- --------------- NO TBS1
SQL> alter table MV_NOLOG logging; Table altered
SQL> select logging,tablespace_name from user_tables p where table_name='MV_NOLOG'; LOGGING TABLESPACE_NAME ------- --------------- YES TBS1
نکته مهم در این زمینه آن است که خصیصه logging در زمان ایجاد materialized view در حجم redo ایجاد شده و زمان ساخت آن اثرگذار خواهد بود:
SQL> create materialized view mv_nolog 2 LOGGING 3 tablespace tbs1 4 BUILD IMMEDIATE 5 REFRESH COMPLETE 6 ON DEMAND 7 AS 8 select a.* from tbl1 a, tbl2 b where a.obj#=b.obj#; Materialized view created Executed in 18.996 seconds
SQL> SELECT s.name, m.value FROM v$mystat m, v$statname s WHERE m.statistic# = s.statistic# AND s.name ='redo size'; NAME VALUE ----------- ---------- redo size 1,111,003,940
حجم archivelog ایجاد شده برای mv_nolog، برابر با 1.1GB خواهد بود:
[root@stb ~]# cd /oracle/arch [root@stb arch]# du -sh . 1.1G
در صورت استفاده از عبارت nologging در زمان ساخت MV و همچنین قرار دادن tablespace در حالت nologging، مسئله متفاوت خواهد بود:
SQL> select force_logging from v$database; FORCE_LOGGING --------------------------------------- NO SQL> alter tablespace tbs1 nologging; Tablespace altered SQL> select t.logging,t.force_logging from dba_tablespaces t where t.tablespace_name='TBS1'; LOGGING FORCE_LOGGING --------- ------------- NOLOGGING NO
SQL> create materialized view mv_nolog 2 NOLOGGING 3 BUILD IMMEDIATE 4 REFRESH COMPLETE 5 ON DEMAND 6 AS 7 select a.* from tbl1 a, tbl2 b where a.obj#=b.obj#; Materialized view created Executed in 8.763 seconds
SQL> SELECT s.name, m.value FROM v$mystat m, v$statname s WHERE m.statistic# = s.statistic# AND s.name ='redo size'; NAME VALUE ---------- ---------- redo size 687,548
همانطور که می بینید، علاوه بر کاهش حجم redo ایجاد شده، سرعت ایجاد mv هم بسیار افزایش پیدا کرده است.
بروزرسانی Materialized View
در زمان بروزرسانی به روش معمول، خصیصه nologging در هیچ سطحی در نظر گرفته نمی شود:
SQL> select force_logging from v$database; NO SQL> select logging from user_tables p where table_name=’MV_NOLOG’; NO select t.logging,t.force_logging from dba_tablespaces t where t.tablespace_name=’TBS1’ NOLOGGING NO
SQL> exec DBMS_MVIEW.REFRESH(LIST => ‘MV_NOLOG’,METHOD => ‘C’); PL/SQL procedure successfully completed Executed in 97.135 seconds
SQL> SELECT s.name, m.value FROM v$mystat m, v$statname s WHERE m.statistic# = s.statistic# AND s.name =’redo size’; NAME VALUE ----------- ---------- redo size 2,199,307,708
همانطور که می بینید، حجم redo ایجاد شده، حدودا دوبرابر شده است، چرا که عملیات بروزرسانی علاوه بر دستور insert، شامل دستور delete هم می باشد.
البته بروزرسانی به روش non-atomic refresh سبب استفاده از truncate به جای delete خواهد شد و از طرفی دیگر، در صورت تنظیم خصیصه nologging از Direct-Path INSERT استفاده خواهد شد که در نتیجه کاهش حجم redo ایجاد شده را در پی خواهد داشت:
SQL> / FORCE_LOGGING_DATABASE LOGGING_TBS LOGGING_MV ------------------------- ----------- ---------- NO NOLOGGING NO
SQL> EXEC DBMS_MVIEW.REFRESH('MV_NOLOG', method => 'C', atomic_refresh => FALSE); PL/SQL procedure successfully completed Executed in 11.12 seconds
SQL> SELECT s.name, m.value FROM v$mystat m, v$statname s WHERE m.statistic# = s.statistic# AND s.name ='redo size'; NAME VALUE ---------- ---------- redo size 1,043,244
حجم redo ایجاد شده از 2,199,307,708 به 1,043,244 رسیده است.
ایراد این روش در آن است که MV به صورت موقت از دسترسی خارج خواهد شد.
به عنوان گزینه دیگر می توان از بروزرسانی به روش out of place استفاده کرد استفاده از این روش سبب خواهد شد تا جدول جدیدی برای mv ایجاد شود و پس از ایجاد جدول جدید، جدول قدیمی متعلق به mv حذف شود. در شرایطی که خصیصه nologging تنظیم شده باشد، ایجاد redo به حداقل ممکن خواهد رسید:
SQL> / FORCE_LOGGING_DATABASE LOGGING_TBS LOGGING_MV ------------------------- ----------- ---------- NO NOLOGGING NO
SQL> EXEC DBMS_MVIEW.REFRESH('MV_NOLOG', method => 'C', atomic_refresh => FALSE, out_of_place => TRUE); PL/SQL procedure successfully completed Executed in 13.447 seconds
SQL> SELECT s.name, m.value FROM v$mystat m, v$statname s WHERE m.statistic# = s.statistic# AND s.name ='redo size'; NAME VALUE ------------ ---------- redo size 939,044
البته پارامتر out_of_place محدودیتهای زیادی را هم به همراه دارد که قبل از برنامه ریزی برای استفاده از آن، بهتر است از محدودیتهای آن مطلع باشیم.
توجه: در روش out of place باید به اندازه دو mv فضای آزاد موجود باشد.