دیتابیس اوراکل

یک سری جداول وجود دارند که لازم است پارتیشن های آنها به صورت دوره ای پاک شوند. مثلا یک policy میگذاریم که اگر از ایجاد هر پارتیشن 4 ماه گذشته باشد، آن پارتیشن drop شود. با استفاده از مراحل زیر میتوان این کار را انجام داد:


1- یک جدول بنام list_drop_part ایجاد میکنیم و لیست جداولی که قرار است پارتیشن های آنها drop شود و همچنین policy که برای drop شدن پارتیشن ها وجود دارد را به آن جدول اضافه میکنیم.

create table c##usr1.list_drop_part

( tab_own  varchar2(128 byte),

 tab_name varchar2(128 byte),

 interval number) ;


نکته1) برای هر جدول جدید، اگر لازم است پارتیشن های آن drop شود باید نام آن به list_drop_part اضافه شود.


2- یک جدول با نام result_drop_part ایجاد میکنیم که اطلاعات پارتیشن های drop شده در آن ریخته میشود.


create table c##usr1.result_drop_part

( tab_own    varchar2(128 byte),

  tab_name   varchar2(128 byte),

  part_name  varchar2(128 byte),

  high_value date,

  exec_date  date);



3- با استفاده از پکیج زیر میتوانیم پارتیشن های جداولی را که به list_drop_part اضافه شده اند ، بر اساس policyهای معین شده حذف نماییم.

drop_partition_pkg


نکته2) برای اجرای پکیج بالا باید grantهای زیر به کاربر c##usr1 داده شود.

grant drop any table to c##usr1 container=all;

grant select on dba_tab_partitions to c##usr1 container=all;


    4- میتوانیم یک job ایجاد کنیم که به صورت دوره ای اجرا شود. این job برای پاک کردن پارتیشن ها لازم است یکی از پروسیجرهای drop_partition_pkg را به صورت زیر فراخوانی کند.


execute c##usr1.drop_partition_pkg.drop_spec_part_prc;


  • راهله شاکری

بعضی وقتها شرایطی پیش میاد که میخواهیم فقط یک یا چند PDB خاص را با استفاده از بکاپی که از آنها داریم بازیابی کنیم. مثلا PDB حذف شده است یا اینکه PDB1 وجود دارد و میخواهیم بکاپی از PDB1 را که مربوط به گذشته است ، با یک نام دیگر بازیابی و اطلاعاتی را از آن بدست آوریم.


1- در ابتدا باید یک auxiliary instance ایجاد کنیم. که این کار را میتوانیم روی همان سرور یا سرور دیگری انجام دهیم.

--Create password file for auxiliary instance

$ cd $ORACLE_HOME/dbs

$ orapwd file=orapwtest password=m#12345678 entries=5

 

--Create init file for auxiliary instance

$ vi inittest.ora


نکته 1) برای ایجاد کردن init file میتوانید از روی spfile دیتابیس source یک  pfile ایجاد کنید و بعد از ایجاد تغییرات لازم از آن به عنوان init file برای  auxiliary instance استفاده کنید.

 

2- در مرحله بعدی باید auxiliary instance را nomount کنید.


$ export ORACLE_SID=TEST 

$ echo $ORACLE_SID

$ sqlplus / as sysdba

SQL> startup nomount pfile=/u01/app/oracle/product/12.2.0/db_1/dbs/inittest.ora;

 

3- در این مرحله با استفاده از دستور RMAN duplicate میتوانیم PDB مورد نظر را بازیابی نماییم.


$ rman auxiliary sys/m#12345678

RMAN> duplicate database to 'TEST' pluggable database PDB1

2> UNTIL TIME "TO_DATE ('15-10-2018 04:40:00','dd-mm-yyyy hh24:mi:ss')"

3> backup location '/home/oracle/back/';


نکته 2) باید بکاپ تمام  archiveهایی که میخواهیم recover کنیم در مسیر بکاپ ها موجود باشد.

 

4-  بعد میتوانیم با استفاده از دستورات زیر PDB1 را از root container auxiliary instance جدا کنیم و به root container که میخواهیم متصل نماییم.


--auxiliary instance

SQL> alter pluggable database PDB1 close immediate;

SQL> alter pluggable database PDB1 unplug into '/home/oracle/pdb1.pdb';

 

--target database

SQL> create pluggable database PDB1 as clone using '/home/oracle/pdb1.pdb';

SQL> alter pluggable database PDB1 open;



Attachments

RMAN Log Output from the DUPLICATE Process

  • راهله شاکری

در موارد مختلفی شاید نیاز داشته باشیم که یک PDB را از یک root container جدا و آن را به یک root container دیگر متصل کنیم.


  • راهله شاکری
timezone یک agent بر اساس timezone سیستم عامل ست میشود، اگر timezone یک سیستم عامل را تغییر دهید برای تغییر agent timezone میتوانید بر اساس روش زیر عمل کنید:
emctl stop agent
emctl resetTZ agent

وقتی این دستور را اجرا میکنید خروجی آن به شکل زیر است :
Oracle Enterprise Manager Cloud Control 13c Release 2  
Copyright (c) 1996, 2016 Oracle Corporation.  All rights reserved.
Updating /u01/app/oracle/product/13.2.0/agent/agent_inst/sysman/config/emd.properties...
Successfully updated /u01/app/oracle/product/13.2.0/agent/agent_inst/sysman/config/emd.properties.
Login as the em repository user and run the  script:
exec mgmt_target.set_agent_tzrgn('tstdb-tst-loc-loc:3872','GMT')
and commit the changes
This can be done for example by logging into sqlplus and doing
SQL> exec mgmt_target.set_agent_tzrgn('tstdb-tst-loc-loc:3872','GMT')
SQL> commit

بعد باید به sysman متصل شوید و دستوراتی را که در بالا به آن اشاره شده است اجرا کنید:
sqlplus sysman/pass
SQL> exec mgmt_target.set_agent_tzrgn('tstdb-tst-loc-loc:3872','GMT');
SQL> commit;

برای اینکه از تغییر timezone مطمئن شوید ، میتوانید کوئری زیر را اجرا کنید:
SQL> select target_name, timezone_region from sysman.mgmt_targets where TARGET_NAME='tstdb-tst-loc-loc';

بعد از انجام این مراحل مجددا agent را start کنید.
emctl start agent


  • راهله شاکری
موقع mount کردن دیتابیس با خطای زیر مواجه شدم :

: Errors in file /u01/app/oracle/diag/rdbms/migdb/migdb/trace/migdb_rvwr_24962.trc
ORA-00600: internal error code, arguments: [krfrFix-2], [0], [2], [], [], [], [], [], [], [], [], []
2018-09-29T06:09:18.809390+00:00
.WARNING: Cannot open the flashback thread for this instance due to the above error

که توی documentها نوشته شده بود دیتابیس را به حالت mount ببرید و flashabck را off کنید، بعد دیتابیس را open کنید. ولی چون دیتابیس ما کلا موقع mount شدن با خطای بالا روبرو میشد. من راه حل زیر را انجام دادم:

;SQL> alter system reset db_recovery_file_dest
;SQL> alter database mount
;SQL> alter database flashback off
;'SQL> alter system set db_recovery_file_dest='/shst/rdb-tst
;SQL> alter database open
;SQL> alter database flashback on



  • راهله شاکری

اگر بخواهیم یک اسکریپت خاص را در چند اسکیما اجرا کنیم ، راه حل های زیر وجود دارد ( البته به جز این موارد ممکن است راه حل های دیگری هم وجود داشته باشد ) :

1- به تک تک آن اسکیماها وصل شده و اسکریپت مورد نظر را اجرا کنیم.

2- به یک اسکیمای خاص وصل شده و با دستور alter session set current_schema=X ،  اسکیمای خود را تغییر دهیم و اسکریپت مورد نظر را اجرا کنیم.

3- راه حل سوم استفاده از پکیج DBMS_SYS_SQL است. کاربرد این پکیج شبیه DBMS_SQL است با این تفاوت که یک کارکرد اضافه تر با نام "parse as user"  دارد که به شما اجازه میدهد یک SQL خاص را برای دیگر اسکیماها در دیتابیس اجرا کنید.

فقط قبل از اجرا باید به دو نکته خیلی خیلی مهم توجه کنید :

- این پکیج در اوراکل جزو undocumented packageها به حساب می آید و اوراکل به صورت internally برای سرویس های خود از آن استفاده میکند. و برای استفاده در خارج از اوراکل در نظر گرفته نشده است.

- این پکیج بسیار پکیج قدرتمندی است ، زیرا هر دستوری را با آن میتوان اجرا کرد ، به همین دلیل باید شدیدا این موضوع تحت کنترل قرار گیرد که این پکیج توسط چه user قرار است اجرا شود.

با در نظر گرفتن نکات بالا من یک مثال از نحوه استفاده از این پکیج را در زیر شرح داده ام :


1-Create User

create user TEST identified by TEST quota unlimited on USERS;

grant connect,create procedure,select on dba_users to TEST;

grant execute on sys.dbms_sys_sql to TEST;

 

create user C identified by C quota unlimited on USERS;

grant CONNECT,CREATE TABLE to C;

 

create user D identified by D quota unlimited on USERS;

grant CONNECT,CREATE TABLE to D;

 

2-Create Procedure In TEST User

create or replace procedure execute_script_prc(v_script in varchar2) as

  l_cursors dbms_sql.number_table;

  l_result  number;

begin

 for cur in (select user_id 

                from dba_users 

               where username in ('C','D')) loop

  --parse the cursor only if we haven't already

  if (not l_cursors.exists(cur.user_id)) then

    l_cursors(cur.user_id) := sys.dbms_sys_sql.open_cursor;

    --parsing anonymous pl/sql block

    sys.dbms_sys_sql.parse_as_user(

    c => l_cursors(cur.user_id), 

    statement => v_script, 

    language_flag => dbms_sql.native,

    userid => cur.user_id);

  end if;

 --execute script

 l_result := sys.dbms_sys_sql.execute(l_cursors(cur.user_id));

 end loop;

end execute_script_prc;

 

3-Execute script on C,D schemas

--Create table T1 in C,D schemas

exec test.execute_script_prc('create table T1 ( id number )');

--Insert to table T1 in C,D schemas

exec test.execute_script_prc('begin insert into T1 values(1); commit; end;');



  • منبع

  • راهله شاکری

اگر بخواهیم پسورد یک user را که در دیتابیس دیگری قرار دارد با استفاده از database link تغییر دهیم ، میتوانیم از پروسیجر زیر برای انجام این کار استفاده کنیم.


create or replace procedure change_pass_prc authid current_user as

begin

  cursor usr_cur is

    select username from dba_users@pass_link;

  begin

    for usr_rec in usr_cur loop

      if usr_rec.username = 'USR1' then

        declare

          job binary_integer;

        begin

          dbms_job.submit@pass_link(job,'begin execute immediate ''alter user ' || usr_rec.username ||

                                                             ' identified by "USR1" ''; end;');

          commit;

        end;

        dbms_output.put_line(usr_rec.username || ' password changed.');

      end if;

    end loop; 

  when

  exception when others then 

     raise_application_error(-20000,sqlerrm);

end change_pass_prc;



  • راهله شاکری

امروز وقتی خواستم به یک restore point که قبلا ایجاد کرده بودم flashback کنم به خطای زیر برخورد کردم :

 ORA-38729 signalled during: flashback pluggable database PDB_RDB1 to restore point RESTORE_POINT_PDB_RDB1_20180617125947

 

بعد وقتی چک کردم دیدم flashback database به صورت اتوماتیک غیرفعال شده است :

SQL> select flashback_on from v$database

FLASHBACK_ON

------------------

NO

بعد از گشتن در docها مختلف متوجه شدم که اگر اوراکل برای نوشتن flashback logها در مسیر FRA به مشکل I/O برخورد کند ، برای جلوگیری از hang کردن دیتابیس ، flashback را به صورت اتوماتیک disable میکند :

:If no guaranteed restore points are defined, then the instance remains unaffected when RVWR encounters I/O errors. Note the following cases

·      On a primary database, Oracle Database automatically disables Flashback Database while the database is open. All existing transactions and queries proceed unaffected. This behavior is expected for both single-instance and Oracle RAC databases


خطایی که موقع disable کردن flashback در alert log  نوشته شده بود به صورت زیر است :

ORA-38886: WARNING: Flashback database was disabled due to error when writing flashback database logs.

ORA-38701: Flashback database log 10 seq 12 thread 1: "/shst/fra/flashback/o1_mf_fjpbmf8r_.flb"

ORA-27072: File I/O error

 

· منابع 

https://docs.oracle.com/database/121/BRADV/flashdb.htm#BRADV601

https://jhdba.wordpress.com/2010/01/06/flashback-disabled-automatically-a-minor-rant

https://easyoradba.com/2010/05/20/ora-38701-flashback-database-log-seq-thread

 

  • راهله شاکری

flashback_pkg

۲۰
خرداد

من قصد دارم یک پکیج بنویسم که با اون بشه کارهای مختلف در رابطه با flashback رو انجام داد، به مرور زمان سعی میکنم این پکیج را کامل میکنم.

این اسکریپت در حال حاضر کارهای زیر را انجام میدهد:

1- ایجاد کردن restore point برای تمامی PDBهای یک root container

set serveroutput on; 

exec userA.create_restore_point_for_all_pdb_prc;


2- ایجاد کردن restore point برای یک PDB خاص

set serveroutput on; 

exec userA.flashback_pkg.create_restore_point_for_spec_pdb_prc('PDB_NAME');


3- انجام flashback در سطح PDB

set serveroutput on;

exec userA.flashback_pkg.flashback_pdb_prc('PDB_NAME','RESTORE_POINT_NAME');


4- بدست آوردن زمان flashback retention

select userA.flashback_pkg.get_flashback_retention_prc from dual;


flashback_pkg script


  • راهله شاکری

در دیتابیس 12c ، اگر هنگام flashback  در یک PDB به یک restore point که قبلا ایجاد شده است به error زیر برخورد کردید :

ERROR at line 1:

ORA-38754: FLASHBACK DATABASE not started; required redo log is not available

ORA-38762: redo logs needed for SCN 1251365490 to SCN 1251403027

ORA-38761: redo log sequence 905 in thread 1, incarnation 1 could not be accessed

 

به این دلیل است که log archiveهایی که برای ریکاور کردن احتیاج دارد در مسیر FRA پیدا نمیکند. برای حل این مشکل باید ابتدا اگر بکاپی از آرشیوها دارید restore نمایید و مجددا flashback  را انجام دهید.

rman target /

RMAN> restore archivelog from sequence 904 ;

SQL> alter pluggable database PDB1 close immediate;

SQL> flashback pluggable database PDB1 to restore point PDB1_20180214;

SQL> alter pluggable database PDB1 open resetlogs;

  • راهله شاکری