Friday, 31 July 2009

เราจะย้ายไปที่ Blog.Oracle.in.Th(ai)

ช่วงหลายเดือนที่ผ่านมา มีข่าวใหญ่ในวงการ IT คือเรื่องการควบรวมกิจการระหว่าง Oracle กับ Sun
ถึงแม้ปัจจุบันรายละเอียดขั้นตอนในเชิงลึกยังไม่เรียบร้อยดีก็ตาม แต่ deal นี้คงไม่มีข้อผิดพลาดอะไรอีกแล้ว

Sun เป็นผู้ให้กำเนิด Java Platform ซึ่งเป็นส่วนหนึ่งที่ Blog แห่งนี้ให้ความสำคัญ
แต่ถัดจากนี้ไป Java Platform ก็จะถือเป็นส่วนหนึ่งของ Oracle จะถือเป็นอีกหนึ่งภาษาที่ Oracle มีอยู่ในครอบครอง นอกเหนือจาก PL/SQL ที่ Oracle สร้างมาเองกับมือ

ดังนั้น Blog นี้ ที่เคยให้ชื่อว่า Oracle and Java Blog ก็คงจะกลายเป็นเพียงแค่ Oracle Blog เท่านั้น
เพราะนิยามชื่อ Oracle ก็จะรวมถึงทุกอย่างภายใต้อาณาจักรของ Oracle, รวมถึง Java Platform ด้วย

ในที่สุดจากชื่อ Blog ที่จะเปลี่ยนไปเหลือเพียงแค่ Oracle Blog, ในเมื่อมีการเปลี่ยนแปลงทั้งที
ดังนั้นทีมงานของ Blog แห่งนี้จึงต้องการปรับเปลี่ยนโครงสร้างหลาย ๆ อย่าง

การปรับเปลี่ยนที่สำคัญอีกอย่างที่จะตามมาก็คือ เราจะย้าย URL จาก http://blog.middleware.co.th ไปเป็น http://blog.oracle.in.th เพื่อให้เห็น scope ที่ชัดเจน ในสิ่งที่เราสนใจ

ถัดจากนี้ไป contents ใหม่ ๆ เราจะ update ที่ http://blog.oracle.in.th
ส่วน contents เก่า ๆ ที่ดี ๆ เราจะค่อย ๆ ทยอยย้ายไป

ขอให้ผู้ที่ติดตาม Blog นี้ ตามเราไปยังที่ http://blog.oracle.in.th เพื่อดูความเปลี่ยนแปลงถัดจากนี้ไปครับ

Thursday, 9 July 2009

Oracle nologging ไม่สร้าง redo log จริงหรือ

nologging ไม่ได้หมายถึง ไม่มีการสร้าง redo log ในการทำงานทุกอย่างบน object นั้น
nologging จะมีการสร้าง redo log น้อยที่สุดเช่นส่วนของ data dictionary
nologging สามารถทำได้ในระดับ table หรือ tablespace ก็ได้

nologging นั้นจะทำงาน ต้องขึ้นกับบางสถานการณ์เท่านั้น
- DIRECT LOAD (SQL*Loader)
- DIRECT LOAD INSERT (using APPEND hint)
- CREATE TABLE ... AS SELECT
- CREATE INDEX
- ALTER TABLE MOVE
- ALTER TABLE ... MOVE PARTITION
- ALTER TABLE ... SPLIT PARTITION
- ALTER TABLE ... ADD PARTITION (if HASH partition)
- ALTER TABLE ... MERGE PARTITION
- ALTER TABLE ... MODIFY PARTITION, ADD SUBPARTITON, COALESCE SUBPARTITON, REBUILD UNUSABLE INDEXES
- ALTER INDEX ... SPLIT PARTITION
- ALTER INDEX ... REBUILD
- ALTER INDEX ... REBUILD PARTITION

nologging นั้นอาจจะเป็นปัญหากับการ recovery และเป็นปัญหากับ flashback database อย่างแน่นอน (เมื่อ alter table... nologging แล้วทำงานเรียบร้อย ก็ควรจะ alter table... logging)

บางครั้งเราอาจต้องการ insert append หรือ create table และต้องการหลีกเลี่ยงการสร้าง redo log ที่มากๆ
บน database ARCHIVELOG Mode, object นั้นต้องถูกกำหนดเป็น nologging เสียก่อน แต่ใน database NOARCHIVELOG Mode, ไม่ต้องกำหนด nologging ที่ object

ตัวอย่างการสร้าง TABLE:
ขอยกscript ในการเช็ค redo size
Script:

--new.sql
column OLD_VALUE new_value OLD_VALUE
select value OLD_VALUE
from v$mystat, v$statname
where v$mystat.statistic# = v$statname.statistic#
and v$statname.name = 'redo size';

--diff.sql
select (value - &OLD_VALUE) OLD_VALUE
from v$mystat, v$statname
where v$mystat.statistic# = v$statname.statistic#
and v$statname.name = 'redo size';

ARCHIVELOG Mode:
SQL> @begin

OLD_VALUE
----------
0

SQL> create table T_NOLOG nologging as select * from all_objects;

Table created.

SQL> @diff
old 1: select (value - &OLD_VALUE) OLD_VALUE
new 1: select (value - 0) OLD_VALUE

OLD_VALUE
----------
133120

REDO SIZE=133120

SQL> @begin

OLD_VALUE
----------
133120

SQL> create table T_LOG logging as select * from all_objects;

Table created.

SQL> @diff
old 1: select (value - &OLD_VALUE) OLD_VALUE
new 1: select (value - 133120) OLD_VALUE

OLD_VALUE
----------
8748596

REDO SIZE=8748596

จะเห็นว่ามีการสร้าง redo log ที่น้อยมากกับ create table ... nologging

NOARCHIVELOG Mode:

SQL> @begin

OLD_VALUE
----------
0

SQL> create table T_NOLOG nologging as select * from all_objects;

Table created.

SQL> @diff
old 1: select (value - &OLD_VALUE) OLD_VALUE
new 1: select (value - 0) OLD_VALUE

OLD_VALUE
----------
109020

SQL> @begin

OLD_VALUE
----------
109020

SQL> create table T_LOG logging as select * from all_objects;

Table created.

SQL> @diff
old 1: select (value - &OLD_VALUE) OLD_VALUE
new 1: select (value - 109020) OLD_VALUE

OLD_VALUE
----------
106360
ในกรณี no archivelog mode... ไม่จำเป็นต้องระบุว่าเป็น nologging...
insert... as... select ถ้าใช้ nologging เข้ามาช่วย (บวก /*+ append */ ด้วย) ก็อาจทำให้เร็วขึ้น
จะเห็นว่าบางครั้ง nologging อาจะมีประโยชน์...

แต่ทั้งนั้น ทั้งนี้ เราควร alter table... logging และ backup เพื่อไม่ให้เกิดปัญหากับการ recovery

by surachart

Sunday, 7 June 2009

Bind variables บน Sql statements ดีอย่างไร



นั่นเป็นคำถามที่บ่อยครั้งที่เราอาจจะต้องตอบ เมื่อเราบอกผู้พัฒนาโปรแกรม ให้ใช้ Bind variables บน Sql statements และ PL/SQL

Oracle SQL statements ทั้งหมดที่มีการเรียกใ ช้ครั้งแรก จะถูกการ parsing ก่อนที่จะมีการ execute 

การ Parsing นั้นจะประกอบด้วยการ เช็ค syntax, เช็คความแตกต่างของตัวอักษร และอื่นๆ จากนั้นจะทำการคิด Execution plan ที่ดีที่สุด (Optimization), Execution plan นี่แหละครับจะถูกเก็บใน Library cache 

เมื่อมีการเรียกใช้อีกครั้ง แล้วพบบน Library cache ก็จะไม่ต้องมีการคิดเพื่อหา Execution plan ดังนั้นแน่นอนส่วนนี้จะช่วยลด waited time ทั้งยังช่วยเรื่อง CPU 

แล้วเรื่อง Bind variables:
ก่อนอื่นอยากให้ รู้จัก CURSOR_SHARING พารามิเตอร์ { SIMILAR | EXACT | FORCE } ซึ่งปกติค่าจะเ ป็น EXACT ซึ่งจะเกี่ยวกับการพิจารณา SQL Statements ที่แชร์บน Cursor

โดยระบบทั่วไปน้อยนักที่จะมีการเปลี่ยนค่าเป็น SIMILAR และ FORCE ยิ่งบนระบบประเภท DSS ไม่แนะนำ เพราะอาจะทำให้เกิด Execution plan ในแบบที่ไม่ต้องการได้

ส่วน CURSOR_SHARING พารามิเตอร์ กับค่า EXACT นั้น จะพิจารณา Sql statements ทุกตัวอักษร
SQL> show parameter CURSOR_SHARING

NAME                                 TYPE        VALUE
----------------------------------------------------------
cursor_sharing                       string      EXACT
ตัวอย่าง 1

user test:
SQL> select * from test01 where object_id=100;
no rows selected
SQL> select * from test01 where object_id=101;

no rows selected

จากนั้น Login ด้วย sys เพื่อต้องการ query V$SQL
SQL> select sql_text,sql_id from v$sql where lower(sql_text) like 'select% from test01%';

SQL_TEXT SQL_ID
-------------------------------------------------- -------------
select * from test01 where object_id=100 42pxm51pbj3gq
select * from test01 where object_id=101 fw9x60q5qbr7z
จะเห็นว่า Sql statments นั้นต่างกันแค่ค่า object_id=? แต่ทำให้เกิด Sql statements บน Library cache ถึง 2 บวกกับมีการ optimization 2 ครั้งเช่นเดียวกัน

ถ้าหากมีการเรียก Sql นี้ 100 ครั้ง 1000 ครั้ง โดยต่างแค่้ object_id=? ย่อมทำให้มีการใช้ Library cache มาก ทั้งยังต้องมีการคิด  Execution plan ทุกครั้งด้วย

ตัวอย่าง 2

ก่อนอื่นใช้ sys user -> flush shared_pool (ใช้กรณี เครื่อง TEST เท่านั้นนะครับ)
SQL> alter system flush shared_pool;

System altered.
user test:
SQL> var A number
SQL> exec :A := 100

PL/SQL procedure successfully completed.

SQL> select * from test01 where object_id=:A;

no rows selected

SQL> exec :A := 101

PL/SQL procedure successfully completed.

SQL> select * from test01 where object_id=:A;

no rows selected
จากนั้นใช้ sys user เพื่อเข้าไป เช็คอีกครั้ง
SQL> select sql_text,sql_id from v$sql where lower(sql_text) like 'select% from test01%'

SQL_TEXT SQL_ID
-------------------------------------------------- -------------
select * from test01 where object_id=:A dtruvsaj9k5xp
จากตัวอย่างนี้ จะเห็นว่ามีการเก็บที่ memory ... Library cache แค่ครั้งเดียว และมีการคิด Execution plan (optimization) แค่ครั้งเดียวด้วย

แน่นอน! จะเห็นว่าประหยัด CPU, memory  มากกว่าด้วย

ตอนนี้เราก็สามารถบอกผู้พัฒนาโปรแกรมได้แล้ว ทำไ มจึงใ ช้  Sql Statements แบบ Bind variables พร้อมขอบคุณ ที่ทำให้งานของเราดีขึ้น

จากนั้นก็แล้วแต่ภาษาที่ใช้อีกที เช่น PHP
$id = $_POST["id"];
$query = "select * from test01 where object_id=:A";
$statement = oci_parse($query);
oci_bind_by_name($statement, ":A", $id);
oci_execute($statement);
หวังว่า Bind variables บน Sql Statements จะช่วยใ้ห้ระบบ Oracle database ดีขึ้นนะครับ