21 June 2021

Undo Segment and error Snapshot Too Old

เมื่อผู้ใช้งานอ่านข้อมูลใน Database เป็นระยะเวลานาน อาจจะเกิดข้อผิดพลาดแจ้งว่าข้อมูลที่ต้องการกลายเป็นข้อมูลที่เก่าเกินไป

เหตุการณ์
Session A รัน SELECT อ่านได้ค่า X
Session B รัน UPDATE เพื่อเปลี่ยนค่าจาก X เป็น Y
โดยเก็บค่าก่อนเปลี่ยนแปลงไว้ที่ UNDO Segment

รูปอธิบาย การทำงานไม่มีปัญหา เพราะ Session A รัน SELECT ข้อมูลในส่วนของ Block 0 จนถึง 19 แล้ว Session B จึงจะมา UPDATE เริ่มที่ block 0 ภายหลัง
จาก https://support.delphix.com/Delphix_Masking_Engine/Resolving_ORA-01555_Error%3A_Snapshot_too_old_(KBA1827)

รูปแสดงขั้นตอนการทำงาน
จาก https://support.delphix.com/Delphix_Masking_Engine/Resolving_ORA-01555_Error%3A_Snapshot_too_old_(KBA1827)
Error ORA-01555 เพราะ Session A ไม่พบข้อมูลที่ต้องการใน UNDO นั่นคือ(ตัวอักษรเอ็ก ไม่ใช่กากบาท)
จาก https://support.delphix.com/Delphix_Masking_Engine/Resolving_ORA-01555_Error%3A_Snapshot_too_old_(KBA1827)

สาเหตุ
เมื่อ Session เริ่ม SELECT ข้อมูล จะต้องได้ข้อมูลที่มีค่าขณะปัจจุบันเสมอ แม้ว่าข้อมูลนั้นจะถูกเปลี่ยนแปลงก่อนที่ SELECT จะอ่านถึง ซึ่งกรณีที่ข้อมูลนั้นถูกเปลี่ยนแปลงภายหลังนี้ จะต้องเก็บข้อมูลเก่าไว้ที่ UNDO เพื่อให้ SELECT นี้สามารถอ่านข้อมูลเก่าได้ แต่ก็สามารถถูกทับได้ ถ้าพื้นที่ใช้งานของ UNDO ไม่เพียงพอ ร่วมกับมีการใช้งาน UNDO จำนวนมาก และ SELECT ทำงานช้า

ขั้นตอนการเปลี่ยนสถานะของพื้นที่ที่ใช้งานใน UNDO
1. Session ทำการ update ข้อมูล จะมีสถานะ active
2. เมื่อ Session จบการทำงานแล้ว จะมีสถานะ inactive และ unexpired (สามารถถูก session อื่น นำไปใช้งานได้ แต่อาจเกิด error ORA-01555)
3. เมื่อหมดอายุตามที่กำหนดใน UNDO_RETENTION แล้ว จะมีสถานะ expired (สามารถถูก session อื่น นำไปใช้งานได้ตามปกติ)
4. ถ้ากำนดค่า retention guarantee ไว้ จะไม่ถูก Session ใดนำไปใช้งานได้ จนกว่าจะหมดระยะเวลาของ retention guarantee

ตัวอย่างการเกิด error ORA-01555
0:00 เซสชัน A เริ่ม SELECT
0:01 เซสชัน B รัน UPDATE ที่บล็อก 1000000 ซึ่งข้อมูล UNDO สำหรับบล็อกนี้จะถูกบันทึกในส่วน UNDO
0:01 เซสชัน B รัน COMMIT เปลี่ยนสถานะเป็น unexpired และเริ่มนับอายุตามที่กำหนดใน UNDO_RETENTION
เซสชันนี้สร้างข้อมูล UNDO แต่ข้อมูลยังคงอยู่ เนื่องจากสามารถใช้เมื่อใดก็ได้
1:00 เซสชัน A สืบค้นถึงบล็อก 200000
1:01 มีกิจกรรมมากมายเกิดขึ้นและสร้างข้อมูล UNDO จำนวนมาก และอายุที่กำหนดใน UNDO_RETENTION หมด ทำให้สถานะคือ expired และสามารถถูกเขียนทับได้
3:00 เซสชัน A สืบค้นถึงบล็อก 600000
4:00 ส่วนของข้อมูล UNDO เริ่มถูกเขียนทับและนำพื้นที่ที่มีการใช้งาน (อยู่ระหว่างดำเนินการ transactions in progress) กลับมาใช้ใหม่เมื่อมีคิวรี่ใดๆเริ่มต้นทำงาน ในที่นี้คือบล็อก 1000000 ถูกเขียนทับ
5:00 เซสชัน A สืบค้นถึงบล็อก 1000000 และต้องไปตรวจสอบการอ่านที่สอดคล้องกัน consistent read ที่ UNDO ด้วย เพราะข้อมูลบล็อก 1000000 นี้มีการเปลี่ยนแปลง แต่เซสชัน A รัน SELECT ก่อนการเปลี่ยนแปลง จึงต้องการค่าเก่า  แต่พบว่าข้อมูล UNDO ส่วนนี้ถูกเปลี่ยนไปแล้วจึงไม่สามารถหาค่าเก่าได้ จึงแสดง error ORA-01555 และเซสชัน A จะสืบค้นโดยแสดงข้อผิดพลาดนี้

วิธีแก้ไข

ให้ Session ใดๆที่กำลัง SELECT ข้อมูลอยู่นั้น สามารถจบการ SELECT ได้ทันก่อนที่ข้อมูลบน Undo จะถูกเขียนทับ

วิธีที่ 1 เพิ่มประสิทธิภาพการ query select เพื่อให้ใช้เวลาน้อยลง
จาก https://www.xtivia.com/ora-01555-snapshot-old/

วิธีที่ 2 พยายามจัดตารางเวลาการ query select ที่รันเป็นเวลานาน ให้อยู่ในช่วงเวลาที่ระบบมีการใช้คำสั่ง DML ที่น้อย
จาก https://www.xtivia.com/ora-01555-snapshot-old/

วิธีที่ 3 เพิ่มขนาดพื้นที่ Undo
จาก https://www.xtivia.com/ora-01555-snapshot-old/
เพื่อให้ไม่ให้ session อื่น มาใช้พื้นที่ที่กำลังถูกใช้โดย session ที่รันนาน

วิธีที่ 4 เพิ่มขนาดของพารามิเตอร์ UNDO_RETENTION
จาก https://www.xtivia.com/ora-01555-snapshot-old/
เพื่อให้มีเวลานานพอ ที่จะให้ session ใดๆที่กำลังอ่านอยู่นั้น สามารถจบการอ่านได้ทันก่อนที่ข้อมูลบน Undo จะ expire เพราะข้อมูลนี้อาจจะถูกทับได้

วิธีที่ 5 ตั้งค่า Undo เป็น GUARANTEE mode
จาก https://www.xtivia.com/ora-01555-snapshot-old/
เพื่อให้พื้นที่ข้อมูลบน Undo ไม่ถูก session อื่นเอาไปใช้ แต่ให้แสดง error พื้นที่ของ Undo ไม่เพียงพอแทน

วิธีที่ 6 อย่า commit ใน cursor loop
จาก https://www.xtivia.com/ora-01555-snapshot-old/

07 October 2020

In-Memory Database Overview

In-Memory Database เป็นการจัดเก็บ data ทั้งหมดไว้ใน memory ทำให้การเข้าถึงข้อมูลรวดเร็วกว่าแบบเดิมที่ใช้ Disk ค่อนข้างมาก เพราะ memory มีการคำนวนซับซ้อนน้อยกว่า Disk และใช้งาน CPU ค่อนข้างต่ำ
ใน Oracle Database แบบเก่าจะเก็บข้อมูลในรูปแบบ row format ในระดับ physical level เพราะรูปแบบของการทำ transaction ของงาน OLTP อาจจะต้องการเข้าถึงข้อมูลคอลัมน์ทั้งหมดเพื่อบันทึกในเวลาเดียวกัน

Oracle In-Memory 12c
คือ feature ของ Oracle Database เหมาะกับงาน real-time analytics Data เพราะสามารถทำ mixed-workload enterprise OLTP ได้

โครงสร้างพื้นฐาน

In-Memory Dual-Format ของเวอร์ชั่น 12cR1
รูป In-Memory Dual-Format ของเวอร์ชั่น 12cR1
จาก https://www.doag.org/formes/pubfiles/8534096/2016-DB-Tirthankar_Lahiri-Database_In-Memory__A_Deep_Dive_and_a_Future_Preview-Manuskript.pdf


จากรูป
- ในเวอร์ชั่น 12cR1 ทำงานด้วยสถาปัตยกรรมแบบ Dual-Format คือ ข้อมูลของ Table ที่อยู่บน memory สามารถถูกเรียกใช้ในแบบ Row และ Column ได้พร้อมๆกัน โดยจะมี Oracle SQL Optimizer มาจัดการ Query
- การทำงานของ Oracle In-Memory จะ run ใน Oracle Database
- งาน OLTP จะ load Table มาเก็บบน memory ในรูปแบบ row format
- งาน Analytics จะ load Table มาเก็บบน memory ในรูปแบบ column format (รูปแบบ column format จะใช้ได้เฉพาะบน In-Memory เท่านั้น โดยไม่ต้องมีการ recovery เพราะมีการเก็บข้อมูลบน Disk ในแบบ row format อยู่แล้ว)

In-Memory Fast Start ของเวอร์ชั่น 12cR2
รูป In-Memory Fast Start ของเวอร์ชั่น 12cR2
จาก https://www.doag.org/formes/pubfiles/8534096/2016-DB-Tirthankar_Lahiri-Database_In-Memory__A_Deep_Dive_and_a_Future_Preview-Manuskript.pdf

จากรูป
- เวอร์ชั่น 12cR2 ปรับปรุงมาเป็นแบบใช้สถาปัตยกรรม Fast Start

อธิบายเพิ่มเติม

ข้อดีและข้อเสีย

ข้อดี
จาก http://www.dadbm.com/oracle-12c-in-memory-database-how-to-start/
- จำนวนข้อมูลที่เก็บบน memory สามารถเก็บได้มาก เพราะสามารถบีบอัดข้อมูลแบบ columnar compression ได้
- มีประสิทธิภาพที่เพิ่มขึ้นอย่างมากในงาน analytic และ reporting queries
- การทำงานของคำสั่ง DML ทำได้เร็วขึ้น เพราะมีการลบ index ที่ใช้สำหรับ analytical และสำหรับ performance ที่มีอยู่ออกให้มากที่สุด
- บน Disk เกิด I/O น้อยมาก
- มีความยืดหยุ่นและความละเอียดสูง โดยการโหลดเฉพาะ segments ของข้อมูลที่จะใช้งานเท่านั้นลงใน memory
- ไม่ต้องแก้ไขอะไรที่ Application
- การตั้งค่า setup In-Memory feature สามารถทำได้ง่าย
- ยังคงใช้ Oracle Database เหมือนเดิม แต่เพิ่มฟังชั่นการทำงานของ In-Memory เข้าไปเฉยๆ

ข้อเสีย
จาก http://www.dadbm.com/oracle-12c-in-memory-database-how-to-start/
- SYS objects ใน SYSTEM และ SYSAUX tablespace ไม่สามารถเก็บใน In-Memory
- ไม่สามารถใช้กับ Clustered table
- ไม่สามารถใช้กับ Column ที่ data type เป็น long

หลักในการเลือกใช้
จาก http://www.dadbm.com/oracle-12c-in-memory-database-how-to-start/
- ถ้าผู้ใช้มีปัญหาด้านประสิทธิภาพเกี่ยวกับงานด้านการค้นหาข้อมูล
- ถ้าไม่สามารถ tuning ในแบบอื่นๆได้
- ถ้าแอปพลิเคชันส่วนใหญ่ประกอบด้วยงาน analytics และ reporting queries ซึ่งส่วนใหญ่จะใช้คอลัมน์จำนวนน้อยแต่ส่งผลลัพธิ์กลับไปหลายแถว ซึ่งต่างจากงาน OLTP ที่ใช้แถวจำนวนน้อยแต่ส่งผลลัพธิ์กลับไปหลายคอลัมน์
- มีประโยชน์สำหรับระบบขนาดใหญ่ รวมถึงระบบที่เล็กกว่าก็สามารถแยกงานออกจาก I/O บน Disk มาทำที่ memory ได้
- ถ้าหากประสิทธิภาพของ In-Memory ทำงานได้ดีกว่าการต้องไปเพิ่ม Oracle license costs อื่น

06 October 2020

Multitenant Features Overview

ในสมัยก่อน Database แต่ละตัวจะแยกกันและจัดการเป็นอิสระด้วยตัวเองไม่เกี่ยวข้องกับ Database ตัวอื่นๆ แต่มีการพัฒนาระบบการจัดการ Database แบบรวมกันที่ส่วนเดียวได้ ด้วยโครงสร้างแบบ Multitenant Database

Oracle database 12c Multitenant คือ feature ใหม่ เปิดตัวครั้งแรกในเวอร์ชั่น 12cR1 ปี 2014 ทำให้สามารถสร้างและจัดการฐานข้อมูลได้หลายตัวมากขึ้นไว้ในฐานข้อมูลใหญ่ตัวเดียวที่เรียกว่า Container Database (CDB) ซึ่งฐานข้อมูลหลายตัวเหล่านั้นเราเรียกว่า Pluggable Databases (PDB) โดยทั้ง CDB และ PDB จะเรียกอีกชื่อเหมือนกันว่า Container
ฐานข้อมูลในเวอร์ชั่นก่อน 12c หรือ ฐานข้อมูลแบบเก่า จะเรียกว่า non-CDBs

โครงสร้างพื้นฐาน

เปรียบเทียบ แบบ non-CDBs และ CDBs
รูปจาก https://www.thegeekdiary.com/oracle-database-server-architecture-overview/
http://mkrishnadba.blogspot.com/2013/09/12c.html

non-CDB SALES and non-CDB HR


CDB (PDBs SALES and HR)


รูป ส่วนประกอบของ file ต่างๆ ใน CDB และ PDB
จาก https://avdeo.com/2015/01/16/creating-oracle-12c-multitenant-container-database/

อธิบายเพิ่มเติม

แต่ละ CDB ประกอบด้วย
- Root Container มีได้ 1 อัน ชื่อว่า CDB$ROOT เป็น Master set of data dictionary views ซึ่งมี metadata ที่เกี่ยวข้องกับ root container ตลอดจน pluggable databases ทุกตัวที่อยู่ใน CDB
- Static seed Container มีได้ 1 อัน ชื่อว่า 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 ตัวอื่นๆ
จาก http://orakitti.blogspot.com/2015/06/oracle-12c-multitenant-practice.html

วิธีแยกประเภทของฐานข้อมูล
ดูค่า CON_ID จาก V$INSTANCE หรือ V$DATABASE
CON_ID = 0 คือ non-CDBs
CON_ID = 1 คือ CDB (CDB$ROOT)
CON_ID = 2 คือ PDB (PDB$SEED)
CON_ID > 2 คือ PDB

ข้อดี
- ส่วนของ memory และ process อยู่ที่ container ที่เดียว
- การโคลนฐานข้อมูลทำง่ายและรวดเร็วขึ้น
- งานพื้นฐานทั่วไป สามารถทำที่ container ที่เดียว เช่น งาน backup
- ทำ patch และ upgrade ฐานข้อมูลที่ container ที่เดียว

User และ Role ของ CDB และ PDB

รูป user ต่างๆที่ใช้งานระบบ
จาก https://docs.oracle.com/database/122/CNCPT/overview-of-the-multitenant-architecture.htm#CNCPT89257


 
Type ของ User

Common User 
- เป็น user ที่สามารถใช้ได้ใน containers ทุกอัน (root Container และ PDBs ทุกอัน)
- เมื่อสร้างเสร็จแล้วจะอยู่ใน root Container และทุก PDB รวมถึง PDB ที่จะถูกสร้างขึ้นในอนาคตด้วย
- สามารถมีสิทธิ์เหมือนกันหรือแตกต่างกันในแต่ละ PDB ได้ โดยต้องถูก grant จากใน PDB นั้นๆเท่านั้น
- Common user ที่เกิดจากระบบสร้างขึ้นเอง เรียกว่า Oracle-supplied คือ user SYS และ SYSTEM
- Common user ที่เกิดจากเราสร้างขึ้นเอง เรียกว่า User-created คือ user ที่ต้องสร้างโดยตั้งชื่อด้วย C## หรือ c## นำหน้า
- ตัวอย่าง จากรูป คือ user c##dba ใน root Container และทุก PDB ซึ่งเป็นคนคนเดียวกัน

Local User
- เป็น user ที่ใช้ได้เฉพาะ PDB นั้นๆเท่านั้น เป็น user ปกติที่ใช้ใน PDB โดยการจัดการจะเหมือนระบบ non-CDB ทั่วๆไป
- แต่ละ PDB สามารถตั้งชื่อ user เหมือนกันได้ แต่จะเป็นคนละคนกันตามแต่ละ PDB ไม่เกี่ยวข้องกัน
- ตัวอย่าง จากรูป คือ user hr ใน hrpdb, hr ใน salespdb, rep ใน salespdb และ rep ใน hrpdb ซึ่งเป็นคนละคนกันในแต่ละ PDB

Type ของ Role

Common Role
- เป็น role ที่สามารถใช้ได้ใน containers ทุกอัน (root และ PDBs ทุกอัน)
- จะคล้ายกับการสร้าง Common user ที่จะอยู่ในทุก PDB ที่อยู่ใน Root container นั้น ตลอดจน PDB ที่ถูกสร้างขึ้นในอนาคต
- Common role ต้องสร้างด้วย C## หรือ c## นำหน้า

Local Role 
- เป็น role ที่ใช้ได้เฉพาะ PDB นั้นๆเท่านั้น เป็น role ปกติที่ใช้ใน PDB โดยการจัดการจะเหมือนระบบ non-CDB ทั่วๆไป
- แต่ละ PDB สามารถตั้งชื่อ role เหมือนกันได้ แต่จะเป็นคนละอันกันตามแต่ละ PDB ไม่เกี่ยวข้องกัน

05 October 2020

Insert Large Data to test

สร้างการเพิ่มข้อมูลขนาดใหญ่บน Database แบบง่ายสำหรับทดสอบการทำงาน

อธิบาย

- เมื่อ run คำสั่ง จะเกิดการใช้ทรัพยากรต่างๆดังนี้
 - ที่ Database ใช้พื้นที่ของ temp Tablespace (เฉพาะใช้ /*+ append_values */ หรือ /*+ append */) - ที่ Database เกิด Logical I/O (มีการอ่านเขียนที่ buffer) - เกิด Disk I/O read และ write (write เกิดมากกว่า read ค่อนข้างแยอะ) - เกิดการขยายขนาด data file เมื่อ transaction เริ่มทำงาน (โดยยังไม่ commit หรือ rollback) - เกิดการเขียน redo log เมื่อ transaction เริ่มทำงาน (โดยยังไม่ commit หรือ rollback) - User มีการใช้พื้นที่ tablespace นั่นคือ ขนาด tablespace เพิ่มขึ้น เมื่อ transaction เริ่มทำงาน (โดยยังไม่ commit หรือ rollback) - Object มีการใช้พื้นที่ segment นั่นคือ ขนาด segment เพิ่มขึ้น เมื่อ transaction เริ่มทำงาน (โดยยังไม่ commit หรือ rollback) - เกิดการใช้ memory เล็กน้อย

- การเพิ่มข้อมูลสามารถเกิดปัญหาดังนี้
- อาจทำให้เกิด error ORA-00257: archiver error. และถ้ายังไม่แก้ปัญหา จะเกิดการ stop execute transactions
ที่ alert log แสดง error 
ORA-19809: limit exceeded for recovery files
ORA-19804: cannot reclaim ขนาดพื้นที่ที่ต้องการเพิ่ม bytes disk space from ขนาดพื้นที่ที่จำกัดไว้ limit
ORA-19815: WARNING: db_recovery_file_dest_size of ขนาดพื้นที่ที่จำกัดไว้ bytes is 100.00% used, and has 0 remaining bytes available.
วิธีแก้ไขไม่ให้สร้าง redolog ให้ปิด log ของ table และใช้คำสั่ง insert value ด้วย /*+ append_values */ หรือ insert as select ด้วย /*+ append */
ตัวอย่าง ปิด log ของ table
SQL> alter table u1.tb_test_large nologging;
- ถ้าต้องการ add primary key ทำภายหลัง insert data เพราะถ้าทำก่อน insert data จะทำให้การ insert data ทำงานช้ามาก
  ตัวอย่าง
SQL> alter table u1.tb_test_large add constraint
tb_test_large3_pk primary key(object_id);
SQL> begin
   dbms_stats.gather_table_stats
   ( ownname    => 'u1',
tabname    => 'tb_test_large',
cascade    => true );
end;
/
สร้าง insert large data โดยกำหนด data size ที่ต้องการ
จาก http://stackoverflow.com/questions/6674919/generate-and-insert-large-clob-1-mb-using-sqlplus

กำหนด
Create table
SQL> create table u1.test_tb_large1(id number
 , large_text clob);

No logging กำหนดให้ไม่เก็บ redolog
SQL> alter table u1.test_tb_large1 nologging;

Insert data
CLOB 32767 byte or 32 KB is the largest string we can use in PL/SQL
ตัวอย่าง 
    ถ้าต้องการ data ขนาด 1 MB = 0.03125 MB * 30 = ใช้ for i in 1..30
    ต้องการ data ขนาด 1024 MB = 1 GB = 0.03125 MB * 32768 = ใช้ for i in 1..32768
    ต้องการ data ขนาด 10240 MB = 10 GB = 0.03125 MB * 327680 = ใช้ for i in 1..327680

RPAD คือ  Store ใช้เพิ่ม characters ทางขวาของ string ในที่นี้คือ "X" โดย เพิ่ม "X" จำนวน 32767 ตัว มีค่าเท่ากับ 32767 byte หรือ 32 KB หรือ 0.03125 MB
   แล้วจึง insert ลง table
SQL> declare
c clob;
i number;
begin
    for i in 1..30
    loop
        -- 32767 byte or 32 KB or 0.03125 MB
        c := c||rpad('X', 32767, 'X');
    end loop;
    insert /*+ append */ into u1.test_tb_large1 values(1, c)
    ;
end;
/

Check
SQL> set long 5000
SQL> set linesize 1000
SQL> set pagesize 1000
SQL> select * from u1.test_tb_large1;
ID  LARGE_TEXT
--- ---------------------------------------------------------------------------------
1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
...
.....
........

สร้าง insert large data โดยใช้  loop

อธิบาย
- ถ้าใช้ /*+ append */ หรือ /*+ append_values */ โดยไม่ commit จะเกิด error ORA-12838: cannot read/modify an object after modifying it in parallel
เพราะทุกครั้งที่ loop run คำสั่ง insert จะเปิด transaction ใหม่เสมอ จึงต้องจบ transaction เดิมก่อน

กำหนด
Create table
SQL> create table u1.tb_test_large2init(text varchar2(1000));
SQL> insert into u1.tb_test_large2init(text) values('XXX');
SQL> create table u1.tb_test_large2(id number,text varchar2(1000));
SQL> alter table u1.tb_test_large2 nologging;

Insert data
SQL> declare
i number;
begin
    for i in 1..1000
    loop
        --insert /*+ append */ into u1.tb_test_large2(id,text) select i,text from u1.tb_test_large2init;
insert /*+ append_values */ into u1.tb_test_large2(id,text) values(i,'XXX');
commit;
    end loop;
end;
/

ถ้าต้องการให้เป็นแบบ infinite
declare
i number:=1;
begin
  loop
--insert /*+ append */ into u1.tb_test_large2(id,text) select :i,text from u1.tb_test_large2init;
insert /*+ append_values */ into u1.tb_test_large2(id,text) values(i,'XXX');
commit;
i:=i+1;
  end loop;
end;
/

Slow query to test

สร้างการอ่านข้อมูลที่ทำงานเป็นระยะเวลานานบน Database แบบง่ายสำหรับทดสอบการทำงาน

อธิบาย
- การอ่านข้อมูลสามารถเกิดปัญหาดังนี้
- เกิดการใช้ CPU 1 ตัว ปริมาณ 90 - 100% หรือใช้ CPU คนเดียว 1 ตัว (ต่อ 1 session)

สร้าง query slow ด้วยการ loop infinite
อธิบาย
- เมื่อ run คำสั่ง จะเกิดการใช้ทรัพยากรต่างๆดังนี้
- เกิดการใช้ CPU 1 ตัว ปริมาณ 90 - 100%  (1 session ใช้ CPU 1 ตัว)

SQL> begin
  loop
null;
  end loop;
end;
/

สร้าง query slow ด้วยการ sleep
อธิบาย
- เมื่อ run คำสั่ง จะเกิดการใช้ทรัพยากรต่างๆดังนี้
- เกิด Parallel Sessions

Create Function ให้ sleep ระยะเวลา P_SECONDS sec
SQL> create or replace function test_func_slow(p_seconds in number)
return number
is
begin
  dbms_lock.sleep(p_seconds);
  return 1;
end;
/

ตัวอย่าง ใช้ table ใดๆ โดยแต่ละ row ใช้เวลา 300 sec
SQL> select test_func_slow(300)
from test_tb_slow
connect by level <= 20000;

ตัวอย่าง ใช้ table ใดๆ โดยแต่ละ row ใช้เวลา 600 sec = 10 min และใช้ run แบบ parallel 4 CPU
SQL> create table test_tb_slow(id number);
SQL> insert into test_tb_slow(id) values(1);
SQL> insert into test_tb_slow(id) values(2);
SQL> insert into test_tb_slow(id) values(3);
SQL> commit;
SQL> select /*+ parallel(test_tb_slow 4) */ test_func_slow(600)
from test_tb_slow;

ตัวอย่าง ใช้ dual กำหนดจำนวน row = 20000 โดยแต่ละ row ใช้เวลา 300 sec
SQL> select test_func_slow(300)
from dual
connect by level <= 20000;

สร้าง query slow ด้วยการ select ข้อมูลขนาดใหญ่
จากหัวข้อ Insert Large Data to test ให้ insert ข้อมูลขนาดใหญ่ก่อน แล้วจึงเอามา select
อธิบาย
- เมื่อ run คำสั่ง จะเกิดการใช้ทรัพยากรต่างๆดังนี้
- ที่ Database เกิด Logical I/O (มีการอ่านเขียนที่ buffer ปกติอ่านจะแยอะกว่าเขียนค่อนข้างมาก เพราะการเรียกใช้ข้อมูลครั้งต่อๆไป จะมีข้อมูลเดิมบางส่วนอยู่ที่ buffer)
- เกิด Disk I/O read ที่ data file ค่อนข้างมาก เมื่อเป็นการ run ครั้งแรก

- การ select ข้อมูลสามารถเกิดปัญหาดังนี้
- อาจทำให้เกิด error ORA-01555 Snapshot Too Old ถ้า select ข้อมูลจากตารางที่กำลังมีการแก้ไขจาก user คนอื่น
   ข้อมูลเพิ่มเติมจาก https://www.tekstream.com/resource-center/ora-01555-snapshot-too-old/

18 July 2020

Optimize Insert and Update Large Data of DML

ปัญหาเมื่อมีการเพิ่มหรือปรับปรุงข้อมูลขนาดใหญ่ใน Database
จาก http://www.dba-oracle.com/t_dml_large_insert_update_hanging.htm

อาจจะเกิดปัญหาดังนี้
1.Insert aborts with a ORA-01555 snapshot too old
2.Insert hangs when your archive redo log directory becomes full.

วิธีต่างๆที่แนะนำ

1.Divide and Conquer

คำอธิบาย
จาก http://www.dba-oracle.com/t_dml_large_insert_update_hanging.htm
Commit job ทุกๆช่วงเวลา เพื่อให้ปลดปล่อยการใช้งาน (release hold) ของ Rollback Segments

2.Check space in archived redo log file system

คำอธิบาย
จาก http://www.dba-oracle.com/t_dml_large_insert_update_hanging.htm
ตรวจสอบพื้นที่ของ disk ให้เพียงพอที่จะเก็บ Archived redo log ที่เพิ่มขึ้น

3.Dedicated undo

คำอธิบาย
จาก http://www.dba-oracle.com/t_dml_large_insert_update_hanging.htm
ตรวจสอบพื้นที่ของ Undo หรือ Rollback Segment ให้เพียงพอกับ insert update Large Data และการทำงานอื่นๆที่ต้องการแก้ไข data พร้อมกันด้วย

4.Parallelize the insert job

คำอธิบาย
จาก http://www.dba-oracle.com/t_dml_large_insert_update_hanging.htm
การ insert โดยใช้ job แบบ parallel

5.Bulk DML

คำอธิบาย
จาก http://www.dba-oracle.com/t_dml_large_insert_update_hanging.htm
ใช้ PL/SQL bulk operators เพื่อเพิ่มความเร็วด้วยการ reducing context switching

6.NOLOGGING option

คำอธิบาย
จาก http://www.dba-oracle.com/t_dml_large_insert_update_hanging.htm
จาก http://dba-oracle.com/t_nologging_append.htm
เป็นวิธีการที่ดีสำหรับเพิ่มความเร็ว insert และการสร้าง index เพราะไม่ทำ redo log แต่ต้องระวังคือ ไม่มี Redo log ให้ใช้งาน ถ้าต้องทำ roll-forward สำหรับการ recovery

เมื่อใช้งาน NOLOGGING option จะต้องพิจารณาคือ
1.Backup data ทั้งหมด ก่อนและหลังดำเนินการ NOLOGGING
2.Only NOLOGGING operations during the NOLOGGING window
คือ ระหว่าง backup ก่อนและหลัง จะเป็นการดำเนินการ NOLOGGING เพียงอย่างเดียวเท่านั้น เรียกว่า backup sandwich
ขั้นตอนที่เกิดขึ้นคือ backup data (ทำก่อนจะดำเนินงาน NOLOGGING) ตามด้วย NOLOGGING operation ตามด้วย backup data (ทำหลังจากดำเนินงาน NOLOGGING เสร็จแล้ว)

คำสั่ง NOLOGGING ไม่ใช่ SQL Hint และ option NOLOGGING มีความซับซ้อนและขึ้นอยู่กับหลายปัจจัย
ถ้า Database คือ NOARCHIVELOG mode และไม่ใช้ APPEND hint สำหรับ inserts ระบบจะยังคงสร้าง redo log อยู่เสมอ (ประโยคนี้บอกถึงว่า การปิด Archivelog ไม่ได้ทำให้หยุดการสร้าง redo log)
ถ้า Database คือ ARCHIVELOG mode (หรือ NOARCHIVELOG mode ก็ได้) ส่วนของ table ต้อง alter เพื่อใช้ NOLOGGING mode และ SQL insert ต้องใช้ APPEND hint เท่านั้น จึงจะไม่สร้าง redo log ไม่เช่นนั้น redo log จะยังคงสร้างตามปกติอยู่

เราสามารถใช้ NOLOGGING สำหรับ batch inserts into tables ก็ได้ และสำหรับการสร้าง index ก็ได้
1.การ insert แบบ NOLOGGING คือ ใช้ APPEND hint และกำหนด table ด้วย NOLOGGING จะทำให้ไม่สร้าง redo log
SQL> alter table MyTable nologging;

SQL> insert /*+ append */ into MyTable ….;
SQL> insert /*+ append */ into MyTable ….;
SQL> insert /*+ append */ into MyTable ….;
….
…….
………

2.การ create index แบบ NOLOGGING สามารถเพิ่มความเร็วในการสร้าง index ได้ถึง 30%
แต่มีสิ่งที่ต้องระวังคือ การสร้าง index แบบ re-run ใหม่ ขณะที่เรากำลังทำ roll-forward สำหรับงาน  Database recovery
SQL> create index newidx . . . nologging;

3.การดำเนินการเหล่านี้สามารถใช้ NOLOGGING ได้
SQL> alter table...move partition
SQL> alter table...split partition
SQL> alter index...split partition
SQL> alter index...rebuild
SQL> alter index...rebuild partition
SQL> create table...as select
SQL> create index
SQL> direct load with SQL*Loader
SQL> direct load INSERT (using APPEND)

NOLOGGING clause warning
1. ระวังเมื่อใช้ UNRECOVERABLE และ NOLOGGING เมื่อดำเนินการ CREATE INDEX หรือ CREATE TABLE AS SELECT (CTAS)
2. การใช้ CTAS with NOLOGGING หรือ UNRECOVERABLE จะส่งคำสั่ง create ที่เกิดขึ้นจริง ไปยัง redo log (เพราะข้อมูลนี้จำเป็นต้องใช้ใน data dictionary) แต่ทุกแถวที่โหลดไปที่ตารางในระหว่างการดำเนินการจะไม่ถูกส่งไปยัง redo logs ด้วย
3.การใช้ NOLOGGING แม้ว่าจะสามารถตั้งค่าแอตทริบิวต์ NOLOGGING ได้
แต่สำหรับ table, partition, index, หรือ tablespace โหมด NOLOGGING จะไม่ดำเนินการกับทุก operation ของ schema object แม้ว่าจะ set  NOLOGGING เอาไว้แล้ว
4.ไม่สามารถใช้ roll-forward ตามเวลาที่เจาะจงได้ (point in time) ถ้าใช้ NOLOGGING
เช่น CREATE INDEX NOLOGGING, CREATE TABLE AS SELECT NOLOGGING, หรือ an NOLOGGING table load
5.การใช้ NOLOGGING มักจะลดระยะเวลา run time ได้มากกว่าครึ่ง
แต่ต้องพิจารณาความเสี่ยงต่างๆด้วย

ตัวอย่าง
เมื่อต้อง reorganize ที่ large tables ที่เกิดจาก insert แบบ CTAS ที่ใช้ NOLOGGING (เป็นตัวอย่างที่ควรระวัง)

Create table ใหม่ จาก table เก่า ที่มีขนาดใหญ่
SQL> create table table_new tablespace new_ts NOLOGGING
as select * from table_old;

Drop table เก่า
SQL> drop table table_old;

Rename table ใหม่เป็นชื่อเก่า
SQL> rename table_new to table_old;

7.Hint /*+ APPEND */ and /*+ APPEND_VALUES*/

คำอธิบาย
จาก https://oracle-base.com/articles/misc/append-hint
จาก https://oracle-base.com/articles/11g/append-values-hint-11gr2
จาก https://sites.google.com/site/oraclepracticals/oracle-sql/append-hint

ให้ใช้ hint /*+ APPEND */ สำหรับกรณี insert as select แต่ถ้าใช้กับ insert values จะมีผลเหมือน insert ปกติ
ให้ใช้ hint /*+ APPEND_VALUES*/ สำหรับกรณี insert values แต่ถ้าใช้กับ insert as select จะมีผลเหมือน insert ปกติ

มีผลกับ Performance อย่างไร
เป็น direct-path insert คือ เขียน data ไปที่ data file หรือ disk โดยตรง โดยไม่ใช้ database buffer cache
โดยเพิ่ม data ไปที่ตำแหน่งสุดท้ายของ table ซึ่ง insert ตามปกติแล้วจะเพิ่ม data ไปที่พื้นที่ว่างภายใน table

มีผลกับ Table Size (High Water Mark) อย่างไร
เป็นการ direct-path insert data ไปที่ end of table ทำให้เป็นการเพิ่ม table high water mark แม้ว่าจะมีพื้นที่ว่างภายใน table ก็ตาม
การใช้ APPEND hint กับ table ที่มีการ delete data บ่อยๆ อาจจะทำให้ table มีขนาดใหญ่ โดยที่ block ถูกใช้เก็บ data เพียงจำนวนน้อย ไม่เต็มพื้นที่ของ table
ทำให้ต้องจัดการด้วยการ shrink operation ด้วยวิธีการดังต่อไปนี้ วิธีใดวิธีหนึ่งก้ได้
1.export data ออกไปก่อน แล้ว truncate table แล้วจึง import เข้ามาใหม่
2.CREATE TABLE tableใหม่ AS SELECT จาก tableเก่า เพื่อสร้าง table ใหม่ ให้ได้ data ที่วางเรียงติดกันภายใน table ใหม่นี้ แล้ว drop table เก่า และเปลี่ยนชื่อ table ใหม่เพื่อแทนที่ table เก่า
3.ใช้ online segment shrink operation สำหรับ compact the data เพื่อให้ data จัดเรียงติดกันมากขึ้น

มีผลกับ Redo Generation อย่างไร
ถ้า database คือ NOARCHIVELOG mode จะช่วยลดการสร้าง redo log
แต่ถ้า database คือ ARCHIVELOG mode จะไม่ลดการสร้าง redo log นอกจากจะกำหนด table เป็น NOLOGGING

Oracle แนะนำไม่ให้ใช้ APPEND hint กับ referential integrity constraints และ trigger เพราะทำให้ data logically corrupt ได้
ดังนั้นควรใช้ insert แบบปกติ หรือ disable referential integrity constraints และ trigger ก่อน

8.Drop or disable index and constraint

คำอธิบาย
จาก http://www.dba-oracle.com/t_insert_tuning.htm
การ drop/disable index และ constraint แล้วจึง insert Large Data แล้วจึง create/enable rebuild index จะทำงานได้เร็วกว่า การ enable index ขณะที่มีการ insert Large Data
นอกจากนี้ การ rebuild index ใน table ที่มี large block size ขนาดใหญ่ จะทำได้ไวมากขึ้น

9.Increasing the Log File Size

คำอธิบาย
จาก https://logicalread.com/oracle-11g-increase-log-checkpoint-interval-mc02/#.Wl7M9K6WbIU
การเพิ่มความเร็วให้กับการ insert, update และ delete ด้วยการเพิ่ม size ของ redo log file ควรใช้ร่วมกับ disk ที่ทำงานได้เร็วด้วย

ผลที่เกิดขึ้นคือ จะทำให้แต่ละจุดของ recovery มีช่วงเวลาที่ห่างกันมากขึ้น และประสิทธิภาพเพิ่มขึ้นเพราะทำให้ลดการ switch log และ checkpoint

สามารถทำงานร่วมกับ LOG_CHECKPOINT_INTERVAL โดย default = 0 คือ switch redo log เมื่อเก็บ data จนเต็มแล้ว สิ่งนี้สำหรับกำหนดระยะเวลาในการทำ checkpoints ซึ่งมีผลกระทบกับระยะห่างของแต่ละ checkpoint ให้น้อยลงหรือมากขึ้นตามค่าที่กำหนดได้เช่นกัน

การ uncommitted transactions (หรือเรียกว่า rollback) จะ generate redo entries เช่นกัน เพราะว่าสิ่งนี้จะมีการ generate undo records และ undo records เหล่านี้ก็จะต้อง write ไปที่ redo logs เช่นกัน

08 May 2020

Tablespace thresholds and alerts

การ monitor เกี่ยวกับการใช้งานพื้นที่ Database แล้วสามารถส่งการแจ้งเตือนได้

การกำหนดเงื่อนไขต่างๆ

- OBJECT_NAME คือ parameter สำหรับกำหนดชื่อของ Tablespace ที่ต้องการ ถ้ากำหนด NULL จะหมายถึงกำหนด thresholds ด้วยค่า default ให้กับทุก Tablespace

- TABLESPACE_PCT_FULL สำหรับกำหนดการแจ้งเตือนของ warning หรือ critical ด้วย threshold แบบ percent full
- TABLESPACE_BYT_FREE สำหรับกำหนดการแจ้งเตือนของ warning หรือ critical ด้วย threshold แบบ bytes free หน่วย KB
      กรณี Cloud Control จะแสดงหน่วย MB

- OPERATOR_LE คือ Less than หรือ equal
- OPERATOR_GE คือ Greater than หรือ equal

การกำหนด Thresholds
จาก https://oracle-base.com/articles/misc/tablespace-thresholds-and-alerts

ที่ tool EM จะแสดง Thresholds ที่ Menu "Metric and Policy Settings" > "Metric Thresholds"
หรือ Menu "All Metrics" ที่หน้าจอเลือก "Tablespaces Full" > "Tablespace Space Used (%)" จะพบ tablespace ต่างๆ เมื่อเลือก tablespace
ที่ต้องการจะเข้าหน้าจอแสดง Tablespace Space Used (%): Tablespace Name ชื่อTablespace: Last 24 hours ที่หน้าจอ Metric Value

SQL> BEGIN
  -- ตัวอย่าง Database-wide KB free threshold
  dbms_server_alert.set_threshold(
    metrics_id              => dbms_server_alert.tablespace_byt_free,
    warning_operator        => dbms_server_alert.operator_le,
    warning_value           => '1024000',
    critical_operator       => dbms_server_alert.operator_le,
    critical_value          => '102400',
    observation_period      => 1,
    consecutive_occurrences => 1,
    instance_name           => NULL,
    object_type             => dbms_server_alert.object_type_tablespace,
    object_name             => NULL);
 
  -- ตัวอย่าง Database-wide percent full threshold
  dbms_server_alert.set_threshold(
    metrics_id              => dbms_server_alert.tablespace_pct_full,
    warning_operator        => dbms_server_alert.operator_ge,
    warning_value           => '85',
    critical_operator       => dbms_server_alert.operator_ge,
    critical_value          => '97',
    observation_period      => 1,
    consecutive_occurrences => 1,
    instance_name           => NULL,
    object_type             => dbms_server_alert.object_type_tablespace,
    object_name             => NULL);

  -- ตัวอย่าง Tablespace-specific KB free threshold
  dbms_server_alert.set_threshold(
    metrics_id              => dbms_server_alert.tablespace_byt_free,
    warning_operator        => dbms_server_alert.operator_le,
    warning_value           => '1024000',
    critical_operator       => dbms_server_alert.operator_le,
    critical_value          => '102400',
    observation_period      => 1,
    consecutive_occurrences => 1,
    instance_name           => NULL,
    object_type             => dbms_server_alert.object_type_tablespace,
    object_name             => 'USERS');
 
  -- ตัวอย่าง Tablespace-specific percent full threshold
  dbms_server_alert.set_threshold(
    metrics_id              => dbms_server_alert.tablespace_pct_full,
    warning_operator        => dbms_server_alert.operator_ge,
    warning_value           => '90',
    critical_operator       => dbms_server_alert.operator_ge,
    critical_value          => '98',
    observation_period      => 1,
    consecutive_occurrences => 1,
    instance_name           => NULL,
    object_type             => dbms_server_alert.object_type_tablespace,
    object_name             => 'USERS');
 
  -- ตัวอย่าง Tablespace-specific reset to defaults
  -- Set warning and critical values to NULL.
  --dbms_server_alert.set_threshold(
  --  metrics_id              => dbms_server_alert.tablespace_pct_full,
  --  warning_operator        => dbms_server_alert.operator_ge,
  --  warning_value           => NULL,
  --  critical_operator       => dbms_server_alert.operator_ge,
  --  critical_value          => NULL,
  --  observation_period      => 1,
  --  consecutive_occurrences => 1,
  --  instance_name           => NULL,
  --  object_type             => dbms_server_alert.object_type_tablespace,
  --  object_name             => 'USERS');
END;
/

แสดง Thresholds
จาก https://oracle-base.com/articles/misc/tablespace-thresholds-and-alerts

ที่ tool EM จะแสดง Thresholds ที่ Menu "Metric and Policy Settings" > "Metric Thresholds"

set linesize 200
column tablespace_name format a30
column metrics_name format a30
column warning_value format a30
column critical_value format a15
SQL> select object_name as tablespace_name,
       metrics_name,
       warning_operator,
       warning_value,
       critical_operator,
       critical_value
from   dba_thresholds
where  object_type = 'TABLESPACE'
order by object_name;
TABLESPACE_NAME                METRICS_NAME                   WARNING_OPER WARNING_VALUE                  CRITICAL_OPE CRITICAL_VALUE
------------------------------ ------------------------------ ------------ ------------------------------ ------------ ---------------
TEMP                           Tablespace Space Usage         DO NOT CHECK    DO_NOT_CHECK 0
UNDOTBS1                       Tablespace Space Usage         DO NOT CHECK    DO_NOT_CHECK 0
UNDOTBS2                       Tablespace Space Usage         DO NOT CHECK    DO_NOT_CHECK 0
USERS                          Tablespace Bytes Space Usage   LE           1024000                        LE           102400
USERS                          Tablespace Space Usage         GE           90                             GE           98
                               Tablespace Space Usage         GE           85                             GE           97
                               Tablespace Bytes Space Usage   LE           1024000                        LE           102400
 
set linesize 200
column metrics_name format a30
column warning_value format a30
column critical_value format a15
SQL> select tablespace_name,
       contents,
       extent_management,
       threshold_type,
       metrics_name,
       warning_operator,
       warning_value,
       critical_operator,
       critical_value
from   dba_tablespace_thresholds
order by tablespace_name;
TABLESPACE_NAME                CONTENTS  EXTENT_MAN THRESHOL METRICS_NAME                   WARNING_OPER WARNING_VALUE                  CRITICAL_OPE CRITICAL_VALUE
------------------------------ --------- ---------- -------- ------------------------------ ------------ ------------------------------ ------------ ---------------
EXAMPLE                        PERMANENT LOCAL      DEFAULT  Tablespace Space Usage         GE           85                             GE           97
EXAMPLE                        PERMANENT LOCAL      DEFAULT  Tablespace Bytes Space Usage   LE           1024000                        LE           102400
SYSAUX                         PERMANENT LOCAL      DEFAULT  Tablespace Space Usage         GE           85                             GE           97
SYSAUX                         PERMANENT LOCAL      DEFAULT  Tablespace Bytes Space Usage   LE           1024000                        LE           102400
SYSTEM                         PERMANENT LOCAL      DEFAULT  Tablespace Bytes Space Usage   LE           1024000                        LE           102400
SYSTEM                         PERMANENT LOCAL      DEFAULT  Tablespace Space Usage         GE           85                             GE           97
TEMP                           TEMPORARY LOCAL      EXPLICIT Tablespace Space Usage         DO NOT CHECK    DO NOT CHECK 0
UNDOTBS1                       UNDO      LOCAL      EXPLICIT Tablespace Space Usage         DO NOT CHECK    DO NOT CHECK 0
USERS                          PERMANENT LOCAL      EXPLICIT Tablespace Bytes Space Usage   LE           1024000                        LE           102400
USERS                          PERMANENT LOCAL      EXPLICIT Tablespace Space Usage         GE           90                             GE           98

แสดง alert ที่เกิดขึ้น

แสดงประวัติของการแจ้งเตือนที่ผ่านมาทั้งหมด ที่กำหนดโดย DBMS_SERVER_ALERT
ที่ tool EM จะแสดงที่ Menu "Alert History"
หรือ Menu "All Metrics" ที่หน้าจอเลือก "Tablespaces Full" > "Tablespace Space Used (%)" จะพบ tablespace ต่างๆ เมื่อเลือก tablespace
ที่ต้องการจะเข้าหน้าจอแสดง Tablespace Space Used (%): Tablespace Name ชื่อTablespace: Last 24 hours ที่หน้าจอ Alert History
SQL> select reason_id, object_name, object_type, reason, time_suggested, suggested_action
from dba_alert_history
where object_name in ('USERS','USERS2');
order by time_suggested desc;
REASON_ID OBJECT_NAME OBJECT_TYPE REASON TIME_SUGGESTED SUGGESTED_ACTION
----------- --------------- -------------------------------------------------------------- ------------------------------------ -----------------------------
9 USERS TABLESPACE Tablespace [USERS] is [70 percent] full 2020-05-12 3:00:00 AM -08:00 Add space to the tablespace
9 USERS2 TABLESPACE Tablespace [USERS2] is [83 percent] full 2020-05-14 4:00:00 PM -08:00 Add space to the tablespace

แสดงการแจ้งเตือนที่กำลังเกิดขึ้นอยู่ทั้งหมด
ที่ tool EM จะแสดงที่หน้า Home ในหน้าจอ "Alert"
SQL> select creation_time, metric_value, message_type, reason, suggested_action
  from dba_outstanding_alerts
 where object_name in ('USERS','USERS2');

01 March 2020

AWR, Snapshot and Baseline for Report

ใน Database จะใช้ AWR (Automatic Workload repository) สำหรับรวบรวมการประมวลผลต่างๆและเก็บสถิติประสิทธิภาพการใช้งาน  แล้วจึงนำมาแสดงสถานะและประสิทธิภาพของ Database ในรูปแบบของ report เพื่อนำไปการตรวจปัญหาต่างๆและ tuning Database ด้วยตนเอง

AWR เก็บรวบรวมข้อมูลดังนี้
- Object Statistics (สถิติการ access และ usage ของ Database segments)
- Time Model Statistics (V$SYS_TIME_MODEL และ V$SESS_TIME_MODEL)
- Some of the System and Session Statistics (V$SYSSTAT และ V$SESSTAT)
- ASH (Active Session History) Statistics
- High load generating SQL Statements

Components ต่างๆของ AWR
- Automatic Database Diagnostic Monitor
- Undo Advisor
- SQL Tuning Advisor
- Segment Advisor

Snapshots
- การ snapshot ในแต่ละอัน คือ เริ่ม snapshot (BEGIN_INTERVAL_TIME) และทำการเก็บค่าต่างๆ และจบการ snapshot (END_INTERVAL_TIME)
                     SNAPSHOT1             SNAPSHOT2                 SNAPSHOT3
เริ่มSnapshot SNAPSHOT_INTERVAL จบSnapshot --> เริ่มSnapshot SNAPSHOT_INTERVAL จบSnapshot --> เริ่มSnapshot SNAPSHOT_INTERVAL จบSnapshot

- ถ้าช่วงระยะห่างของ start ถึง end time ของการ snapshot มีค่าน้อยจะเก็บรายละเอียดได้มากกว่ามีค่ามาก เพราะค่าน้อยจะเกิดการ snapshot บ่อยกว่า จึงมีข้อมูลเก็บไว้หลากหลายกว่า ทำให้วิเคราะห์ได้ละเอียดกว่า แต่การ snapshot จำนวนมาก ก็จะต้องการพื้นที่และกระทบกับการทำงานของระบบมากกว่า
 การพิจารณาว่าจะกำหนดช่วงให้ห่างกันเท่าไร ให้ดูจากถ้าช่วงไหนมีปัญหาบ่อย ก็ให้กำหนดช่วงสั้นๆ เพื่อให้หาสาเหตุได้ง่ายขึ้น แต่พอแก้ไขปัญหาแล้วระบบทำงานปกติ ก็ให้กำหนดช่วงยาวๆแทน
   เช่น
    ตัวอย่าง
จำนวน session ในแต่ละช่วงเวลา
2020/01/01 00:00 = 1
2020/01/01 01:00 = 10
2020/01/01 02:00 = 20
...
....
.....
2020/01/01 22:00 = 220
2020/01/01 23:00 = 230
2020/01/02 00:00 = 240
 
กรณี snap ทุกๆ 1 ชม
SNAP_ID BEGIN_INTERVAL_TIME END_INTERVAL_TIME  
---------- ------------------- -------------------
24  2020/01/01 23:00:00 2020/01/02 00:00:00
23  2020/01/01 22:00:00 2020/01/01 23:00:00
22  2020/01/01 21:00:00 2020/01/01 22:00:00
....                                       
......                                     
........ 
5   2020/01/01 02:00:00 2020/01/01 05:00:00
4   2020/01/01 02:00:00 2020/01/01 04:00:00
3   2020/01/01 02:00:00 2020/01/01 03:00:00
2   2020/01/01 01:00:00 2020/01/01 02:00:00
1   2020/01/01 00:00:00 2020/01/01 01:00:00
กรณี snap ทุกๆ 6 ชม
SNAP_ID BEGIN_INTERVAL_TIME END_INTERVAL_TIME  
---------- ------------------- -------------------
4   2020/01/01 18:00:00 2020/01/02 00:00:00
3   2020/01/01 12:00:00 2020/01/01 18:00:00
2   2020/01/01 06:00:00 2020/01/01 12:00:00
1   2020/01/01 00:00:00 2020/01/01 06:00:00
ตัวอย่าง 1 ต้องการหาการเปลี่ยนแปลงจำนวน sessions ในช่วงเวลา 2020/01/01 01:00:00 - 2020/01/01 05:00:00 กรณี snap ทุกๆ 1 ชม SNAP_ID 1 มีจำนวน session Begin ถึง End = 1 ถึง 10 SNAP_ID 2 มีจำนวน session Begin ถึง End = 10 ถึง 20 SNAP_ID 3 มีจำนวน session Begin ถึง End = 20 ถึง 30 SNAP_ID 4 มีจำนวน session Begin ถึง End = 30 ถึง 40 SNAP_ID 5 มีจำนวน session Begin ถึง End = 40 ถึง 50 กรณี snap ทุกๆ 6 ชม SNAP_ID 1 มีจำนวน session Begin ถึง End = 1 ถึง 60 SNAP_ID 2 มีจำนวน session Begin ถึง End = 60 ถึง 120 จะเห็นว่า snap ทุกๆ 1 ชม แสดง report (จะใช้ค่า End) = 10 ถึง 50 ได้ค่าที่ตรงกับความเป็นจริงมากกว่า snap ทุกๆ 6 ชม แสดง report (จะใช้ค่า End) = 60 ถึง 120 ตัวอย่าง 2 ต้องการหาการเปลี่ยนแปลงจำนวน sessions ในช่วงเวลา 2020/01/01 02:00:00 - 2020/01/01 03:00:00 กรณี snap ทุกๆ 1 ชม SNAP_ID 2 มีจำนวน session Begin ถึง End = 10 ถึง 20 SNAP_ID 3 มีจำนวน session Begin ถึง End = 20 ถึง 30 กรณี snap ทุกๆ 6 ชม มี SNAP_ID = 1 SNAP_ID 1 มีจำนวน session Begin ถึง End = 1 ถึง 60 SNAP_ID 2 มีจำนวน session Begin ถึง End = 60 ถึง 120 จะเห็นว่า snap ทุกๆ 1 ชม แสดง report (จะใช้ค่า End) = 20 ถึง 30 ได้ค่าที่ตรงกับความเป็นจริงมากกว่า snap ทุกๆ 6 ชม แสดง report (จะใช้ค่า End) = 60 ถึง 120

- การเกิดใหม่ของ Snapshot หรือ SNAP_ID ตัวใหม่ ใน DBA_HIST_SNAPSHOT เมื่อ snapshot เริ่มต้นทำงาน คือ เกิด BEGIN_INTERVAL_TIME โดยจะยังไม่มีข้อมูลใน DBA_HIST_SNAPSHOT จนกว่าจะจบการทำงาน คือ เกิด END_INTERVAL_TIME หรือเรียกว่า จบการ snapshot
- ค่า default คือ ทำการ snapshot ทุกๆ 1 ชม (INTERVAL)  และเก็บรักษา snapshot เอาไว้ 8 วัน (RETENTION)
- สำหรับการออก report
  การกำหนดช่วงของ snapshot จะแสดง report นับจาก snap ID เริ่มต้น ถึง snap ID สิ้นสุด โดยใช้ END_INTERVAL_TIME แสดงว่าถ้าต้องการกำหนด snapshot ในช่วงเวลาใดๆต้องดูจากระยะ END_INTERVAL_TIME
  เช่น
 DBA_HIST_SNAPSHOT
    SNAP_ID       DBID INSTANCE_NUMBER BEGIN_INTERVAL_TIME END_INTERVAL_TIME  
 ---------- ---------- --------------- ------------------- -------------------
        86 1256122414               1 2020/09/10 14:00:54 2020/09/10 15:00:28
        85 1256122414               1 2020/09/10 13:00:25 2020/09/10 14:00:54
        84 1256122414               1 2020/09/10 12:00:51 2020/09/10 13:00:25
        83 1256122414               1 2020/09/10 10:35:05 2020/09/10 12:00:51
        82 1256122414               1 2020/09/09 18:00:04 2020/09/10 10:35:05
        81 1256122414               1 2020/09/09 17:00:32 2020/09/09 18:00:04
        80 1256122414               1 2020/09/09 16:27:05 2020/09/09 17:00:32
  ต้องการ report ช่วงเวลา 2020/09/09 17:00 ถึง 2020/09/10 15:00 จะต้องเลือก start snapshot = 80 และ end snapshot = 86
  โดย report จะแสดง Begin Snap = 17:00:32 และ End Snap = 15:00:28

RETENTION หรือ RETENTION_INTERVAL (ระยะการเก็บรักษา)
- คือ ช่วงเวลาหน่วยนาทีในการเก็บรักษา history เอาไว้
- ระบุค่าต่างๆ
ค่าเป็นตัวเลข ค่าที่ระบุต้องอยู่ในช่วง MIN_RETENTION (1 วัน) ถึง MAX_RETENTION (100 ปี)
ค่า 0 คือ Snapshot จะเก็บรักษาไว้ตลอดไป ค่าที่ระบบกำหนดส่วนมากจะใช้เป็นการตั้งค่าการเก็บข้อมูล
ค่า NULL คือ Snapshot ค่าเดิมจะถูกรักษาไว้

INTERVAL หรือ  SNAPSHOT_INTERVAL (ระยะ snapshot)
- คือ ช่วงระยะห่างของเวลาเริ่มต้นและสิ้นสุดของแต่ล่ะ Snapshot หน่วยนาที หรือเรียกว่า ในแต่ละ snapshot จะเริ่มเก็บจนหยุดเก็บใช้เวลาเท่าไร
- ระบุค่าต่างๆ
ค่าเป็นตัวเลข ค่าที่ระบุต้องอยู่ในช่วง MIN_INTERVAL (10 นาที) ถึง MAX_INTERVAL (1 ปี)
ค่า 0 คือ ทำการ Snapshot แบบ auto โดยการทำงาน Snapshot ในแบบ manual จะถูกปิดใช้งานการรวบรวมสถิติทั้งหมด ค่าที่ระบบกำหนดส่วนมากจะใช้เป็นการตั้งค่าการเก็บข้อมูล
ค่า NULL คือ Snapshot ค่าปัจจุบันจะถูกรักษาไว้

TOPNSQL
- ระบุค่าเป็นตัวเลข 
- คือ จำนวนสูงสุดของ SQL ที่จะ flush ข้อมูลของแต่ละ  criteria (Elapsed Time, CPU Time, Parse Calls, Shareable Memory, และ Version Count)
- จะไม่กระทบกับ statistics และ flush level แต่จะแทนที่ค่า system default ของ AWR SQL collection
- การตั้งค่าจะมีดังนี้
ค่าเป็นตัวเลข กำหนดได้ต่ำสุด 30 และสูงสุด 50000
NULL จะคงการตั้งค่าปัจจุบันไว้
- ระบุค่าเป็น varchar(2)
- การตั้งค่าจะมีดังนี้
MAXIMUM ทำการ capture SQL ใน cursor cache แบบสมบูรณ์
ค่าเป็นตัวเลข กำหนดได้ต่ำสุด 30 และสูงสุด 50000
DEFAULT กำหนดค่าแบบ default คือ top 30 สำหรับ statistics level แบบ TYPICAL และ top 100 สำหรับ statistics level แบบ ALL
NULL จะคงการตั้งค่าปัจจุบันไว้nt will keep the current setting.

- Criteria 14 อัน ใน AWR report และ Oracle AWR จะ capture ใน top-n-SQL ของแต่ละ criteria จาก http://www.dba-oracle.com/t_awr_automatic_snapshot_settings_modify.htm
1.Elapsed Time (ms)
2.CPU Time (ms)
3.Executions
4.Buffer Gets
5.Disk Reads
6.Parse Calls
7.Rows
8.User I/O Wait Time (ms)
9.Cluster Wait Time (ms)
10.Application Wait Time (ms)
11.Concurrency Wait Time (ms)
12.Invalidations
13.Version Count
14.Sharable Mem(KB)

แสดงเวลาของการ snapshot
- BEGIN_INTERVAL_TIME คือ เวลาที่เริ่ม snapshot
- END_INTERVAL_TIME คือ เวลาที่จบ snapshot
- BEGIN_INTERVAL_TIME ถึง END_INTERVAL_TIME ระยะเวลาจะห่างกันตามค่า SNAPSHOT_INTERVAL

คำสั่ง modify snapshot settings
dbms_workload_repository.modify_snapshot_settings(
   retention   in  number    default null,
   interval    in  number    default null,
   topnsql     in  number    default null,
   dbid        in  number    default null);

คำสั่ง taken snapshot
exec dbms_workload_repository.create_snapshot;

คำสั่ง removed snapshot
begin
  dbms_workload_repository.drop_snapshot_range (
    low_snap_id  => 22,
    high_snap_id => 32);
end;


แสดงค่าจำนวน วัน ชม นาที วินาที ของ SNAPSHOT_INTERVAL และ RETENTION_INTERVAL

ตัวอย่าง ทำการ snapshot ทุกๆ 1 ชม และเก็บรักษา snapshot เอาไว้ 8 วัน

รูปแบบของ SNAP_INTERVAL และ RETENTION คือ +วัน ชม:นาที:วินาที
SQL> select dbid,snap_interval,retention,topnsql from dba_hist_wr_control;
      DBID SNAP_INTERVAL         RETENTION            TOPNSQL 
---------- --------------------- -------------------- ----------
1550490185 +00 01:00:00.000000   +08 00:00:00.000000  DEFAULT 
หรือ
SNAPSHOT_INTERVAL_SEC และ RETENTION_INTERVAL_SEC หน่วยคือ seconds
set linesize 1000
SQL> select
(' Total='||trunc(wrcon.snapshot_interval_sec/60/60/24) || 'Day '
||to_char(trunc(MOD(wrcon.snapshot_interval_sec/60/60,24)),'fm9900')||':'||to_char(trunc(MOD(wrcon.snapshot_interval_sec,3600)/60),'fm00')||':'||to_char(MOD(MOD(wrcon.snapshot_interval_sec,3600),60),'fm00')
)snapshot_interval
,(' Total='||trunc(wrcon.retention_interval_sec/60/60/24) || 'Day '
||to_char(trunc(MOD(wrcon.retention_interval_sec/60/60,24)),'fm9900')||':'||to_char(trunc(MOD(wrcon.retention_interval_sec,3600)/60),'fm00')||':'||to_char(MOD(MOD(wrcon.retention_interval_sec,3600),60),'fm00')
)retention_interval
from
(select (extract(day from snap_interval) *24*60+extract(hour from snap_interval) *60+extract(minute from snap_interval))*60 snapshot_interval_sec
,(extract(day from retention) *24*60+extract(hour from retention) *60+extract(minute from retention))*60 retention_interval_sec
from dba_hist_wr_control)wrcon;
SNAPSHOT_INTERVAL         RETENTION_INTERVAL                                           
------------------------- ----------------------
Total=0Day 01:00:00       Total=8Day 00:00:00

แสดงค่าจำนวน นาที ของ SNAPSHOT_INTERVAL และ RETENTION_INTERVAL (เป็นค่าที่ set ใน parameter)
SQL> select extract(day from snap_interval) *24*60+extract(hour from snap_interval) *60+extract(minute from snap_interval) snapshot_interval,
extract(day from retention) *24*60+extract(hour from retention) *60+extract(minute from retention) retention_interval
from dba_hist_wr_control;
SNAPSHOT_INTERVAL RETENTION_INTERVAL
----------------- ------------------
               60              11520

แสดง detail snapshot ทั้งหมดที่มีอยู่
SQL> select sn.snap_id,sn.dbid,sn.instance_number
--,sn.startup_time
,to_char(sn.begin_interval_time,'yyyy/mm/dd hh24:mi:ss')begin_interval_time
,to_char(sn.end_interval_time,'yyyy/mm/dd hh24:mi:ss')end_interval_time
from dba_hist_snapshot sn
where to_char(sn.begin_interval_time,'yyyy/mm/dd hh24:mi:ss') >= '2018/07/05 00:00:00' and to_char(sn.end_interval_time,'yyyy/mm/dd hh24:mi:ss') <= '2018/07/05 06:00:00'
order by sn.begin_interval_time desc,sn.end_interval_time desc
;
   SNAP_ID       DBID INSTANCE_NUMBER STARTUP_TIME                BEGIN_INTERVAL_TIME END_INTERVAL_TIME
---------- ---------- --------------- --------------------------- ------------------- -------------------
      6551 1550490185               1 6/7/2018 5:25:17.000 PM     2018/07/05 04:00:08 2018/07/05 05:00:39
      6550 1550490185               1 6/7/2018 5:25:17.000 PM     2018/07/05 03:00:44 2018/07/05 04:00:08
      6549 1550490185               1 6/7/2018 5:25:17.000 PM     2018/07/05 02:00:07 2018/07/05 03:00:44
      6548 1550490185               1 6/7/2018 5:25:17.000 PM     2018/07/05 01:00:45 2018/07/05 02:00:07
      6547 1550490185               1 6/7/2018 5:25:17.000 PM     2018/07/05 00:00:38 2018/07/05 01:00:45


แสดง summary snapshot ทั้งหมดที่มีอยู่
SQL> select min(sn.snap_id)min_snap_id,max(sn.snap_id)max_snap_id
,min(to_char(sn.begin_interval_time,'yyyy/mm/dd hh24:mi:ss'))min_begin_interval_time
--,max(to_char(sn.begin_interval_time,'yyyy/mm/dd hh24:mi:ss'))max_begin_interval_time
--,min(to_char(sn.end_interval_time,'yyyy/mm/dd hh24:mi:ss'))min_end_interval_time
,max(to_char(sn.end_interval_time,'yyyy/mm/dd hh24:mi:ss'))max_end_interval_time
,count(sn.snap_id)count_snap
from dba_hist_snapshot sn
where to_char(sn.begin_interval_time,'yyyy/mm/dd hh24:mi:ss') >= '2018/07/05 00:30:00' and to_char(sn.end_interval_time,'yyyy/mm/dd hh24:mi:ss') <= '2018/07/05 03:30:00'
;
MIN_SNAP_ID MAX_SNAP_ID MIN_BEGIN_INTERVAL_TIME MAX_END_INTERVAL_TIME COUNT_SNAP
----------- ----------- ----------------------- --------------------- ----------
      42606       42610 2018/07/05 00:30:20     2018/07/05 03:00:27           10

Snapshots settings

Set STATISTICS_LEVEL เป็นการกำหนดจำนวนของ SQL statements ที่จะทำการ captured ดูเพิ่มเติมจาก Document "ORACLE_TUNING_Statistics Level.txt"
SQL> alter system set statistics_level=typical;
หรือ
SQL> alter system set statistics_level=all;

Modify snapshot settings
ตัวอย่าง snapshot ทุกๆ 10 นาที และเก็บ history เป็นเวลา 3 ปี
SQL> execute dbms_workload_repository.modify_snapshot_settings (interval => 10,retention => 1576800);
หรือ กำหนดค่าเหมือนค่า default คือ snapshot ทุกๆชม. และเก็บ history เป็นเวลา 7 วัน
SQL> execute dbms_workload_repository.modify_snapshot_settings (interval => 60,retention => 10080);

Baselines
- เป็นการสร้าง snapshot ในช่วงเวลาใดๆก็ได้ที่ต้องการใช้เป็นตัวนำไปเปรียบเทียบกับตัวอื่นๆ
   เช่น ช่วงเวลา 08.00 น. ระบบจะทำงานช้ามาก จึงนำช่วงนี้มาสร้างเป็น baseline ชื่อ SYSTEM_CRITICAL เพื่อนำไปเทียบกับ snapshot อื่นๆที่ทำงานช้า ว่ามี metrics แตกต่างจาก SYSTEM_CRITICAL อย่างไร
         ช่วงเวลา 12.00 น. ระบบจะทำงานเป็นปกติ จึงนำช่วงนี้มาสร้างเป็น baseline ชื่อ SYSTEM_NORMAL เพื่อนำไปเทียบกับ snapshot อื่นๆที่ทำงานช้า ว่ามี metrics แตกต่างจาก SYSTEM_NORMAL อย่างไร

แสดง Baseline
set linesize 1000
SQL> select bl.dbid,bl.baseline_id,bl.baseline_name,bl.baseline_type
,bl.start_snap_id,bl.end_snap_id
,bl.start_snap_time,bl.end_snap_time
,bl.moving_window_size
from dba_hist_baseline bl;
      DBID BASELINE_ID BASELINE_NAME                 BASELINE_TYPE START_SNAP_ID END_SNAP_ID START_SNAP_TIME                    END_SNAP_TIME                    MOVING_WINDOW_SIZE
---------- ----------- ----------------------------- ------------- ------------- ----------- ---------------------------------- -------------------------------- ------------------
1550490185           1 SYSTEM_NORMAL                 STATIC                 6000        6010 6/12/2018 6:00:21.094 AM           6/12/2018 4:00:49.560 PM                         
1550490185           2 SYSTEM_CRITICAL               STATIC                 5993        5999 6/11/2018 11:00:59.064 PM          6/12/2018 5:00:20.522 AM                         
1550490185           0 SYSTEM_MOVING_WINDOW          MOVING_WINDOW          6006        6197 6/12/2018 12:00:52.653 PM          6/20/2018 11:00:10.618 AM                         8


Create baseline
SQL> begin
  dbms_workload_repository.create_baseline (
    start_snap_id => 210,
    end_snap_id   => 220,
    baseline_name => 'mybaseline_batch_workingday');
end;
/

Delete baseline
SQL> begin
  dbms_workload_repository.drop_baseline (
    baseline_name => 'mybaseline_batch_workingday',
    cascade       => FALSE); -- Deletes associated snapshots if TRUE.
end;
/

การสร้าง AWR Report ด้วย AWR Scripts

AWR Report
--> sqlplus / as sysdba @$ORACLE_HOME/rdbms/admin/awrrpt.sql
SQL*Plus: Release 12.2.0.1.0 Production on Tue Jan 22 12:06:52 2019
Copyright (c) 1982, 2016, Oracle.  All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

Specify the Report Type
~~~~~~~~~~~~~~~~~~~~~~~
AWR reports can be generated in the following formats. Please enter the
name of the format at the prompt.  Default value is 'html'.

'html' HTML format (default)
'text' Text format
'active-html' Includes Performance Hub active report

Enter value for report_type: html
old   1: select 'Type Specified: ',lower(nvl('&&report_type','html')) report_type from dual
new   1: select 'Type Specified: ',lower(nvl('html','html')) report_type from dual

Type Specified:  กำหนดประเภทรายงาน --> html

old   1: select '&&report_type' report_type_def from dual
new   1: select 'html' report_type_def from dual

old   1: select '&&view_loc' view_loc_def from dual
new   1: select 'AWR_PDB' view_loc_def from dual

Current Instance
~~~~~~~~~~~~~~~~
DB Id        DB Name       Inst Num      Instance     Container Name
-------------- -------------- -------------- -------------- --------------
 1186862925 DBTEST1      1 dbtest1      dbtest1

Instances in this Workload Repository schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  DB Id      Inst Num DB Name      Instance   Host
------------ ---------- ---------    ----------   ------
* 1186862925  1 DBTEST1      dbtest1   oradb12c.loc

Using 1186862925 for database Id
Using        1 for instance number

Specify the number of days of snapshots to choose from
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Entering the number of days (n) will result in the most recent
(n) days of snapshots being listed.  Pressing without
specifying a number lists all completed snapshots.

Enter value for num_days: กำหนดจำนวนวัน --> 5

Listing the last 5 days of Completed Snapshots
Instance     DB Name   Snap Id Snap Started Snap Level
------------ ------------ ---------- ------------------ ----------
dbtest1      DBTEST1 429  21 Jan 2019 21:04   1
430  21 Jan 2019 21:15   1
431  21 Jan 2019 21:30   1
432  21 Jan 2019 21:45   1
....
......
...........
452  22 Jan 2019 02:45   1
453  22 Jan 2019 03:00   1
454  22 Jan 2019 03:15   1
455  22 Jan 2019 03:30   1
....
......
...........
489  22 Jan 2019 12:00   1
490  22 Jan 2019 12:15   1
491  22 Jan 2019 12:30   1

Specify the Begin and End Snapshot Ids
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter value for begin_snap: กำหนดSnapIDเริ่มต้น --> 429
Begin Snapshot Id specified: 429

Enter value for end_snap: กำหนดSnapIDสิ้นสุด --> 489
End   Snapshot Id specified: 489

Specify the Report Name
~~~~~~~~~~~~~~~~~~~~~~~
The default report file name is awrrpt_1_429_489.html. To use this name,
press to continue, otherwise enter an alternative.

Enter value for report_name: กำหนดReportName --> awr_20190121to20190122

Using the report name awr_20190121to20190122
.......
...........
...............

End of Report

Report written to awr_20190121to20190122

จะได้ AWR Report file
--> ls -lrt
total 884
-rw-r--r--. 1 oracle oinstall 902197 Jan 22 12:08 awr_20190121to20190122.lst

Transfer awr_20190121to20190122.lst ไปที่ Local PC และแก้ไข file จาก .lst เป็น .html
และ open ด้วย Browser Tool จะสามารถดู AWR ได้

Compare Two AWR Reports

--> sqlplus / as sysdba @$ORACLE_HOME/rdbms/admin/awrddrpt.sql
SQL*Plus: Release 12.2.0.1.0 Production on Tue Jan 22 12:40:29 2019
Copyright (c) 1982, 2016, Oracle.  All rights reserved.

Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

Specify the Report Type
~~~~~~~~~~~~~~~~~~~~~~~
Would you like an HTML report, or a plain text report?
Enter 'html' for an HTML report, or 'text' for plain text
Defaults to 'html'
Enter value for report_type: html
old   1: select 'Type Specified: ',lower(nvl('&&report_type','html')) report_type from dual
new   1: select 'Type Specified: ',lower(nvl('html','html')) report_type from dual

Type Specified: กำหนดประเภทรายงาน --> html

old   1: select '&&report_type' report_type_def from dual
new   1: select 'html' report_type_def from dual

old   1: select '&&view_loc' view_loc_def from dual
new   1: select 'AWR_PDB' view_loc_def from dual

Current Instance
~~~~~~~~~~~~~~~~
old   1: select (case when '&view_loc' = 'AWR_PDB'
new   1: select (case when 'AWR_PDB' = 'AWR_PDB'

old   1: select &default_dbid   dbid
new   1: select 1186862925     dbid
old   2:      , &default_dbid   dbid2
new   2:      , 1186862925     dbid2

   DB Id       DB Id DB Name      Inst Num Inst Num Instance
----------- ----------- ------------ -------- -------- ------------
 1186862925  1186862925 DBTEST1      1      1 dbtest1

Instances in this Workload Repository schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  DB Id      Inst Num DB Name      Instance   Host
------------ ---------- ---------    ----------   ------
* 1186862925  1 DBTEST1      dbtest1   oradb12c.loc

Database Id and Instance Number for the First Pair of Snapshots
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using 1186862925 for Database Id for the first pair of snapshots
Using        1 for Instance Number for the first pair of snapshots

Specify the number of days of snapshots to choose from
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Entering the number of days (n) will result in the most recent
(n) days of snapshots being listed.  Pressing without
specifying a number lists all completed snapshots.

Enter value for num_days: กำหนดจำนวนวันของFirst --> 2

Listing the last 2 days of Completed Snapshots
Instance     DB Name   Snap Id Snap Started Snap Level
------------ ------------ ---------- ------------------ ----------
dbtest1      DBTEST1 429  21 Jan 2019 21:04   1
          430  21 Jan 2019 21:15   1
431  21 Jan 2019 21:30   1
432  21 Jan 2019 21:45   1
....
......
...........
452  22 Jan 2019 02:45   1
453  22 Jan 2019 03:00   1
454  22 Jan 2019 03:15   1
455  22 Jan 2019 03:30   1
....
......
...........
489  22 Jan 2019 12:00   1
490  22 Jan 2019 12:15   1
491  22 Jan 2019 12:30   1

Specify the First Pair of Begin and End Snapshot Ids
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter value for begin_snap: กำหนดSnapIDเริ่มต้นของFirst --> 429
First Begin Snapshot Id specified: 429

Enter value for end_snap: กำหนดSnapIDสิ้นสุดของFirst --> 440
First End   Snapshot Id specified: 440

Instances in this Workload Repository schema
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  DB Id      Inst Num DB Name      Instance   Host
------------ ---------- ---------    ----------   ------
* 1186862925  1 DBTEST1      dbtest1   oradb12c.loc

Database Id and Instance Number for the Second Pair of Snapshots
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Using 1186862925 for Database Id for the second pair of snapshots
Using        1 for Instance Number for the second pair of snapshots

Specify the number of days of snapshots to choose from
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Entering the number of days (n) will result in the most recent
(n) days of snapshots being listed.  Pressing without
specifying a number lists all completed snapshots.

Enter value for num_days2: กำหนดจำนวนวันของSecond --> 2

Listing the last 2 days of Completed Snapshots
                                429  21 Jan 2019 21:04   1
430  21 Jan 2019 21:15   1
431  21 Jan 2019 21:30   1
432  21 Jan 2019 21:45   1
....
......
...........
452  22 Jan 2019 02:45   1
453  22 Jan 2019 03:00   1
454  22 Jan 2019 03:15   1
455  22 Jan 2019 03:30   1
....
......
...........
489  22 Jan 2019 12:00   1
490  22 Jan 2019 12:15   1
491  22 Jan 2019 12:30   1

Specify the Second Pair of Begin and End Snapshot Ids
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Enter value for begin_snap2: กำหนดSnapIDเริ่มต้นของSecond -->  441
Second Begin Snapshot Id specified: 441

Enter value for end_snap2: กำหนดSnapIDสิ้นสุดของSecond --> 491
Second End   Snapshot Id specified: 491

Specify the Report Name
~~~~~~~~~~~~~~~~~~~~~~~
The default report file name is awrdiff_1_429_1_441.html  To use this name,
press to continue, otherwise enter an alternative.

Enter value for report_name: กำหนดReportName --> awr_20190121compare20190122

Using the report name awr_20190121compare20190122
.......
.............
.................


Report written to awr_20190121compare20190122

จะได้ AWR Report file
--> ls -lrt
total 1192
-rw-r--r--. 1 oracle oinstall 1217225 Jan 22 12:42 awr_20190121compare20190122.lst

Transfer awr_20190121compare20190122.lst to Local PC และแก้ไข file จาก .lst เป็น .html
และ open ด้วย Browser Tool จะสามารถดู AWR ได้

การสร้าง AWR Report ด้วย SQL Developer

เปิดใช้งานเครื่องมือสำหรับ DBA
Menu View > DBA

จะเห็นหน้าจอ DBA และไปที่ Menu Performance > AWR
จะเห็นรูปแบบรายงานดังนี้
AWR Report Viewer สำหรับออกรายงาน AWR อันเดียว
Difference Report Viewer สำหรับออกรายงาน AWR สองอัน แล้วนำมาเปรียบเทียบกัน
SQL Report Viewer สำหรับออกรายงาน SQL อันเดียว

การกำหนดช่วงของ snapshot จะแสดง report นับจาก snap ID เริ่มต้น ถึง snap ID สิ้นสุด โดยใช้ END_INTERVAL_TIME