ฟังก์ชั่น LISTAGG() เป็นฟังก์ชั่นใหม่ในเวอร์ชั่น 11GR2 เพื่อเชื่อม multiple rows ให้เป็น single line
รูปแบบ syntax
LISTAGG( [,]) WITHIN GROUP (ORDER BY ) [OVER (PARTITION BY )]
ปล. สามารถใช้ในการ Analytic ได้เช่นใช้คำสั่ง OVER() clause
ตัวอย่างนี้จะดู username ใน dba_users โดยจะให้มันเชื่อมต่อกันเป็นบรรทัดเดียวและคั่นด้วยเครื่องหมาย ","
วันจันทร์ที่ 22 มิถุนายน พ.ศ. 2558
วันพฤหัสบดีที่ 11 มิถุนายน พ.ศ. 2558
Oracle 12c Multitenant practice
Oracle database 12c Multitenant คือฟีเจอร์ใหม่ที่ทำให้เราสามารถสร้างและจัดการฐานข้อมูลได้หลายตัวมากขึ้นไว้ในฐานข้อมูลใหญ่ตัวเดียวที่เรียกว่า Container Database (CDB) ซึ่งฐานข้อมูลหลายตัวเหล่านั้นเราเรียกว่า Pluggable Databases (PDB)
แต่ละ CDB ประกอบด้วย
- หนึ่ง Root Container ชื่อว่า CDB$ROOT เป็น Master set of data dictionary views ซึ่งมี metadata ที่เกี่ยวข้องกับ root container ตลอดจน pluggable databases ทุกตัวที่อยู่ใน CDB
- หนึ่ง Static seed container ชื่อว่า PDB$SEED โดย container ตัวนี้จะอยู่เป็นอิสระมีหน้าที่เป็นเพียง template เพื่อสร้าง data files และ metadata สำหรับ pluggable databases ตัวใหม่ๆที่จะสร้างขึ้นใน CDB
- Pluggable databases (0 - 252 ตัว) แต่ละ PDB จะจัดการข้อมูลและฟังก์ชั่นต่างๆในตัวเองคล้ายกับ non-CDB database และมันมี data files และ application objects (users , tables , indexes , อื่นๆ) เป็นของตัวเอง เมื่อเราเชื่อมต่อเข้าสู่ PDB ตัวหนึ่งเราจะมองไม่เห็น root container หรือ PDB ตัวอื่นๆ
Pluggable Database Architecture
สร้าง CDB
ถ้าเราจะใช้งาน PDB feature เราต้องสร้าง Database ให้เป็น Container database โดยมีหลายวิธีในการสร้างเช่น
- สร้างโดย SQL CREATE DATABASE command
- ใช้ DBCA
- Generate script จาก DBCA แล้วเอามารันเอง
- ใช้ RMAN เพื่อทำ Duplicate จาก CDB ที่มีอยู่แล้ว
โดยวิธีการสร้างเหล่านี้ขอไม่พูดถึง
ตรวจสอบ CDB ที่ถูกสร้างขึ้นมาแล้ว
- ใช้ sqlplus / as sysdba
- ตรวจสอบคอลัม name และ CDB ถ้าเป็น YES แสดงว่าถูกสร้างเป็น Container
SQL> select name,cdb from v$database;
NAME CDB
--------- ---
KITTICDB YES
- ตอนนี้เราจะมี 2 containers ใน CDB database ของเราก็คือ root กับ seed pluggable database เราสามารถเช็คด้วยการ query
SQL> select con_id,name from v$containers;
CON_ID NAME
---------- ------------------------------
1 CDB$ROOT
2 PDB$SEED
- เราจะมี data files ของทั้ง root และ seed database เราจะตรวจสอบ data files เหล่านั้นด้วย query
select con_id,file_name from cdb_data_files
order by con_id;
Note : ถ้าเราใช้เวอร์ชั่น 12.1.0.2 เราจะไม่เห็นข้อมูลของ seed เพราะมี undocument parameter ใหม่ตัวนึงชื่อว่า EXCLUDE_SEED_CDB_VIEW ค่า default เป็น true
แต่ในตัวอย่างปรับไว้เป็น false จึงทำให้เราเห็นข้อมูลใน seed database ด้วย
- ถ้าเรา query จาก dba_data_files เราจะเห็นแค่ไฟล์ของ database ที่เราใช้งานอยู่ในที่นี้คือ CDB$ROOT
FILE_NAME
---------------------------------------------------------------------
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_SYSTEM_BQHPTC9S_.DBF
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_SYSAUX_BQHPRMY9_.DBF
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_UNDOTBS1_BQHPWG1C_.DBF
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_USERS_BQHPWDRS_.DBF
เชื่อมต่อเข้าสู่ Root Container
เราสามารถเชื่อมต่อโดยเป็น sys as sysdba ได้เหมือนการเชื่อมต่อเข้าฐานข้อมูลแบบ non-CDB ทั่วๆไปเช่น
sqlplus / as sysdba
sqlplus sys@KITTICDB as sysdba
SQL> show user con_id con_name
USER is "SYS"
CON_ID
------------------------------
1
CON_NAME
------------------------------
CDB$ROOT
Start/Stop Root Container
เราสามารถ start/stop CDB ได้เหมือนกับ non-CDB ได้ตามปกติโดยต้องเข้ามาในสิทธิที่สามารถทำการเปิด/ปิด ฐานข้อมูลได้ เช่น
sqlplus / as sysdba
SQL*Plus: Release 12.1.0.2.0 Production on Thu Jun 11 10:37:09 2015
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to an idle instance.
SQL> startup
ORACLE instance started.
Total System Global Area 2583691264 bytes
Fixed Size 3048968 bytes
Variable Size 687868408 bytes
Database Buffers 1879048192 bytes
Redo Buffers 13725696 bytes
Database mounted.
Database opened.
เมื่อ CDB startup แล้วแต่ PDB ทุกตัวจะยังอยู่ในสถานะ Mount อยู่เราจะสั่งให้เปิดทุกตัว เช่น
SQL> alter pluggable database all open;
Pluggable database altered.
หากต้องการปิด PDB ทุกตัวก็สั่ง close โดยทุกตัวจะกลายเป็น Mount mode (ยกเว้น PDB$SEED จะอยู่สถานะ Read Only ตลอด)
SQL> alter pluggable database all close;
Pluggable database altered.
สร้าง PDB และเชื่อมต่อเข้าสู่ PDB
เราสามารถสร้าง PDB ใหม่ได้จาก
- PDB$SEED
- PDB ที่มีอยู่แล้ว
- non-CDB
- Unplugged PDB
1. ลอง Cloning จาก PDB$SEED
Login เข้าสู่ CDB แล้วใช้ SQL สร้าง PDB ขึ้นมาโดยใช้ PDB$SEED เป็น template
SQL> create pluggable database kittipdb1
2 admin user kittiadmin identified by kittiadmin
3 file_name_convert = ('E:\app\kitti_l\oradata\KITTICDB\pdbseed',
4 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB1');
Pluggable database created.
Note. ถ้าใช้ OMF ไม่ต้องใส่ file_name_convert เพราะ Oracle จะกำหนดชื่อและที่อยู่ของไฟล์ให้อัตโนมัติ ส่วน admin user คือ local user ที่มีสิทธิ์จัดการ PDB ได้และได้รับ PDB_DBA role
2. Clone จาก PDB ที่มีอยู่แล้ว
ทำการสร้าง KITTIPDB2 โดย Clone จาก KITTIPDB1
เราต้องปิด PDB ตัวที่เราจะ Clone แล้วเปิดใหม่เป็นแบบ Read Only
SQL> alter pluggable database KITTIPDB1 close;
Pluggable database altered.
SQL> alter pluggable database KITTIPDB1 open read only;
Pluggable database altered.
ทำการ Clone ด้วยคำสั่ง SQL
SQL> create pluggable database KITTIPDB2
2 from KITTIPDB1
3 file_name_convert = ('E:\app\kitti_l\oradata\KITTICDB\KITTIPDB1',
4 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB2')
5 storage (maxsize 4G max_shared_temp_size 80M);
Pluggable database created.
Note. storage clause ในที่นี้คือกำหนดขนาด PDB เต็มที่ไว้มากสุด 4G (maxsize) และ session ใน PDB นี้สามารถใช้ Shared Temporary Tablespace ได้มากสุด 80M (max_shared_temp_size)
3. Clone จาก non-CDB database
ใช้ได้หลายวิธีเช่น DBMS_PDB package , Data Pump(Transport Tablespace), GoldenGate
ในที่นี้จะใช้วิธี DBMS_PDB package แต่มีข้อแม้ว่า database ที่จะ Clone นี้ต้องเวอร์ชั่น 12c ขึ้นไป
เปิด non-CDB แบบ read only
SQL> alter database open read only;
Database altered.
หลังจากนั้นรัน DBMS_PDB เพื่อสร้าง XML file ที่มีโครงสร้างของ database อยู่
SQL> begin
2 dbms_pdb.describe(pdb_descr_file => 'E:\noncdb.xml');
3 end;
4 /
PL/SQL procedure successfully completed.
หลังจากไฟล์ XML ถูกสร้างแล้วให้ปิด non-CDB
SQL> shutdown immediate;
ปรับ ORACLE_SID ให้ชี้ไปที่ CDB database ที่เราจะ Clone non-CDB ไปและเข้า sys as sysdba
sqlplus / as sysdba
ตอนนี้เราอยู่ใน CDB database แล้วเราสามารถเช็คก่อนได้ว่า non-CDB ที่เราจะ Clone นั้น compatible กับ CDB database ของเราไหมด้วย DBMS_PDB.CHECK_PLUG_COMPATIBILITY
SQL> set serveroutput on
SQL> declare
2 hold_var boolean;
3 begin
4 hold_var := dbms_pdb.check_plug_compatibility(pdb_descr_file => 'E:\noncdb.xml');
5 if hold_var then
6 dbms_output.put_line('YES');
7 else
8 dbms_output.put_line('NO');
9 end if;
10 end;
11 /
YES
PL/SQL procedure successfully completed.
จากการทดสอบผลคือ YES แสดงว่าไม่มีปัญหาเกี่ยวกับ compatibility แต่ถ้าเป็น NO แสดงว่าอาจมีอะไรผิดพลาด เราสามารถดู PDB_PLUG_IN_VIOLATIONS view เพื่อดูรายละเอียดได้ว่าทำไมถึงไม่ compatibility
ต่อมาใช้คำสั่ง SQL เพื่อสร้าง PDB ขึ้นมาจาก non-CDB โดยเราต้องระบุชื่อและที่อยู่ของ XML file ของ non-CDB , ที่อยู่ของ non-CDB data files , และที่อยู่ใหม่ของ PDB
SQL> create pluggable database KITTIPDB2FROMnonCDB
2 using 'E:\noncdb.xml'
3 copy
4 file_name_convert = ('E:\app\kitti_l\oradata\KITTInonCDB',
5 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB3FROMnonCDB');
Pluggable database created.
เสร็จแล้วลองเชื่อมต่อเข้า PDB ใหม่
SQL> alter session set container=KITTIPDB2FROMnonCDB;
Session altered.
สุดท้ายรันสคริปต์นี้ก็เสร็จสมบูรณ์
@?\rdbms\admin\noncdb_to_pdb.sql
หลังจากนั้น database ควรจะสามารถเปิดขึ้นมาได้ตามปกติ
Unplugging a PDB
ก่อนที่เราจะเอา PDB ไปปลั๊กเข้ากับ CDB อื่นเราต้องทำการ Unplug มันออกจาก CDB ตัวเดิมเสียก่อน
เมื่อเรา Unplug ออกจาก CDB แล้วเราจะได้ XML file มาโดยไฟล์นี้จะเป็นข้อมูล metadata ของ PDB ตัวนั้นๆและสามารถนำไปใช้ Plug เข้าไปที่ CDB ตัวอื่นได้
ปิด PDB ตัวที่จะ Unplug ก่อน
สั่ง Unplug ด้วยคำสั่ง alter pluggable database ... unplug into '....xml';
SQL> alter pluggable database kittipdb2 unplug into 'E:\kittipdb2.xml';
Pluggable database altered.
Note. เมื่อ Unplugged PDB เสร็จแล้วเราต้อง Drop PDB ตัวนั้นก่อนที่จะทำการ Plug เข้ามาสู่ CDB ตัวเดิม (แต่ต้องใช้ keep datafiles option เพราะต้องใช้ data files เดิม)
SQL> drop pluggable database kittipdb2 keep datafiles;
Pluggable database dropped.
Note2. เราสามารถใช้ DBMS_PDB package เพื่อตรวจสอบ compatible ก่อนได้เหมือนกับการ Clone non-CDB to PDB ด้านบน
ในการ Plug เข้าไปใน CDB เราจะทำด้วย SQL statement CREATE PLUGGABLE DATABASE ... และใช้ 2 คำสั่งนี้ในการระบุข้อมูลลงไปคือ
USING clause : ใช้ในการระบุที่อยู่ของ XML file
COPY FILE_NAME_CONVERT clause : ใช้ในการกำหนดที่อยู่ data files ใหม่ในกรณีที่ path ไม่เป็นเหมือนเดิม
แต่ตอนนี้เราจะทำการ Plug เข้าสู่ CDB ตัวเดิมและใช้ data files location เดิมจึงสามารถใช้ NOCOPY clause ได้
SQL> create pluggable database kittipdb2
2 using 'E:\kittipdb2.xml'
3 nocopy;
Pluggable database created.
เมื่อ Plug เข้ามาแล้วก็เปิด database ได้ตามปกติ
SQL> alter pluggable database kittipdb2 open;
Pluggable database altered.
ลองเชื่อมต่อเข้าสู่ PDB ต่างๆ
วิธีแรกใช้ alter session
SQL> alter session set container=KITTIPDB2;
Session altered.
SQL> show con_name
CON_NAME
------------------------------
KITTIPDB2
วิธีที่สองเข้าผ่าน easy connect หรือ tnsnames
sqlplus sys/oracle@localhost:1521/KITTIPDB2 as sysdba
sqlplus sys/oracle@KITTIPDB2 as sysdba
เช็คสถานะของ PDB
ใช้คำสั่ง SQL ถ้าอยู่ที่ CDB จะเห็น PDB ทุกตัวแต่ถ้าอยู่ที่ PDB ตัวไหนจะเห็นแค่ตัวนั้น
SQL> select con_id,name,open_mode,restricted from v$pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 KITTIPDB2 READ WRITE NO
4 KITTIPDB1 READ WRITE NO
5 KITTIPDB2FROMNONCDB READ WRITE NO
ตรวจสอบว่า parameter ตัวไหนบ้างที่สามารถแก้ไขได้ในระดับ PDB
select name
from v$parameter
where ispdb_modifiable='TRUE'
order by name;
เปลี่ยนชื่อ PDB
เราสามารถเปลี่ยนชื่อ PDB ได้โดยทำการปิดแล้วเปิดใหม่เป็นโหมด restrict เสร็จแล้วสั่งเปลี่ยนชื่อด้วยคำสั่งเช่น
SQL> alter session set container=kittipdb2fromnoncdb;
Session altered.
SQL> shutdown immediate
Pluggable Database closed.
SQL> startup restrict;
Pluggable Database opened.
SQL> alter pluggable database KITTIPDB2FROMnonCDB rename global_name to KITTIPDB3;
Pluggable database altered.
Common Users
มี User 2 ประเภทที่ใช้ใน Pluggable database environment คือ local user กับ common user
local user คือ user ปกติที่ใช้ใน PDB โดยการจัดการจะเหมือนระบบ non-CDB ทั่วๆไป
และ common user เมื่อสร้างเสร็จจะอยู่ใน root container และทุก pluggable database ตลอดจน pluggable database ที่ถูกสร้างขึ้นในอนาคตอีกด้วย
Note. SYS กับ SYSTEM คือ common users ที่ Oracle สร้างให้โดยอัตโนมัติใน Pluggable environment
Common user จะถูกสร้างโดยใช้ C## หรือ c## นำหน้าชื่อ เช่น
sqlplus / as sysdba
SQL> create user c##kitti identified by kitti;
User created.
Common user จะมีสิทธิ์ต่างๆกับไหน PDB ได้ต้องถูก grant จากใน PDB นั้นเท่านั้น ถ้าเราต้องการ grant ให้มีสิทธิ์กับทุกๆ PDB เราต้องสร้าง Common Role แล้ว grant ให้ common user
Common Roles
จะคล้ายกับการสร้าง Common user ที่จะอยู่ในทุก PDB ใน Root container นั้นตลอดจน PDB ที่ถูกสร้างขึ้นในอนาคต และเหมือนกับกับ Common user อีกก็คือ Common role ต้องสร้างด้วย C## หรือ c## นำหน้า ตัวอย่างเช่น
sqlplus / as sysdba
SQL> create role c##dbaprivs container=all;
Role created.
ต่อมาเราสามารถกำหนดสิทธิ์ต่างๆให้กับ common role นี้ได้ เช่น
SQL> grant dba to c##dbaprivs container=all;
Grant succeeded.
เท่านี้ role นี้ก็จะมีสิทธิ์ dba (มาจาก dba role) ที่สามารถใช้งานได้ทุก PDB ต่อมาเราก็จะ grant role นี้ให้กับ common user
SQL> grant c##dbaprivs to c##kitti container=all;
Grant succeeded.
ตอนนี้ c##kitti ก็สามารถจัดการฐานข้อมูลด้วยสิทธิ์ c##dbaprivs(from dba role) ได้ทุก PDB แล้ว
RMAN Backup and Recovery
ในขณะที่เราเชื่อมต่อกับ CDB(Root contaner) เราสามารถ backup ได้ทุก data file ใน database หรือแค่ root container data files , a specific pluggable database , specific tablespaces or data files , or a combination of these
แต่ในขณะที่เราเชื่อมต่อกับ PDB เราจะสามารถ backup ได้แค่ data files ของ PDB ที่เราเชื่อมต่ออยู่
While Connected to the Root container
เช็คก่อนว่าเราเชื่อมต่อไปที่ Root container หรือยัง
RMAN> SELECT SYS_CONTEXT('USERENV', 'CON_ID') AS con_id,
2> SYS_CONTEXT('USERENV', 'CON_NAME') AS cur_container,
3> SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') AS cur_user
4> FROM DUAL;
using target database control file instead of recovery catalog
CON_ID CUR_CONTAINER CUR_USER
---------------------------- ---------------------------- ----------------------------
1 CDB$ROOT SYS
ลอง backup ทุก data file ทั้ง root container database และ pluggable database ในนั้น
RMAN> backup database;
ถ้าเราอยาก backup เฉพาะของ root container ให้ใส่ "root"
RMAN> backup database root;
เราสามารถ backup เฉพาะ PDB ที่เราต้องการได้เช่นกัน
RMAN> backup pluggable database kittipdb1;
และเราก็ backup แบบเจาะจง tablespace ใน PDB ที่เราต้องการได้ด้วย
RMAN> backup tablespace kittipdb1:system,sysaux;
สุดท้ายนี้เราสามารถ backup data file ของ root container database หรือ pluggable database โดยการใส่พาธและชื่อลงไปได้เลย
RMAN> backup datafile 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB2\SYSTEM01.DBF';
While Connected to a Pluggable database
เราสามารถเชื่อมต่อเข้า PDB ได้เลยจาก RMAN เช่น
rman target sys/oracle@KITTIPDB1
หลังจากเชื่อมต่อเข้ามาแล้วเราสามารถ backup ได้เฉพาะ data file ของ PDB นั้น ดังนั้นเมื่อเราสั่ง
RMAN> backup database;
จะเป็นการ backup เพียงแค่ทุก data file ของ PDB นั้นๆ
หรือ
RMAN> backup tablespace system;
ก็เป็นการ backup system tablespace's data file ของ PDB นั้นๆ เช่นกัน
Complete Recovery
การกู้ทั้ง CDB จะคล้ายกับการกู้ non-CDB แต่มันจะกู้ PDB ที่เกี่ยวข้องมาด้วย
RMAN> run {
2> shutdown immediate; #or abort if failed
3> startup mount;
4> restore database;
5> recover database;
6> alter database open;
7> }
Root Container Complete Recovery
จะให้ผลลัพธ์เหมือนกับการกู้ทั้ง CDB
RMAN> run {
2> shutdown immediate; #or abort if failed
3> startup mount;
4> restore database root;
5> recover database root;
6> alter database open;
7> }
Pluggable Database Complete Recovery
มี 2 วิธีคือ
1.เชื่อมต่ออยู่กับ CDB เราสามารถเลือก PDB ที่จะกู้ได้เลย
RMAN> run {
2> alter pluggable database kittipdb1,kittipdb2 close;
3> restore pluggable database kittipdb1,kittipdb2;
4> recover pluggable database kittipdb1,kittipdb2;
5> alter pluggable database kittipdb1,kittipdb2 open;
6> }
2.ถ้าเชื่อมต่อกับ PDB ก็จะกู้ได้เฉพาะ PDB นั้น
RMAN> run {
2> shutdown immediate;
3> restore database;
4> recover database;
5> startup;
6> }
CDB Point In Time Recovery
จะเหมือนกับของ non-CDB แค่เพิ่มเติมคือเราได้ทำ PITR ทุก PDB ไปด้วย
RMAN> run {
2> shutdown immediate; #or abort if failed
3> startup mount;
4> restore database;
5> recover database until time "to_date('16/06/2015 17:00','DD/MM/YYYY HH24:M
I')";
6> alter database open resetlogs;
7> }
PDB Point In Time Recovery
ทำคล้ายกับ Complete ตรงที่สามารถกู้ PDB กี่ตัวก็ได้ถ้าเราเชื่อมต่ออยู่ที่ Root Container
แต่ถ้าเชื่อมต่ออยู่ที่ PDB ไหนก็จะกู้ได้เฉพาะ PDB นั้น
RMAN> run {
2> alter pluggable database kittipdb1,kittipdb2 close;
3> restore pluggable database kittipdb1,kittipdb2;
4> recover pluggable database kittipdb1,kittipdb2 until time "to_date('16/06/2015 17:00','DD/MM/YYYY HH24:M
I')";
5> alter pluggable database kittipdb1,kittipdb2 open resetlogs;
6> }
Note. กรณีนี้ Resetlogs option จะไม่ได้ทำอะไรกับ Redo log file แต่แค่สร้าง DB incarnation ใหม่
ศึกษามาจากหนังสือ e-book : Pro Oracle Database 12c Administration, 2nd Edition
แต่ละ CDB ประกอบด้วย
- หนึ่ง Root Container ชื่อว่า CDB$ROOT เป็น Master set of data dictionary views ซึ่งมี metadata ที่เกี่ยวข้องกับ root container ตลอดจน pluggable databases ทุกตัวที่อยู่ใน CDB
- หนึ่ง Static seed container ชื่อว่า PDB$SEED โดย container ตัวนี้จะอยู่เป็นอิสระมีหน้าที่เป็นเพียง template เพื่อสร้าง data files และ metadata สำหรับ pluggable databases ตัวใหม่ๆที่จะสร้างขึ้นใน CDB
- Pluggable databases (0 - 252 ตัว) แต่ละ PDB จะจัดการข้อมูลและฟังก์ชั่นต่างๆในตัวเองคล้ายกับ non-CDB database และมันมี data files และ application objects (users , tables , indexes , อื่นๆ) เป็นของตัวเอง เมื่อเราเชื่อมต่อเข้าสู่ PDB ตัวหนึ่งเราจะมองไม่เห็น root container หรือ PDB ตัวอื่นๆ
Pluggable Database Architecture
สร้าง CDB
ถ้าเราจะใช้งาน PDB feature เราต้องสร้าง Database ให้เป็น Container database โดยมีหลายวิธีในการสร้างเช่น
- สร้างโดย SQL CREATE DATABASE command
- ใช้ DBCA
- Generate script จาก DBCA แล้วเอามารันเอง
- ใช้ RMAN เพื่อทำ Duplicate จาก CDB ที่มีอยู่แล้ว
โดยวิธีการสร้างเหล่านี้ขอไม่พูดถึง
ตรวจสอบ CDB ที่ถูกสร้างขึ้นมาแล้ว
- ใช้ sqlplus / as sysdba
- ตรวจสอบคอลัม name และ CDB ถ้าเป็น YES แสดงว่าถูกสร้างเป็น Container
SQL> select name,cdb from v$database;
NAME CDB
--------- ---
KITTICDB YES
- ตอนนี้เราจะมี 2 containers ใน CDB database ของเราก็คือ root กับ seed pluggable database เราสามารถเช็คด้วยการ query
SQL> select con_id,name from v$containers;
CON_ID NAME
---------- ------------------------------
1 CDB$ROOT
2 PDB$SEED
- เราจะมี data files ของทั้ง root และ seed database เราจะตรวจสอบ data files เหล่านั้นด้วย query
select con_id,file_name from cdb_data_files
order by con_id;
Note : ถ้าเราใช้เวอร์ชั่น 12.1.0.2 เราจะไม่เห็นข้อมูลของ seed เพราะมี undocument parameter ใหม่ตัวนึงชื่อว่า EXCLUDE_SEED_CDB_VIEW ค่า default เป็น true
แต่ในตัวอย่างปรับไว้เป็น false จึงทำให้เราเห็นข้อมูลใน seed database ด้วย
- ถ้าเรา query จาก dba_data_files เราจะเห็นแค่ไฟล์ของ database ที่เราใช้งานอยู่ในที่นี้คือ CDB$ROOT
FILE_NAME
---------------------------------------------------------------------
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_SYSTEM_BQHPTC9S_.DBF
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_SYSAUX_BQHPRMY9_.DBF
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_UNDOTBS1_BQHPWG1C_.DBF
E:\APP\KITTI_L\ORADATA\KITTICDB\DATAFILE\O1_MF_USERS_BQHPWDRS_.DBF
เชื่อมต่อเข้าสู่ Root Container
เราสามารถเชื่อมต่อโดยเป็น sys as sysdba ได้เหมือนการเชื่อมต่อเข้าฐานข้อมูลแบบ non-CDB ทั่วๆไปเช่น
sqlplus / as sysdba
sqlplus sys@KITTICDB as sysdba
SQL> show user con_id con_name
USER is "SYS"
CON_ID
------------------------------
1
CON_NAME
------------------------------
CDB$ROOT
Start/Stop Root Container
เราสามารถ start/stop CDB ได้เหมือนกับ non-CDB ได้ตามปกติโดยต้องเข้ามาในสิทธิที่สามารถทำการเปิด/ปิด ฐานข้อมูลได้ เช่น
sqlplus / as sysdba
SQL*Plus: Release 12.1.0.2.0 Production on Thu Jun 11 10:37:09 2015
Copyright (c) 1982, 2014, Oracle. All rights reserved.
Connected to an idle instance.
SQL> startup
ORACLE instance started.
Total System Global Area 2583691264 bytes
Fixed Size 3048968 bytes
Variable Size 687868408 bytes
Database Buffers 1879048192 bytes
Redo Buffers 13725696 bytes
Database mounted.
Database opened.
เมื่อ CDB startup แล้วแต่ PDB ทุกตัวจะยังอยู่ในสถานะ Mount อยู่เราจะสั่งให้เปิดทุกตัว เช่น
SQL> alter pluggable database all open;
Pluggable database altered.
หากต้องการปิด PDB ทุกตัวก็สั่ง close โดยทุกตัวจะกลายเป็น Mount mode (ยกเว้น PDB$SEED จะอยู่สถานะ Read Only ตลอด)
SQL> alter pluggable database all close;
Pluggable database altered.
สร้าง PDB และเชื่อมต่อเข้าสู่ PDB
เราสามารถสร้าง PDB ใหม่ได้จาก
- PDB$SEED
- PDB ที่มีอยู่แล้ว
- non-CDB
- Unplugged PDB
1. ลอง Cloning จาก PDB$SEED
Login เข้าสู่ CDB แล้วใช้ SQL สร้าง PDB ขึ้นมาโดยใช้ PDB$SEED เป็น template
SQL> create pluggable database kittipdb1
2 admin user kittiadmin identified by kittiadmin
3 file_name_convert = ('E:\app\kitti_l\oradata\KITTICDB\pdbseed',
4 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB1');
Pluggable database created.
Note. ถ้าใช้ OMF ไม่ต้องใส่ file_name_convert เพราะ Oracle จะกำหนดชื่อและที่อยู่ของไฟล์ให้อัตโนมัติ ส่วน admin user คือ local user ที่มีสิทธิ์จัดการ PDB ได้และได้รับ PDB_DBA role
2. Clone จาก PDB ที่มีอยู่แล้ว
ทำการสร้าง KITTIPDB2 โดย Clone จาก KITTIPDB1
เราต้องปิด PDB ตัวที่เราจะ Clone แล้วเปิดใหม่เป็นแบบ Read Only
SQL> alter pluggable database KITTIPDB1 close;
Pluggable database altered.
SQL> alter pluggable database KITTIPDB1 open read only;
Pluggable database altered.
ทำการ Clone ด้วยคำสั่ง SQL
SQL> create pluggable database KITTIPDB2
2 from KITTIPDB1
3 file_name_convert = ('E:\app\kitti_l\oradata\KITTICDB\KITTIPDB1',
4 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB2')
5 storage (maxsize 4G max_shared_temp_size 80M);
Pluggable database created.
Note. storage clause ในที่นี้คือกำหนดขนาด PDB เต็มที่ไว้มากสุด 4G (maxsize) และ session ใน PDB นี้สามารถใช้ Shared Temporary Tablespace ได้มากสุด 80M (max_shared_temp_size)
3. Clone จาก non-CDB database
ใช้ได้หลายวิธีเช่น DBMS_PDB package , Data Pump(Transport Tablespace), GoldenGate
ในที่นี้จะใช้วิธี DBMS_PDB package แต่มีข้อแม้ว่า database ที่จะ Clone นี้ต้องเวอร์ชั่น 12c ขึ้นไป
เปิด non-CDB แบบ read only
SQL> alter database open read only;
Database altered.
หลังจากนั้นรัน DBMS_PDB เพื่อสร้าง XML file ที่มีโครงสร้างของ database อยู่
SQL> begin
2 dbms_pdb.describe(pdb_descr_file => 'E:\noncdb.xml');
3 end;
4 /
PL/SQL procedure successfully completed.
หลังจากไฟล์ XML ถูกสร้างแล้วให้ปิด non-CDB
SQL> shutdown immediate;
ปรับ ORACLE_SID ให้ชี้ไปที่ CDB database ที่เราจะ Clone non-CDB ไปและเข้า sys as sysdba
sqlplus / as sysdba
ตอนนี้เราอยู่ใน CDB database แล้วเราสามารถเช็คก่อนได้ว่า non-CDB ที่เราจะ Clone นั้น compatible กับ CDB database ของเราไหมด้วย DBMS_PDB.CHECK_PLUG_COMPATIBILITY
SQL> set serveroutput on
SQL> declare
2 hold_var boolean;
3 begin
4 hold_var := dbms_pdb.check_plug_compatibility(pdb_descr_file => 'E:\noncdb.xml');
5 if hold_var then
6 dbms_output.put_line('YES');
7 else
8 dbms_output.put_line('NO');
9 end if;
10 end;
11 /
YES
PL/SQL procedure successfully completed.
จากการทดสอบผลคือ YES แสดงว่าไม่มีปัญหาเกี่ยวกับ compatibility แต่ถ้าเป็น NO แสดงว่าอาจมีอะไรผิดพลาด เราสามารถดู PDB_PLUG_IN_VIOLATIONS view เพื่อดูรายละเอียดได้ว่าทำไมถึงไม่ compatibility
ต่อมาใช้คำสั่ง SQL เพื่อสร้าง PDB ขึ้นมาจาก non-CDB โดยเราต้องระบุชื่อและที่อยู่ของ XML file ของ non-CDB , ที่อยู่ของ non-CDB data files , และที่อยู่ใหม่ของ PDB
SQL> create pluggable database KITTIPDB2FROMnonCDB
2 using 'E:\noncdb.xml'
3 copy
4 file_name_convert = ('E:\app\kitti_l\oradata\KITTInonCDB',
5 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB3FROMnonCDB');
Pluggable database created.
เสร็จแล้วลองเชื่อมต่อเข้า PDB ใหม่
SQL> alter session set container=KITTIPDB2FROMnonCDB;
Session altered.
สุดท้ายรันสคริปต์นี้ก็เสร็จสมบูรณ์
@?\rdbms\admin\noncdb_to_pdb.sql
หลังจากนั้น database ควรจะสามารถเปิดขึ้นมาได้ตามปกติ
Unplugging a PDB
ก่อนที่เราจะเอา PDB ไปปลั๊กเข้ากับ CDB อื่นเราต้องทำการ Unplug มันออกจาก CDB ตัวเดิมเสียก่อน
เมื่อเรา Unplug ออกจาก CDB แล้วเราจะได้ XML file มาโดยไฟล์นี้จะเป็นข้อมูล metadata ของ PDB ตัวนั้นๆและสามารถนำไปใช้ Plug เข้าไปที่ CDB ตัวอื่นได้
ปิด PDB ตัวที่จะ Unplug ก่อน
สั่ง Unplug ด้วยคำสั่ง alter pluggable database ... unplug into '....xml';
SQL> alter pluggable database kittipdb2 unplug into 'E:\kittipdb2.xml';
Pluggable database altered.
Note. เมื่อ Unplugged PDB เสร็จแล้วเราต้อง Drop PDB ตัวนั้นก่อนที่จะทำการ Plug เข้ามาสู่ CDB ตัวเดิม (แต่ต้องใช้ keep datafiles option เพราะต้องใช้ data files เดิม)
SQL> drop pluggable database kittipdb2 keep datafiles;
Pluggable database dropped.
Note2. เราสามารถใช้ DBMS_PDB package เพื่อตรวจสอบ compatible ก่อนได้เหมือนกับการ Clone non-CDB to PDB ด้านบน
ในการ Plug เข้าไปใน CDB เราจะทำด้วย SQL statement CREATE PLUGGABLE DATABASE ... และใช้ 2 คำสั่งนี้ในการระบุข้อมูลลงไปคือ
USING clause : ใช้ในการระบุที่อยู่ของ XML file
COPY FILE_NAME_CONVERT clause : ใช้ในการกำหนดที่อยู่ data files ใหม่ในกรณีที่ path ไม่เป็นเหมือนเดิม
แต่ตอนนี้เราจะทำการ Plug เข้าสู่ CDB ตัวเดิมและใช้ data files location เดิมจึงสามารถใช้ NOCOPY clause ได้
SQL> create pluggable database kittipdb2
2 using 'E:\kittipdb2.xml'
3 nocopy;
Pluggable database created.
เมื่อ Plug เข้ามาแล้วก็เปิด database ได้ตามปกติ
SQL> alter pluggable database kittipdb2 open;
Pluggable database altered.
ลองเชื่อมต่อเข้าสู่ PDB ต่างๆ
วิธีแรกใช้ alter session
SQL> alter session set container=KITTIPDB2;
Session altered.
SQL> show con_name
CON_NAME
------------------------------
KITTIPDB2
วิธีที่สองเข้าผ่าน easy connect หรือ tnsnames
sqlplus sys/oracle@localhost:1521/KITTIPDB2 as sysdba
sqlplus sys/oracle@KITTIPDB2 as sysdba
เช็คสถานะของ PDB
ใช้คำสั่ง SQL ถ้าอยู่ที่ CDB จะเห็น PDB ทุกตัวแต่ถ้าอยู่ที่ PDB ตัวไหนจะเห็นแค่ตัวนั้น
SQL> select con_id,name,open_mode,restricted from v$pdbs;
CON_ID CON_NAME OPEN MODE RESTRICTED
---------- ------------------------------ ---------- ----------
2 PDB$SEED READ ONLY NO
3 KITTIPDB2 READ WRITE NO
4 KITTIPDB1 READ WRITE NO
5 KITTIPDB2FROMNONCDB READ WRITE NO
ตรวจสอบว่า parameter ตัวไหนบ้างที่สามารถแก้ไขได้ในระดับ PDB
select name
from v$parameter
where ispdb_modifiable='TRUE'
order by name;
เปลี่ยนชื่อ PDB
เราสามารถเปลี่ยนชื่อ PDB ได้โดยทำการปิดแล้วเปิดใหม่เป็นโหมด restrict เสร็จแล้วสั่งเปลี่ยนชื่อด้วยคำสั่งเช่น
SQL> alter session set container=kittipdb2fromnoncdb;
Session altered.
SQL> shutdown immediate
Pluggable Database closed.
SQL> startup restrict;
Pluggable Database opened.
SQL> alter pluggable database KITTIPDB2FROMnonCDB rename global_name to KITTIPDB3;
Pluggable database altered.
Common Users
มี User 2 ประเภทที่ใช้ใน Pluggable database environment คือ local user กับ common user
local user คือ user ปกติที่ใช้ใน PDB โดยการจัดการจะเหมือนระบบ non-CDB ทั่วๆไป
และ common user เมื่อสร้างเสร็จจะอยู่ใน root container และทุก pluggable database ตลอดจน pluggable database ที่ถูกสร้างขึ้นในอนาคตอีกด้วย
Note. SYS กับ SYSTEM คือ common users ที่ Oracle สร้างให้โดยอัตโนมัติใน Pluggable environment
Common user จะถูกสร้างโดยใช้ C## หรือ c## นำหน้าชื่อ เช่น
sqlplus / as sysdba
SQL> create user c##kitti identified by kitti;
User created.
Common user จะมีสิทธิ์ต่างๆกับไหน PDB ได้ต้องถูก grant จากใน PDB นั้นเท่านั้น ถ้าเราต้องการ grant ให้มีสิทธิ์กับทุกๆ PDB เราต้องสร้าง Common Role แล้ว grant ให้ common user
Common Roles
จะคล้ายกับการสร้าง Common user ที่จะอยู่ในทุก PDB ใน Root container นั้นตลอดจน PDB ที่ถูกสร้างขึ้นในอนาคต และเหมือนกับกับ Common user อีกก็คือ Common role ต้องสร้างด้วย C## หรือ c## นำหน้า ตัวอย่างเช่น
sqlplus / as sysdba
SQL> create role c##dbaprivs container=all;
Role created.
ต่อมาเราสามารถกำหนดสิทธิ์ต่างๆให้กับ common role นี้ได้ เช่น
SQL> grant dba to c##dbaprivs container=all;
Grant succeeded.
เท่านี้ role นี้ก็จะมีสิทธิ์ dba (มาจาก dba role) ที่สามารถใช้งานได้ทุก PDB ต่อมาเราก็จะ grant role นี้ให้กับ common user
SQL> grant c##dbaprivs to c##kitti container=all;
Grant succeeded.
ตอนนี้ c##kitti ก็สามารถจัดการฐานข้อมูลด้วยสิทธิ์ c##dbaprivs(from dba role) ได้ทุก PDB แล้ว
RMAN Backup and Recovery
ในขณะที่เราเชื่อมต่อกับ CDB(Root contaner) เราสามารถ backup ได้ทุก data file ใน database หรือแค่ root container data files , a specific pluggable database , specific tablespaces or data files , or a combination of these
แต่ในขณะที่เราเชื่อมต่อกับ PDB เราจะสามารถ backup ได้แค่ data files ของ PDB ที่เราเชื่อมต่ออยู่
While Connected to the Root container
เช็คก่อนว่าเราเชื่อมต่อไปที่ Root container หรือยัง
RMAN> SELECT SYS_CONTEXT('USERENV', 'CON_ID') AS con_id,
2> SYS_CONTEXT('USERENV', 'CON_NAME') AS cur_container,
3> SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') AS cur_user
4> FROM DUAL;
using target database control file instead of recovery catalog
CON_ID CUR_CONTAINER CUR_USER
---------------------------- ---------------------------- ----------------------------
1 CDB$ROOT SYS
ลอง backup ทุก data file ทั้ง root container database และ pluggable database ในนั้น
RMAN> backup database;
ถ้าเราอยาก backup เฉพาะของ root container ให้ใส่ "root"
RMAN> backup database root;
เราสามารถ backup เฉพาะ PDB ที่เราต้องการได้เช่นกัน
RMAN> backup pluggable database kittipdb1;
และเราก็ backup แบบเจาะจง tablespace ใน PDB ที่เราต้องการได้ด้วย
RMAN> backup tablespace kittipdb1:system,sysaux;
สุดท้ายนี้เราสามารถ backup data file ของ root container database หรือ pluggable database โดยการใส่พาธและชื่อลงไปได้เลย
RMAN> backup datafile 'E:\app\kitti_l\oradata\KITTICDB\KITTIPDB2\SYSTEM01.DBF';
While Connected to a Pluggable database
เราสามารถเชื่อมต่อเข้า PDB ได้เลยจาก RMAN เช่น
rman target sys/oracle@KITTIPDB1
หลังจากเชื่อมต่อเข้ามาแล้วเราสามารถ backup ได้เฉพาะ data file ของ PDB นั้น ดังนั้นเมื่อเราสั่ง
RMAN> backup database;
จะเป็นการ backup เพียงแค่ทุก data file ของ PDB นั้นๆ
หรือ
RMAN> backup tablespace system;
ก็เป็นการ backup system tablespace's data file ของ PDB นั้นๆ เช่นกัน
Complete Recovery
การกู้ทั้ง CDB จะคล้ายกับการกู้ non-CDB แต่มันจะกู้ PDB ที่เกี่ยวข้องมาด้วย
RMAN> run {
2> shutdown immediate; #or abort if failed
3> startup mount;
4> restore database;
5> recover database;
6> alter database open;
7> }
Root Container Complete Recovery
จะให้ผลลัพธ์เหมือนกับการกู้ทั้ง CDB
RMAN> run {
2> shutdown immediate; #or abort if failed
3> startup mount;
4> restore database root;
5> recover database root;
6> alter database open;
7> }
Pluggable Database Complete Recovery
มี 2 วิธีคือ
1.เชื่อมต่ออยู่กับ CDB เราสามารถเลือก PDB ที่จะกู้ได้เลย
RMAN> run {
2> alter pluggable database kittipdb1,kittipdb2 close;
3> restore pluggable database kittipdb1,kittipdb2;
4> recover pluggable database kittipdb1,kittipdb2;
5> alter pluggable database kittipdb1,kittipdb2 open;
6> }
2.ถ้าเชื่อมต่อกับ PDB ก็จะกู้ได้เฉพาะ PDB นั้น
RMAN> run {
2> shutdown immediate;
3> restore database;
4> recover database;
5> startup;
6> }
CDB Point In Time Recovery
จะเหมือนกับของ non-CDB แค่เพิ่มเติมคือเราได้ทำ PITR ทุก PDB ไปด้วย
RMAN> run {
2> shutdown immediate; #or abort if failed
3> startup mount;
4> restore database;
5> recover database until time "to_date('16/06/2015 17:00','DD/MM/YYYY HH24:M
I')";
6> alter database open resetlogs;
7> }
PDB Point In Time Recovery
ทำคล้ายกับ Complete ตรงที่สามารถกู้ PDB กี่ตัวก็ได้ถ้าเราเชื่อมต่ออยู่ที่ Root Container
แต่ถ้าเชื่อมต่ออยู่ที่ PDB ไหนก็จะกู้ได้เฉพาะ PDB นั้น
RMAN> run {
2> alter pluggable database kittipdb1,kittipdb2 close;
3> restore pluggable database kittipdb1,kittipdb2;
4> recover pluggable database kittipdb1,kittipdb2 until time "to_date('16/06/2015 17:00','DD/MM/YYYY HH24:M
I')";
5> alter pluggable database kittipdb1,kittipdb2 open resetlogs;
6> }
Note. กรณีนี้ Resetlogs option จะไม่ได้ทำอะไรกับ Redo log file แต่แค่สร้าง DB incarnation ใหม่
ศึกษามาจากหนังสือ e-book : Pro Oracle Database 12c Administration, 2nd Edition
วันอาทิตย์ที่ 7 มิถุนายน พ.ศ. 2558
Restore database to before upgrade using guarantee restore point
เมื่ออัพเกรดผิดพลาด
หรือมีปัญหาเราสามารถย้อนกลับไปสู่เวลาก่อนการอัพเกรดได้อย่างรวดเร็วด้วยวิธีดังนี้
1.
เปิด Flashback
mode
2.
ทำการสร้าง Guarantee restore point เพื่อเป็นจุดไว้ย้อนกลับก่อนการอัพเกรด (หลังจากสร้างแล้วให้สั่ง alter system switch logfile; ซัก 1ครั้งเพื่อให้มันเก็บ archive ในภาพไม่ได้ทำผมไปทำทีหลัง)
และไปตรวจสอบ flashback
log ที่เก็บ
before image ของข้อมูลจะเก็บอยู่ใน
Flash recovery area
3.
ทำการอัพเกรด
4.
ดูข้อมูล Restore point (v$restore_point) กับ Version
5.
ทำการย้อน DB ไปสู่ก่อนการอัพเกรด
6.
เช็ค Version
(ต้องเข้าด้วย
sqlplus ของ version เดิม)
ข้อบังคับ
-
COMPATIBLE
parameter ต้อง
10.2 ขึ้นไป
-
DB in archivelog
mode
-
มี archive
log file หลังจากสร้าง
Guarantee restore point อันแรก
-
ต้องใช้ flash recovery area
ข้อจำกัด
-
Media failure ไม่สามารถซ่อมด้วย
flashback database ได้
-
ย้อนกลับไปก่อนหน้าการปรับขนาด data file ให้เล็กลงหรือ shrink ไม่ได้
-
ไม่สามารถใช้ flashback database ได้ถ้า control file ถูก restore หรือ recreate
-
Drop tablespace แล้ว recovery ผ่าน resetlogs ไม่สามารถทำได้
สมัครสมาชิก:
บทความ (Atom)