<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Rudi Kristanto's BLOG</title>
	<atom:link href="http://rudikristanto.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://rudikristanto.wordpress.com</link>
	<description>Behave Like Oracle Geek</description>
	<lastBuildDate>Sat, 06 Dec 2008 05:12:12 +0000</lastBuildDate>
	<generator>http://wordpress.com/</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<cloud domain='rudikristanto.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://www.gravatar.com/blavatar/3aad97b90d8096a3da68496cf123eb69?s=96&#038;d=http://s.wordpress.com/i/buttonw-com.png</url>
		<title>Rudi Kristanto's BLOG</title>
		<link>http://rudikristanto.wordpress.com</link>
	</image>
			<item>
		<title>Oracle Sequence Basic</title>
		<link>http://rudikristanto.wordpress.com/2008/11/29/oracle-sequence-basic/</link>
		<comments>http://rudikristanto.wordpress.com/2008/11/29/oracle-sequence-basic/#comments</comments>
		<pubDate>Sat, 29 Nov 2008 05:33:18 +0000</pubDate>
		<dc:creator>Rudi Kristanto</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<category><![CDATA[Tuning]]></category>
		<category><![CDATA[Oracle Sequence]]></category>
		<category><![CDATA[Sequence]]></category>
		<category><![CDATA[Trigger]]></category>

		<guid isPermaLink="false">http://rudikristanto.wordpress.com/?p=57</guid>
		<description><![CDATA[Oracle sequence (selanjutnya saya sebut sequence saja, untuk mempermudah) merupakan object dalam database yang berfungsi sebagai sequence number generator, nilai yang dihasilkan ini biasanya disimpan dalam kolom yang berfungsi sebagai primary key pada suatu table. Fungsionalitas sequence ini hampir sama seperti kolom autonumber di Microsoft Access hanya saja cara pemakaiannya berbeda, nanti pada pertengahan artikel [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=57&subd=rudikristanto&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><strong>Oracle sequence</strong> (selanjutnya saya sebut <em>sequence </em>saja, untuk mempermudah) merupakan object dalam database yang berfungsi sebagai sequence number generator, nilai yang dihasilkan ini biasanya disimpan dalam kolom yang berfungsi sebagai primary key pada suatu table. Fungsionalitas sequence ini hampir sama seperti kolom autonumber di <em>Microsoft Access</em> hanya saja cara pemakaiannya berbeda, nanti pada pertengahan artikel ini akan saya sertakan bagaimana cara memiliki kolom autonumber di Oracle seperti yang dimiliki Microsoft Access dengan menggunakan <em>sequence</em>.</p>
<p>Developer yang tidak mengetahui adanya sequence atau karena hal lain yang membatasinya untuk tidak menggunakan sequence, menggantikannya dengan membuat sendiri sequence number (selanjutnya saya sebut <em>m-sequence</em>, untuk membedakannya dengan Oracle sequence) layaknya Oracle sequence. Teknik ini direalisasikan dengan menyimpan nilai maksimum dari <em>m-sequence</em> pada sebuah table. Saat aplikasi meminta nilai untuk <em>m-sequence</em> berikutnya, nilai terakhir yang disimpan dalam table tersebut dibaca kemudian ditambah satu (atau bilangan tertentu) dan disimpan kembali dalam table tersebut. Pada mekanisme ini, jika setelah table yang menyimpan nilai terakhir m-sequence ini di-update dan kemudian transaksi tidak segera diakhiri (<em>commit</em> atau <em>rollback</em>) maka aplikasi lain yang juga membutuhkan nilai <em>m-sequence</em> ini harus menunggu sampai transaksi yang memegang <em>row level lock</em> tersebut berakhir. Untuk aplikasi single user mekanisme ini tidak menimbulkan masalah, sedangkan dalam situasi multiuser, aplikasi yang seperti ini dikatakan tidak <em>scalable</em>. Pada <em>m-sequence</em> developer juga harus menangani sendiri mekanisme <em>locking</em> untuk mencegah terjadinya <em>lost update</em>, karena jika mekanisme locking tidak diimplementasikan dengan benar maka terdapat kemungkinan dua session yang me-request <em>m-sequence </em>secara bersamaan memperoleh nilai sama.</p>
<p><span id="more-57"></span></p>
<p>Sequence memiliki karakteristik berbeda dengan <em>m-sequence</em> yaitu dapat digunakan oleh aplikasi lain tanpa menunggu transaksi yang meng-update sequence tersebut berakhir, dengan kata lain memperkecil terjadinya <em>window serialization</em> yang pada akhirnya meningkatkan <em>scalability</em>. Selain itu mekanisme locking-nya juga ditangani secara internal oleh Oracle, jadi kita tidak perlu khawatir memperoleh nilai kembar. Berikut saya sertakan contoh membuat sequence lengkap dengan parameternya.</p>
<pre class="brush: sql;">
create sequence myblog_seq
  start with 1
  increment by 1
  maxvalue 99999
  minvalue 1
  nocycle
  cache 5
  noorder;
</pre>
<p>Seperti halnya object lain dalam database dimiliki oleh seorang owner, sequence object ini juga tidak terkecuali, sequence di atas dimiliki oleh current user dimana sequence tersebut saya create. Seorang user harus memiliki privilege <strong><em>create sequence</em></strong> untuk dapat membuat sequence pada schema-nya, untuk membuat sequence pada schema yang dimiliki user lain dibutuhkan privilege <strong><em>create any sequence</em></strong>. Sequence di atas, <em>ascending sequence</em>, akan menghasilkan sequence number mulai dari <strong>start with</strong> (1) sampai <strong>maxvalue</strong> (10000), dan selisih dari tiap nilai yang dihasilkan adalah sebesar <strong>increment by</strong> (1). Jika aplikasi meminta sequence number berikutnya setelah sequence tersebut mencapai <em>maxvalue</em> maka ada dua kemungkinan yang terjadi tergantung parameter sequence tersebut <em>cycle</em> atau <em>nocycle</em>. Jika <strong>cycle</strong> setelah mencapai <em>maxvalue</em>, sequence tersebut akan kembali menghasilkan nilai mulai <em>minvalue</em>, sebaliknya jika <strong>nocycle</strong> maka pesan error<em> ORA-08004</em> yang dihasilkan. Perlu diketahui bahwa parameter <em>increment by</em> juga bisa bernilai negatif artinya sequence yang dihasilkannyapun bersifat <em>desceding sequence</em>.</p>
<p>Persamaan dari <em>m-sequence</em> dan sequence adalah state dan karakteristik masing-masing sequence disimpan dalam sebuah table. Jika pada <em>m-sequence</em> table yang menyimpannya dibuat sendiri oleh developer maka pada sequence disimpan pada table dalam data dictionary yaitu <em><strong>sys.seq$</strong></em>. Untuk setiap perubahan dari sequence, Oracle akan meng-update nilai maksimum sequence tersebut pada table <em>sys.seq$</em> dan segera meng-<em>commit</em> transaksinya tanpa harus mempengaruhi transaksi yang meminta sequence number tersebut. Mekanisme seperti ini dimungkinkan karena adanya <em>autonomous transaction</em>. Sebagai konsekuensinya jika transaksi yang meminta sequence number tadi me-<em>rollback</em> transaksinya, nilai maksimum sequence tersebut tidak berubah.</p>
<p>Oracle menyediakan mekanisme caching pada sequence dengan tujuan untuk mengurangi intensitas update pada table <em>sys.seq$</em> yang pada akhirnya meningkatkan performance saat akses sequence tersebut.<br />
Jika kita saat membuat sequence tidak menspesifikasikan parameter cache maka default-nya sequence tersebut akan di-<em>cache</em> dan nilai <strong>cache</strong> ini adalah 20 yang artinya ada 20 sequence number yang dipre-alokasikan dalam sequence cache, dan jika habis terpakai cache tersebut akan diisi kembali. Kalau kita menggunakan teknologi RAC maka tiap-tiap instance dalam RAC memiliki sequence cache-nya sendiri. Selain meningkatkan performance sequence, <em>cache</em> ini juga menimbulkan efek samping yaitu <em>gap</em> yang cukup signifikan pada sequence number yang dihasilkan. Sekali lagi saya tekankan secara eksplisit, sekalipun sequence tersebut tidak menggunakan <em>cache</em> (<strong>nocache</strong>) Oracle tidak menjamin tidak adanya gap, yang dijamin Oracle dengan sequence ini ialah tidak ada dua atau lebih user akan memperoleh hasil kembar dari sebuah sequence.</p>
<p>Selanjutnya saya akan membahas mengapa gap yang cukup signifikan ini bisa terjadi. Karena sequence cache disimpan dalam <em>shared pool</em> tepatnya <em>libary cache</em> maka saat <strong><em>instance shutdown</em></strong>, cache tersebut juga akan hilang. Sebab lainnya ialah, object dalam shared pool dimaintain dengan modified <em>LRU algorithm</em> termasuk di dalamnya sequence <em>cache</em>, dan jika sequence cache tersebut tidak sering diakses maka besar kemungkinan akan mengalami <strong><em>aged out</em></strong>. Berikut gambaran akses sequence <em>myblog_seq</em> yang telah saya create di atas dan di dalamnya terdapat aged out dan instance shutdown (<em>Metalink Note:62002.1</em>).</p>
<pre class="brush: sql;">
   app.    | number   | sequence |  cache   |
  access   | returned | current  |  current |
---------------------------------------------
1st access |     1    |     5    |     1    |
2nd access |     2    |     5    |     2    |
---------------------------------------------
               cache aged out
---------------------------------------------
3rd access |     6    |    10    |     6    |
4th access |     7    |    10    |     7    |
---------------------------------------------
              instance shutdown
---------------------------------------------
5th access |    11    |    15    |    11    |
6th access |    12    |    15    |    12    |
7th access |    13    |    15    |    13    |
</pre>
<p>Karena dua efek tersebut sequence number yang dihasilkan (lihat kolom 2) didalamnya terdapat <em>gap</em> tak beraturan. Khusus untuk kasus <em>aged out</em>, Oracle menyediakan solusi dengan menggunakan procedure <strong>keep</strong> dalam package <strong>dbms_shared_pool</strong>. Package ini perlu di-create terlebih dulu dengan menjalankan script <em>dbmspool.sql</em> sebagai user SYS, dan di Linux script ini berada di <em>$ORACLE_HOME/rdbms/admin/</em>. Berikut contoh penggunaan procedure ini pada sequence <em>myblog_seq</em>.</p>
<pre class="brush: sql;">
begin
  sys.dbms_shared_pool.keep('myblog_seq','q');
end;
/
</pre>
<p>Setelah eksekusi procedure ini sequence akan tetap di-cache dalam memory tanpa terpengaruh efek <em>LRU</em>. Untuk sequence yang tidak sering diakses, lebih baik tidak menggunakan cache dari pada harus menggunakan procedure <em>keep</em> untuk alokasi memory (<em>sequence cache</em>) yang jarang dipakai. Solusi ini tidak menyelesaikan masalah pada kasus instance shutdown. Kita dapat melihat sequence apa saja yang telah di-<em>keep</em> melalui perintah SQL berikut.</p>
<pre class="brush: sql;">
select owner, name
from v$db_object_cache
where type = 'SEQUENCE' and kept = 'YES';

OWNER      NAME
---------- --------------------
RK         MYBLOG_SEQ
</pre>
<p>Pada RAC, sequence dengan cache ini dapat menghasilkan nilai yang tidak berurutan dengan timing event request-nya. Contoh, user A pada instance rac1 meminta sequence number pada jam 07:00 selanjutnya user B pada instance rac2 juga meminta sequence number pada jam 07:01. Pada RAC, kejadian berikut mungkin terjadi dimana user A memperoleh nilai 11 untuk request-nya dan user B memperoleh nilai 7 untuk request-nya. Untuk menjaga keterurutan sequence ini Oracle menyediakan clausa <strong>order</strong> sebagai parameter saat developer membuat sequence, dengan demikian user A akan memperoleh nilai 7 and user B akan memperoleh nilai 8.</p>
<p>Apabila setelah di-create kita ingin mengubah nilai dari parameter sequence maka kita dapat menggunakan perintah alter sequence. Untuk meng-alter sequence yang berada di schema user lain dibutuhkan privilege <strong><em>alter any sequence</em></strong>.</p>
<p>Kombinasi parameter cache dan order ini berpengaruh terhadap <em>performance</em> sequence yang di-create. Saya tidak akan menjelaskan alasannya satu-persatu karena artikel ini hanya mengulas tentang basic sequence saja. Kombinasi dari kedua parameter tersebut dari yang terburuk sampai yang terbaik dari segi performance sebagai berikut :<br />
1. nocache dan order<br />
2. nocache dan noorder<br />
3. cache dan order<br />
4. cache dan noorder</p>
<p>Sampai sejauh ini saya belum menunjukkan bagaimana cara menggunakan sequence. Karena penggunaannya sangat mudah saya tidak akan membahasnya tersendiri, seperti yang telah saya singgung di awal artikel ini, saya akan menggunakan sequence untuk memperoleh fungsionalitas <em>autonumber</em> seperti pada Microsoft Access.</p>
<p>Misalkan saya mau menyimpan informasi judul setiap artikel blog ini ke dalam sebuah table dan menggunakan sequence number sebagai <em>primary key</em>-nya.</p>
<pre class="brush: sql;">
create table myblog_post
(
  myblog#    number(5),
  title        varchar2(255),
  constraints    myblog_post_pk primary key (myblog#)
);
</pre>
<p>Selanjutnya dengan menggunakan <strong><em>before insert trigger</em></strong> saya mengisi kolom <em>myblog#</em> dengan sequence number sehingga saat insert record ke table tersebut kita tidak perlu lagi mengisi nilai kolom ini. Kali ini saya menggunakan trigger hanya untuk menunjukkan bahwa Oracle juga bisa mengimplementasikan autonumber seperti pada Microsoft Access meskipun dengan usaha yang lebih banyak dan biasanya teknik ini digunakan oleh aplikasi yang bersifat database independent. Baca artikel saya sebelumnya tentang <a href="http://rudikristanto.wordpress.com/2008/10/29/dont-trigger-to-code-triggers/">trigger</a> sebelum menggunakan trigger dalam aplikasi yang anda buat. Script berikut telah saya test di <em>Oracle 10.2.0.1</em> dan <em>Oracle 11.1.0.6</em>. <em>Conditional compilation</em> yang saya pakai di trigger mulai tersedia pada <em>Oracle release 10.1.0.4</em>.</p>
<pre class="brush: sql;">
create or replace trigger myblog_post_bir
before insert on myblog_post
for each row
begin
  $if dbms_db_version.ver_le_10 $then
    select myblog_seq.nextval into :new.myblog#
    from dual;
  $else
    :new.myblog# := myblog_seq.nextval;
  $end
end;
/

insert into myblog_post (title) values ('Intro');
insert into myblog_post (title) values ('Activate Extended SQL Trace');
insert into myblog_post (title) values ('Reading TKPROF Output');
insert into myblog_post (title) values ('Don''t trigger to code Trigger');
commit;

insert into myblog_post (title) values ('Oracle Sequence Basic');
rollback;

insert into myblog_post (title) values ('Oracle Sequence Basic');
commit;

select * from myblog_post;

   MYBLOG# TITLE
---------- ------------------------------
         1 Intro
         2 Activate Extended SQL Trace
         3 Reading TKPROF Output
         4 Don't trigger to code Trigger
         6 Oracle Sequence Basic

select myblog_seq.currval from dual;

   CURRVAL
----------
         6
</pre>
<p>Atribut <strong>nextval</strong> di atas digunakan untuk memperoleh sekaligus mengalokasikan nilai sequence selanjutnya. Untuk mengetahui nilai terakhir yang dialokasikan sequence tersebut pada suatu session digunakan atribut <strong>currval</strong>. Jika eksekusi atribut currval ini tidak pernah didahului dengan eksekusi nextval untuk setiap sequence pada suatu session, maka akan muncul pesan error <em>ORA-08002</em>. Berikut perilaku yang perlu diperhatikan saat menggunakan atribut <em>currval</em>. (Pada tabel berikut, jika ada dua select yang berada sebaris maka select milik session A dieksekusi terlebih dulu)</p>
<pre class="brush: sql;">
Session A                            | Session B
-------------------------------------|-------------------------------------
select myblog_seq.nextval from dual; | select myblog_seq.nextval from dual;
                                     |
   NEXTVAL                           |    NEXTVAL
----------                           | ----------
         7                           |          8
-------------------------------------|-------------------------------------
select myblog_seq.nextval from dual; | Idle
                                     |
   NEXTVAL                           |
----------                           |
         9                           |
-------------------------------------|-------------------------------------
select myblog_seq.nextval from dual; | Idle
                                     |
   NEXTVAL                           |
----------                           |
        10                           |
-------------------------------------|-------------------------------------
select myblog_seq.currval from dual; | select myblog_seq.currval from dual;
                                     |
   CURRVAL                           |    CURRVAL
----------                           | ----------
        10                           |          8
-------------------------------------|-------------------------------------
Idle                                 | select myblog_seq.nextval from dual;
                                     |
                                     |    NEXTVAL
                                     | ----------
                                     |         11
</pre>
<p>Untuk mengetahui nilai yang akan dihasilkan suatu sequence tanpa harus mengeksekusi <em>nextval </em>ternyata tidak semudah yang saya bayangkan, dapat dilihat pada table di atas nilai yang ditampilkan oleh atribut currval ini hanya mengacu pada masing-masing session dimana nilainya tidak konsisten dan tidak dapat digunakan sebagai patokan untuk nilai yang akan dihasilkan oleh suatu sequence. Oracle mengeksternalisasi <em>sys.seg$</em> menjadi data dictionary view <em>dba_sequences/all_sequences/user_sequences</em> dan melalui kolom last_number kita dapat mengetahui berapa nilai yang akan kita peroleh jika kita mengeksekusi <em>nextval</em>.</p>
<pre class="brush: sql;">
select last_number from user_sequences
where sequence_name = 'MYBLOG_SEQ';

LAST_NUMBER
-----------
         16

select myblog_seq.nextval from dual;

   NEXTVAL
----------
        12
</pre>
<p>Ternyata <em>view </em>ini juga memberikan informasi yang tidak tepat karena saya menspesifikasikan <em>cache </em>5 saat membuat sequence ini. Namun jika kita tidak menggunakan cache untuk sequence tersebut maka ketiga <em>dictionary view</em> tadi akan memberikan informasi yang tepat untuk nilai sequence selanjutnya. Saat ini cara yang saya ketahui untuk sequence yang di-cache ialah melalui fixed view yang dimiliki oleh user SYS yaitu <strong>v$_sequences</strong>.</p>
<pre class="brush: sql;">
select nextvalue from v$_sequences
where sequence_name = 'MYBLOG_SEQ';

 NEXTVALUE
----------
        13

select myblog_seq.nextval from dual;

   NEXTVAL
----------
        13
</pre>
<p>Tetapi untunglah kita dapat memakai sequence dalam aplikasi tanpa perlu mengetahui berapa nilai selanjutnya yang akan dihasilkan oleh sequence tersebut selama parameter yang kita isikan saat create sequence tersebut benar. Jadi bahasan terakhir ini hanya untuk memuaskan rasa keingintahuan saya saja tentang <strong>Oracle sequence</strong>.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/rudikristanto.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/rudikristanto.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/rudikristanto.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/rudikristanto.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/rudikristanto.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/rudikristanto.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/rudikristanto.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/rudikristanto.wordpress.com/57/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/rudikristanto.wordpress.com/57/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/rudikristanto.wordpress.com/57/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=57&subd=rudikristanto&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://rudikristanto.wordpress.com/2008/11/29/oracle-sequence-basic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3b3709f48c19ec27610047308b37554a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Rudi</media:title>
		</media:content>
	</item>
		<item>
		<title>Don&#8217;t trigger to code Triggers</title>
		<link>http://rudikristanto.wordpress.com/2008/10/29/dont-trigger-to-code-triggers/</link>
		<comments>http://rudikristanto.wordpress.com/2008/10/29/dont-trigger-to-code-triggers/#comments</comments>
		<pubDate>Wed, 29 Oct 2008 05:14:59 +0000</pubDate>
		<dc:creator>Rudi Kristanto</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[Trace File]]></category>
		<category><![CDATA[Tuning]]></category>
		<category><![CDATA[PL/SQL]]></category>
		<category><![CDATA[TKPROF]]></category>
		<category><![CDATA[Trigger]]></category>

		<guid isPermaLink="false">http://rudikristanto.wordpress.com/?p=47</guid>
		<description><![CDATA[Dulu waktu kuliah saya sempat belajar mengenai trigger, apa itu trigger, bagaimana trigger digunakan dan sebagainya. Setelah saya lulus, dan bukan kebetulan saya bekerja menggunakan Oracle database, saya merupakan pengguna trigger yang tanpa tahu efek buruk yang ditimbulkannya, bahkan saya sempat berpikir kalau trigger merupakan salah satu feature yang keren.
Efek pertama, yang terasa bagi saya [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=47&subd=rudikristanto&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Dulu waktu kuliah saya sempat belajar mengenai <em>trigger</em>, apa itu trigger, bagaimana trigger digunakan dan sebagainya. Setelah saya lulus, dan bukan kebetulan saya bekerja menggunakan Oracle database, saya merupakan pengguna trigger yang tanpa tahu efek buruk yang ditimbulkannya, bahkan saya sempat berpikir kalau trigger merupakan salah satu feature yang keren.</p>
<p><strong>Efek pertama</strong>, yang terasa bagi saya sendiri setelah cukup banyak mengerjakan program adalah repotnya <strong>memaintain</strong> program lama jika mengalami perubahan. Kalau saya tidak lupa tentang keberadaan trigger, saya akan menelusuri kembali trigger apa saja yang ada pada module tersebut, karena sifat trigger yang transparent terhadap aplikasi, dan bayangkan saja jika event (insert, update, delete, dst) satu table men-trigger event table lain dan event table lain ini juga men-trigger event table lainnya lagi, sungguh rumit dan butuh ketelitian apakah perubahan tersebut juga harus mengubah source trigger tersebut.</p>
<p><strong>Efek kedua</strong>, berhubungan dengan <strong>performance</strong>. Sekarang ini setiap project yang saya tangani, saya kerjakan dengan menggunakan PL/SQL package, dimana package ini berupa API (Application Programming Interface). Berikut ini saya akan membandingkan eksekusi SQL yang berada dalam trigger dan yang berada dalam stored procedure (PL/SQL) dari segi performance. Test saya kerjakan di Oracle Database 10g Enterprise Edition Release 10.2.0.1.0.</p>
<p><span id="more-47"></span></p>
<pre class="brush: sql;">
create table t (col varchar2(30));

create or replace procedure sql_in_proc
as
begin
  for i in (select /*+ stored procedure */ * from dual)
  loop
    null;
  end loop;
end;
/

create or replace trigger sql_in_trig
before insert on t
for each row
begin
  for i in (select /*+ trigger */ * from dual)
  loop
    null;
  end loop;

  sql_in_proc;
end;
/

alter session set timed_statistics = true;

alter session set events '10046 trace name context forever, level 1';

insert into t values ('TEST1');

insert into t values ('TEST2');

insert into t
select owner from all_objects
where rownum &lt; 11;

commit;

alter session set events '10046 trace name context off';
</pre>
<p>Dengan menggunakan <a href="http://rudikristanto.wordpress.com/2008/09/28/reading-tkprof-output/">TKPROF</a> saya memformat <em>raw trace file</em> yang dihasilkan, dan berikut adalah bagian yang perlu dianalisa lebih lanjut.</p>
<pre class="brush: sql;">
SELECT /*+ trigger */ *
FROM
 DUAL

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        3      0.00       0.00          0          0          0           0
Execute     12      0.00       0.00          0          0          0           0
Fetch       12      0.00       0.00          4         36          0          12
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       27      0.00       0.00          4         36          0          12

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 74     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS FULL DUAL (cr=3 pr=2 pw=0 time=175 us)

********************************************************************************

SELECT /*+ stored procedure */ *
FROM
 DUAL

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute     12      0.00       0.00          0          0          0           0
Fetch       12      0.00       0.00          0         36          0          12
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       25      0.00       0.00          0         36          0          12

Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 74     (recursive depth: 1)
</pre>
<p>Dari hasil test di atas dapat dilihat bahwa keduanya sama-sama melakukan sekali <em>hard parsing</em>,  statistik <em>misses in library cache during parse</em> yang keduanya bernilai satu. Statistik lain yang menunjukkan perbedaan ialah jumlah <em>soft parse</em>, diperoleh dari statistik parse dikurangi jumlah hard parse. Untuk SQL yang berada dalam stored procedure mengalami soft parse yang lebih sedikit (0) jika dibandingkan dengan SQL yang berada pada trigger (2). Dari sini dapat saya simpulkan bahwa SQL pada trigger hanya di-cache selama triggering statement berlangsung. Sedangkan SQL pada PL/SQL (stored procedure/function), mulai Oracle 9i, akan di-cache sebanyak jumlah yang dispesifikasikan dalam parameter <em>session_cached_cursors</em>. Detail dari statement saya yang terakhir akan menjadi topik blog saya yang lain. Jumlah execute call yang tidak didahului parse call disebut juga sebagai <em>no parse</em>.</p>
<p>Jadi dari segi performance, SQL dalam PL/SQL lebih baik jika dibandingkan SQL dalam trigger karena seperti kita ketahui jika parameter <em>session_cached_cursors</em> dikonfigurasi dengan benar akan mengurangi jumlah soft parse yang terjadi.</p>
<p>Mulai Oracle 11g, SQL yang berada pada trigger diperlakukan sama seperti SQL yang berada dalam PL/SQL. Untuk itu saya ulangi lagi test di atas hanya saja saya kerjakan di Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 dan saya peroleh hasil dari TKPROF sebagai berikut.</p>
<pre class="brush: sql;">
SQL ID : a8w9mrw70zb7k
SELECT /*+ trigger */ *
FROM
 DUAL

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute     12      0.00       0.00          0          0          0           0
Fetch       12      0.00       0.00          0         36          0          12
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       25      0.00       0.00          0         36          0          12

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 95     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS FULL DUAL (cr=3 pr=0 pw=0 time=0 us cost=2 size=2 card=1)

********************************************************************************

SQL ID : 610w27avd3dts
SELECT /*+ stored procedure */ *
FROM
 DUAL

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute     12      0.00       0.00          0          0          0           0
Fetch       12      0.00       0.00          0         36          0          12
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total       25      0.00       0.00          0         36          0          12

Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 95     (recursive depth: 1)

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  TABLE ACCESS FULL DUAL (cr=3 pr=0 pw=0 time=0 us cost=2 size=2 card=1)
</pre>
<p>Walaupun sudah diperlakukan sama di Oracle 11g, saya cenderung tidak menggunakan trigger karena alasan yang saya jelaskan pada efek pertama di atas.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/rudikristanto.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/rudikristanto.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/rudikristanto.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/rudikristanto.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/rudikristanto.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/rudikristanto.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/rudikristanto.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/rudikristanto.wordpress.com/47/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/rudikristanto.wordpress.com/47/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/rudikristanto.wordpress.com/47/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=47&subd=rudikristanto&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://rudikristanto.wordpress.com/2008/10/29/dont-trigger-to-code-triggers/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3b3709f48c19ec27610047308b37554a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Rudi</media:title>
		</media:content>
	</item>
		<item>
		<title>Reading TKPROF Output</title>
		<link>http://rudikristanto.wordpress.com/2008/09/28/reading-tkprof-output/</link>
		<comments>http://rudikristanto.wordpress.com/2008/09/28/reading-tkprof-output/#comments</comments>
		<pubDate>Sun, 28 Sep 2008 05:56:14 +0000</pubDate>
		<dc:creator>Rudi Kristanto</dc:creator>
				<category><![CDATA[Performance Toolkit]]></category>
		<category><![CDATA[Trace File]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<category><![CDATA[10046]]></category>
		<category><![CDATA[TKPROF]]></category>

		<guid isPermaLink="false">http://rudikristanto.wordpress.com/?p=34</guid>
		<description><![CDATA[Dari topik sebelumnya yaitu Activate Extended SQL Trace, kita telah memperoleh sebuah file yang berisi history tentang apa saja yang dikerjakan oleh Oracle kernel untuk memenuhi permintaan aplikasi terhadap database. Menurut pengalaman saya dalam tracing ini, file yang dihasilkan dari SQL tracing ini berukuran besar, dan tidak mudah untuk langsung dianalisa. Untuk itulah TKPROF dibuat [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=34&subd=rudikristanto&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Dari topik sebelumnya yaitu <a href="http://rudikristanto.wordpress.com/2008/08/21/activate-extended-sql-trace/">Activate Extended SQL Trace</a>, kita telah memperoleh sebuah file yang berisi history tentang apa saja yang dikerjakan oleh Oracle kernel untuk memenuhi permintaan aplikasi terhadap database. Menurut pengalaman saya dalam tracing ini, file yang dihasilkan dari SQL tracing ini berukuran besar, dan tidak mudah untuk langsung dianalisa. Untuk itulah TKPROF dibuat supaya mempermudah kita melakukan analisa.</p>
<p>TKPROF ini akan mem-format trace file yang dihasilkan ke dalam bentuk standard dengan tujuan mudah dimengerti. Saya tidak akan menjelaskan seluruh option yang dimiliki oleh TKPROF karena Oracle telah mendokumentasikannya dengan baik, hanya yang sering saya pakai saja. Untuk lebih dimengerti, penjelasan akan saya sertai dengan contoh. Berikut saya bentuk dulu test case-nya, saya jalankan dengan menggunakan Oracle 11g karena saya memakai <em><strong>v$diag_info</strong></em> untuk mencari nama trace file yang terbentuk.</p>
<p><span id="more-34"></span></p>
<pre class="brush: sql;">
spool trace;

set serveroutput off;

select value
from v$diag_info
where inst_id = (select instance_number from v$instance) and
      name = 'Default Trace File';

execute dbms_random.seed(0);

create table t
as
select rownum-1 id,
       dbms_random.string('X',50) name,
       trunc((rownum-1)/10) manager,
       to_date('19800101','yyyymmdd')+trunc((rownum-1)/100) hire_date,
       1000000-trunc(rownum/10) salary,
       'LEVEL '||decode(rownum-1,0,0,trunc((rownum-1)/10)+1) job,
       rpad('*',50,'*') description
from dual
connect by level &lt;= 1000000;

alter table t add constraint t_pk primary key (id);

alter table t add constraint t_r01 foreign key (manager) references t(id);

alter table t modify(manager not null);

execute dbms_stats.gather_table_stats(user,'T',cascade =&gt; true);

alter session set timed_statistics = true;

alter session set max_dump_file_size = unlimited;

alter session set events '10046 trace name context forever, level 12';

begin
  for i in (select a.*
            from (select emp.*, mgr.name mgr_name
                  from t emp, t mgr
                  where mgr.id = emp.manager
                  order by emp.id) a
            where rownum &lt;= 100000)
  loop
    null;
  end loop;
end;
/

alter session set events '10046 trace name context off';

spool off;

exit;
</pre>
<p>Selanjutnya pada command line/shell ketikkan perintah berikut.</p>
<pre class="brush: sql;">
tkprof rac3_ora_6942.trc tkrpt1.prf sys=no sort=prsela,exeela,fchela
</pre>
<p>Perintah TKPROF ini akan memproses trace file yang diinputkan yaitu <em>rac3_ora_6942.trc</em> dan kemudian menghasilkan report dengan nama <em>tkrpt1.prf</em>. Option sys=no ini memberi perintah kepada TKPROF supaya SQL statement yang dieksekusi oleh user SYS (recursive SQL) tidak disertakan ke dalam report yang terbentuk. Option <em>sort=prsela,exeela,fchela</em> memberi perintah pada TKPROF untuk mengurutkan SQL statement pada report yang terbentuk berdasarkan penjumlahan waktu (response time) yang dibutuhkan untuk parsing, execute dan fetching secara descending. Selanjutnya akan saya jelaskan bagian-bagian dari report tersebut yang penting untuk troubleshooting.</p>
<p>Bagian header berisi informasi tentang nama trace file dan sort option. Trace file ini saya peroleh dari session yang terkoneksi dengan dedicated server, jadi SQL statement yang terkandung di dalamnya pasti juga berasal dari session yang sama. Memang ada pengecualian, misalnya pada operating system Windows saya pernah menjumpai trace file dari session yang berbeda berada dalam satu file walaupun koneksinya dedicated server. Ada informasi yang tidak muncul pada TKPROF report yang saya hasilkan yaitu informasi mengenai identitas session yang bersangkutan (<em>sid,serial#,timing information</em>), hal ini dipengaruhi oleh parameter <em>aggregate</em> yang default-nya bernilai true. Jika parameter ini bernilai false identitas session ini akan muncul sebagai pemisah SQL statement yang dieksekusi oleh session berbeda (shared server).</p>
<pre class="brush: sql;">
TKPROF: Release 11.1.0.6.0 - Production on Thu Sep 18 11:34:45 2008

Copyright (c) 1982, 2007, Oracle.  All rights reserved.

Trace file: rac3_ora_6942.trc
Sort options: prsela  exeela  fchela
********************************************************************************
count    = number of times OCI procedure was executed
cpu      = cpu time in seconds executing
elapsed  = elapsed time in seconds executing
disk     = number of physical reads of buffers from disk
query    = number of buffers gotten for consistent read
current  = number of buffers gotten in current mode (usually for update)
rows     = number of rows processed by the fetch or execute call
********************************************************************************
</pre>
<p>Setelah bagian header dapat dijumpai satu blok besar yang berisi SQL statement, execution statistic, query environment, execution plan dan wait event. Perlu diingat urutan statement yang muncul dalam TKPROF report ini bukan merupakan urutan kejadian tetapi diurutkan sesuai sort option yang saya spesifikasikan saat membentuk report ini.</p>
<p><strong>SQL statement</strong><br />
Mengandung informasi tentang SQL statement beserta SQL ID yang profile eksekusinya terletak setelahnya.</p>
<pre class="brush: sql;">
SQL ID : d026689a03jpc
SELECT A.*
FROM
 (SELECT EMP.*, MGR.NAME MGR_NAME FROM T EMP, T MGR WHERE MGR.ID =
  EMP.MANAGER ORDER BY EMP.ID) A WHERE ROWNUM &lt;= 100000
</pre>
<p><strong>Execution statistics</strong><br />
Tabular report berikut menampilkan informasi statistik dari tiap-tiap database call. Ada tiga macam database call yang statistiknya dicatat dalam TKPROF report, yaitu:<br />
<em>1. Parse</em><br />
Dalam fase ini, Oracle melakukan syntax, semantical dan access right checking. Kemudian Oracle mencari shareable cursor pada shared pool dan jika tidak ada maka membuat plan baru (hard parsing).<br />
<em>2. Execute</em><br />
Merupakan tahap eksekusi statement oleh Oracle. Jika statement tersebut adalah DML maka pada tahap inilah semua perkerjaan diselesaikan. Sedangkan untuk select statement fase ini biasanya bernilai nol, karena load sesungguhnya berada pada fase fetch.<br />
<em>3. Fetch</em><br />
Fase ini hanya untuk select statement saja dan merupakan fase dominan dari select statement. Jika query mengembalikan record/row maka dalam fase inilah record-record tersebut didapatkan.</p>
<pre class="brush: sql;">
call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch     1001      2.55       5.46      49517      39884          0      100000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     1003      2.55       5.47      49517      39884          0      100000
</pre>
<p>Berikut saya jelaskan mengenai arti dari statistik pada tiap-tiap database call.<br />
<em>1. Count</em><br />
Menyatakan jumlah eksekusi dari tiap-tiap database call.<br />
<em>2. CPU</em><br />
Jumlah CPU time dalam second yang digunakan pada tiap-tiap database call.<br />
<em>3. Elapsed</em><br />
Lama waktu dalam second yang dibutuhkan pada tiap-tiap database call. Jika nilai elapsed lebih besar dari cpu maka artinya session tersebut pernah mengalami penantian untuk sesuatu hal yang session tersebut butuhkan (wait event).<br />
<em>4. Disk</em><br />
Jumlah data block yang dibaca secara langsung dari datafile (OS cache/disk subsystem cache/disk) pada tiap-tiap database call. Pembacaan langsung ke datafile ini juga dikenal dengan istilah physical IO (PIO).<br />
<em>5. Query</em><br />
Jumlah data block yang dibaca dari buffer cache dengan consistent read artinya block yang kita baca adalah block yang sama saat query dimulai dan tidak akan terpengaruh perubahan yang dilakukan oleh session lain. Block yang semacam ini direkonstruksi dari rollback segment. Jumlah block yang terbaca dari statistik ini merupakan salah satu kontributor dari logical IO (LIO). LIO dengan consistent read ini ditimbulkan oleh select statement.<br />
<em>6. Current</em><br />
Jumlah data block yang dibaca dari buffer cache dengan current read artinya block yang kita baca adalah isi block saat itu juga. Jumlah ini juga merupakan kontributor bagi LIO. Jadi LIO merupakan jumlah block yang dibaca baik dengan consistent maupun current read. LIO dengan current read ini ditimbulkan oleh DML (insert/update/delete/merge).<br />
<em>7. Rows</em><br />
Jumlah row/record yang diproses pada tiap-tiap database call. Untuk select statement jumlah ini merupakan jumlah row yang di-fetch, sedangkan untuk DML merupakan jumlah row yang terpengaruh perubahan.</p>
<p><strong>Query environment</strong><br />
Pada bagian ini berisi informasi tentang parsing. Jumlah misses pada bagian berikut menandakan Oracle melakukan satu kali hard parsing dan terjadi saat parse, sedangkan jika bernilai nol artinya Oracle melakukan soft parse. Selain informasi tentang kapan terjadinya hard parsing, dapat ditemukan parameter optimizer mode apa yang digunakan untuk mengoptimasi execution plan dan siapa yang melakukan parsing SQL statement tersebut.</p>
<pre class="brush: sql;">
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 109     (recursive depth: 1)
</pre>
<p><strong>Execution plan</strong><br />
Row source operation atau yang sering disebut execution plan merupakan plan yang digunakan oleh Oracle ketika SQL statement tersebut dijalankan. Bagian ini terdiri dari dua kolom, kolom pertama adalah rows yang merupakan jumlah row/record yang dihasilkan pada operasi yang tertera disebelahnya. Sedangkan pada kolom kedua berisi tetang operasi yang dikerjakan oleh Oracle berikut dengan statistiknya.</p>
<pre class="brush: sql;">
Rows     Row Source Operation
-------  ---------------------------------------------------
 100000  COUNT STOPKEY (cr=39884 pr=49517 pw=49517 time=2873 us)
 100000   VIEW  (cr=39884 pr=49517 pw=49517 time=1856 us cost=61101 size=4104000000 card=1000000)
 100000    SORT ORDER BY STOPKEY (cr=39884 pr=49517 pw=49517 time=801 us cost=61101 size=192000000 card=1000000)
1000000     HASH JOIN  (cr=39884 pr=49517 pw=49517 time=18290 us cost=19093 size=192000000 card=1000000)
1000000      TABLE ACCESS FULL T (cr=19942 pr=19938 pw=19938 time=13449 us cost=4424 size=56000000 card=1000000)
1000000      TABLE ACCESS FULL T (cr=19942 pr=19938 pw=19938 time=11271 us cost=4430 size=136000000 card=1000000)
</pre>
<p>Berikut saya sertakan penjelasan dari statistik yang menyertai row source operation:<br />
- <em>cr</em> (consitent read) merupakan jumlah block yang dibaca dari buffer cache dengan consistent read.<br />
- <em>pr</em> (physical read) merupakan jumlah block yang dibaca dari datafile.<br />
- <em>pw</em> (physical write) merupakan jumlah block yang ditulis ke disk.<br />
- <em>time</em> merupakan jumlah waktu dalam microsecond (us) yang dibutuhkan hingga mencapai langkah tersebut.<br />
- <em>cost</em> merupakan perkiraan cost yang diberikan oleh optimizer sampai dengan operasi tersebut.<br />
- <em>size</em> merupakan perkiraan jumlah data yang dihasilkan sampai dengan operasi tersebut dalam byte.<br />
- <em>card</em> merupakan perkiraan jumlah row yang dihasilkan pada operasi tersebut.</p>
<p>Untuk tiga parameter terakhir hanya ada mulai Oracle 11g. Selain cardinalty (<em>card</em>), nilai di atas sifatnya akumulatif artinya juga mengandung nilai dari child operation-nya. Untuk time, nilainya tidak akurat karena dalam hal ini saya menggunakan parameter <em>statistics_level</em> default yaitu <em>TYPICAL</em>. Ada dua cara untuk memperoleh statistik time yang akurat (1) mengubah parameter <em>statistics_level</em> menjadi <em>ALL</em> atau (2) mengubah hidden parameter <em>&#8220;_rowsource_statistics_sampfreq&#8221;</em> menjadi 1 (defaultnya 128) dan tentunya kedua cara ini menimbulkan overhead.</p>
<p><strong>Wait event</strong><br />
Bagian ini sangatlah membantu saat tuning, terutama untuk menelusuri penggunaan waktu (elapsed) yang di luar pemakaian CPU. Bagian ini terdiri dari empat kolom yaitu:<br />
- <em>Event waited on</em>, kolom ini menampilkan nama wait event. Wait event dapat berupa penantian resource untuk kembali tersedia, misalnya latch, enqueue; menunggu terselesaikannya suatu pekerjaan, misalnya I/O operation; menunggu pekerjaan selanjutnya, misalnya menunggu SQL statement yang akan di-submit oleh client (idle event).<br />
- <em>Times Waited</em>, menampilkan jumlah terjadinya wait event tersebut.<br />
- <em>Max. Wait</em>, menampilkan lama waktu maksimal dalam second untuk sebuah wait event ini.<br />
- <em>Total Waited</em>, menampilkan total lama waktu dalam second yang dibutuhkan untuk wait event ini.</p>
<pre class="brush: sql;">
Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  rdbms ipc reply                                77        0.00          0.00
  KJC: Wait for msg sends to complete             2        0.00          0.00
  reliable message                                2        0.00          0.01
  enq: KO - fast object checkpoint                4        0.04          0.04
  ges inquiry response                            2        0.00          0.00
  direct path read                             2682        0.00          0.01
  enq: TT - contention                           32        0.00          0.01
  direct path write temp                        311        0.00          0.00
  direct path read temp                         311        0.00          0.00
********************************************************************************
</pre>
<p>Idealnya total cpu time (2.55 s) ditambah total wait event time (0.07 s) sama dengan total elapsed time (5.47 s), namun pada contoh ini terdapat selisih sebesar 2.85 second. Selisih waktu ini disebut juga unaccounted for time. Terdapat banyak hal mengapa timbul unaccounted for time, misalnya un-instrumented Oracle kernel code, quantization error, measurement intrusion effect.</p>
<p>Perlu diingat penjelasan ini bukan merupakan penjelasan keseluruhan dari report yang terbentuk, jadi ada beberapa bagian dari report yang tidak saya munculkan di sini, misalnya bagian PL/SQL yang memanggil SQL statement di atas karena memiliki struktur yang sama dengan penjelasan di atas.</p>
<p>Selanjutnya kita jumpai bagian summary dari TKPROF report ini. Pada bagian berikut tampak total statistik yang dipisahkan menjadi dua bagian yaitu total statistik untuk non-recursive statement (dalam hal ini PL/SQL yang kita trace) dan total statistik untuk recursive statement. Bagian ini secara garis besar memiliki struktur yang sama seperti struktur yang saya jelaskan di atas.</p>
<pre class="brush: sql;">
OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        2      0.00       0.00          0          0          0           0
Execute      2      0.04       0.04          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      0.04       0.04          0          0          0           1

Misses in library cache during parse: 1

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  SQL*Net message to client                       2        0.00          0.00
  SQL*Net message from client                     2        0.00          0.00
  library cache lock                              1        0.00          0.00
  library cache pin                               1        0.00          0.00
  rdbms ipc reply                                77        0.00          0.00

OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch     1001      2.55       5.46      49517      39884          0      100000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total     1003      2.55       5.47      49517      39884          0      100000

Misses in library cache during parse: 1

Elapsed times include waiting on following events:
  Event waited on                             Times   Max. Wait  Total Waited
  ----------------------------------------   Waited  ----------  ------------
  KJC: Wait for msg sends to complete             2        0.00          0.00
  reliable message                                2        0.00          0.01
  enq: KO - fast object checkpoint                4        0.04          0.04
  ges inquiry response                            2        0.00          0.00
  direct path read                             2682        0.00          0.01
  enq: TT - contention                           32        0.00          0.01
  direct path write temp                        311        0.00          0.00
  direct path read temp                         311        0.00          0.00
</pre>
<p>Di akhir summary terdapat informasi mengenai jumlah SQL statement baik yang di-eksekusi oleh user ataupun oleh sys. Setelah itu terdapat informasi mengenai nama trace file beserta lokasinya, kompatibilitas/versi dari trace file, sorting option yang digunakan, total jumlah SQL statement dari beberapa perspektif, berikut total elapsed time dalam second untuk seluruh SQL statement.</p>
<pre class="brush: sql;">
    3  user  SQL statements in session.
    0  internal SQL statements in session.
    3  SQL statements in session.
********************************************************************************
Trace file: /u01/app/oracle/diag/rdbms/rac/rac3/trace/rac3_ora_6942.trc
Trace file compatibility: 11.01.00
Sort options: prsela  exeela  fchela
       1  session in tracefile.
       3  user  SQL statements in trace file.
       0  internal SQL statements in trace file.
       3  SQL statements in trace file.
       3  unique SQL statements in trace file.
    4499  lines in trace file.
       5  elapsed seconds in trace file.
</pre>
<p>Walaupun TKPROF ini merupakan tool untuk troubleshooting yang handal, namun TKPROF ini juga memiliki kelemahan, yaitu kita tidak selalu dapat memperoleh trace file dari session yang bermasalah karena <em>event 10046</em> tidak otomatis aktif, ditambah lagi jika kemunculan masalah tersebut random. Selain itu tracing event ini juga menambah overhead pada session yang di-trace karena masih harus menuliskan informasi debug pada file.</p>
  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/rudikristanto.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/rudikristanto.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/rudikristanto.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/rudikristanto.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/rudikristanto.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/rudikristanto.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/rudikristanto.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/rudikristanto.wordpress.com/34/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/rudikristanto.wordpress.com/34/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/rudikristanto.wordpress.com/34/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=34&subd=rudikristanto&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://rudikristanto.wordpress.com/2008/09/28/reading-tkprof-output/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3b3709f48c19ec27610047308b37554a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Rudi</media:title>
		</media:content>
	</item>
		<item>
		<title>Activate Extended SQL Trace</title>
		<link>http://rudikristanto.wordpress.com/2008/08/21/activate-extended-sql-trace/</link>
		<comments>http://rudikristanto.wordpress.com/2008/08/21/activate-extended-sql-trace/#comments</comments>
		<pubDate>Thu, 21 Aug 2008 05:40:16 +0000</pubDate>
		<dc:creator>Rudi Kristanto</dc:creator>
				<category><![CDATA[Trace File]]></category>
		<category><![CDATA[Troubleshooting]]></category>
		<category><![CDATA[10046]]></category>
		<category><![CDATA[TKPROF]]></category>

		<guid isPermaLink="false">http://rudikristanto.wordpress.com/?p=14</guid>
		<description><![CDATA[Kadang saat troubleshooting dibutuhkan tracing session (event 10046) yang mengalami masalah, karena dengan cara ini kita dapat menemukan SQL statement yang tidak efisien. Event-event apa saja yang dapat diaktifkan tersembunyi dalam file $ORACLE_HOME/rdbms/mesg/oraus.msg, yaitu file yang berisi error message dari kernel Oracle. Dapat ditemukan dalam file tersebut, bahwa error codes 10000 .. 10999 bukan merupakan [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=14&subd=rudikristanto&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p>Kadang saat troubleshooting dibutuhkan tracing session (<em>event 10046</em>) yang mengalami masalah, karena dengan cara ini kita dapat menemukan SQL statement yang tidak efisien. Event-event apa saja yang dapat diaktifkan tersembunyi dalam file <em>$ORACLE_HOME/rdbms/mesg/oraus.msg</em>, yaitu file yang berisi error message dari kernel Oracle. Dapat ditemukan dalam file tersebut, bahwa error codes 10000 .. 10999 bukan merupakan error message tetapi event. Jika aktif, event ini digunakan oleh Oracle developer untuk salah satu dari ketiga hal berikut:<br />
- Meng-enable atau disable suatu feature<br />
- Simulasi crash/corruption<br />
- Mencatat informasi trace atau debug</p>
<p>Debug atau trace event yang sering saya pakai untuk troubleshooting adalah:<br />
- 10046 (enable SQL statement timing)<br />
- 10053 (CBO enable optimizer trace)</p>
<p><span id="more-14"></span></p>
<p>Yang akan saya bahas di sini adalah bagaimana cara untuk mengaktifkan tracing pada debug event 10046. Perlu diketahui hasil tracing dari event ini adalah input file untuk <strong>TKPROF</strong> (Trace Kernel Profiler) yang merupakan salah satu tool yang digunakan untuk performance tuning &#8211; akan saya bahas penggunaannya di artikel selanjutnya.</p>
<p>Ada dua cara yang sering saya pakai untuk mengaktifkan debug event tergantung dari program yang akan kita trace,<br />
1. Tracing program yang source code-nya dapat kita edit<br />
2. Tracing program dimana kita tidak memiliki akses ke source code program tersebut</p>
<p><strong>Untuk tipe pertama</strong>, langkah-langkahnya sebagai berikut:</p>
<p>1. Pastikan session tersebut memiliki hak untuk alter session.</p>
<p>2. Untuk mengetahui nama trace file yang akan dibentuk jalankan salah satu SQL berikut.</p>
<pre class="brush: sql;">
--Oracle 10g dan 11g, untuk 8i, 9i belum saya coba.
select rtrim(a.value,'/')||'/'||b.instance_name||'_ora_'||
       ltrim(to_char(d.spid))||
       decode(d.traceid,null,null,'_'|| d.traceid)||
       '.trc' trace_file_name
from v$parameter a, v$instance b, v$session c, v$process d
where a.name = 'user_dump_dest' and
      c.audsid = sys_context('userenv','sessionid' ) and
      d.addr = c.paddr;

--Oracle 11g
select value
from v$diag_info
where inst_id = (select instance_number from v$instance) and
      name = 'Default Trace File';
</pre>
<p>Pastikan session ini memiliki hak akses ke v$ view di atas untuk dapat menjalankan query tersebut. Tanpa memiliki hak akses ke v$ view, pencarian trace file yang dihasilkan dapat lebih mudah dengan menjalankan perintah berikut.</p>
<pre class="brush: sql;">
alter session set tracefile_identifier = XXX;
</pre>
<p>Perintah ini akan menambahkan string XXX pada nama trace file.</p>
<p>3. Pada source code yang akan di-trace tambahkan statement berikut.</p>
<pre class="brush: sql;">
alter session set timed_statistics = true;
alter session set max_dump_file_size = unlimited;
alter session set events '10046 trace name context forever, level 12';

-- source code yang akan di-trace

alter session set events '10046 trace name context off';
</pre>
<p>4. Selesai.</p>
<p><strong>Tracing tipe kedua</strong>, langkah-langkahnya sebagai berikut:</p>
<p>1. Login dengan user yang memiliki hak untuk mengeksekusi package sys.dbms_system.</p>
<p>2. Pastikan <em>SID</em> session yang akan di-trace sudah diketahui. Jika SID tidak diketahui, maka cari lewat <em>v$session</em> kemudian difilter dengan field yang nilainya sudah diketahui, misalkan osuser, machine, program, module. Cara ini berlaku untuk aplikasi client server yang menggunakan dedicated server.</p>
<p>3. Dari SID yang diperoleh, jalankan query berikut untuk memperoleh serial# dan lokasi file trace.</p>
<pre class="brush: sql;">
select serial#, audsid
from v$session where sid = :sid

--Oracle 10g dan 11g, untuk 8i, 9i belum saya coba.
select rtrim(a.value,'/')||'/'||b.instance_name||'_ora_'||
       ltrim(to_char(d.spid))||
       decode(d.traceid,null,null,'_'||d.traceid)||
       '.trc' trace_file_name
from v$parameter a, v$instance b, v$session c, v$process d
where a.name = 'user_dump_dest' and
      c.audsid = :audsid and
      d.addr = c.paddr;
</pre>
<p>4. Gunakan nilai <em>sid </em>dan <em>serial#</em> yang telah diperoleh dari langkan no 2 dan 3 sebagai input statement berikut.</p>
<pre class="brush: sql;">
execute sys.dbms_system.set_bool_param_in_session(:sid,:serial#,'timed_statistics',true);
execute sys.dbms_system.set_ev(:sid,:serial#,10046,12,''); 

-- jalankan action yang akan di-trace (session berbeda) sampai selesai

execute sys.dbms_system.set_ev(:sid,:serial#,10046,0,'');
</pre>
<p>5. Selesai</p>
<p>Ada empat nilai level yang valid untuk debug event 10046, <em>level 1</em> = enable sql trace, <em>level 4</em> = enable sql trace dan capture bind variable value, <em>level 8</em> = enable sql trace dan capture wait event dan <em>level 12</em> = enable sql trace, capture bind variable value dan capture wait event.</p>
<p>Kedua cara tersebut bukan merupakan satu-satunya cara untuk mengaktifkan sql trace, hanya yang sering saya pakai saja. Masih ada package-package lain seperti <em>DBMS_MONITOR</em>, <em>DBMS_SESSION</em>, <em>DBMS_SUPPORT</em> ataupun dengan menggunakan fasilitas <em>ORADEBUG</em>. Beragam cara yang ditawarkan ini memiliki kelebihan dan kekurangan masing-masing dan tentunya ada yang di-support dan ada yang tidak di-support oleh Oracle.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/rudikristanto.wordpress.com/14/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/rudikristanto.wordpress.com/14/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/rudikristanto.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/rudikristanto.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/rudikristanto.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/rudikristanto.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/rudikristanto.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/rudikristanto.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/rudikristanto.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/rudikristanto.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/rudikristanto.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/rudikristanto.wordpress.com/14/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=14&subd=rudikristanto&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://rudikristanto.wordpress.com/2008/08/21/activate-extended-sql-trace/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3b3709f48c19ec27610047308b37554a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Rudi</media:title>
		</media:content>
	</item>
		<item>
		<title>Intro</title>
		<link>http://rudikristanto.wordpress.com/2008/08/18/intro/</link>
		<comments>http://rudikristanto.wordpress.com/2008/08/18/intro/#comments</comments>
		<pubDate>Mon, 18 Aug 2008 03:50:54 +0000</pubDate>
		<dc:creator>Rudi Kristanto</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Rudi Kristanto]]></category>

		<guid isPermaLink="false">http://rudikristanto.wordpress.com/?p=5</guid>
		<description><![CDATA[BLOG (Behave Like Oracle Geek) akan berisi dokumentasi tetang feature-feature Oracle yang saya peroleh baik dari eksperimen sendiri atau dari sumber lain misalnya Dokumentasi Oracle atau buku-buku Oracle. Tujuan pertama tentunya supaya mempermudah saya mengakses dokumen tersebut jika diperlukan. Kedua, mungkin juga berguna bagi siapa saja yang mengunjungi blog ini.
Script atau artikel yang berkaitan tetang [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=5&subd=rudikristanto&ref=&feed=1" />]]></description>
			<content:encoded><![CDATA[<div class='snap_preview'><br /><p><a href="http://rudikristanto.wordpress.com">BLOG</a> (<strong>B</strong>ehave <strong>L</strong>ike <strong>O</strong>racle <strong>G</strong>eek) akan berisi dokumentasi tetang feature-feature <a href="http://otn.oracle.com">Oracle</a> yang saya peroleh baik dari eksperimen sendiri atau dari sumber lain misalnya <a href="http://tahiti.oracle.com">Dokumentasi Oracle</a> atau buku-buku Oracle. Tujuan pertama tentunya supaya mempermudah saya mengakses dokumen tersebut jika diperlukan. Kedua, mungkin juga berguna bagi siapa saja yang mengunjungi blog ini.</p>
<p>Script atau artikel yang berkaitan tetang Oracle yang akan saya posting di sini pasti telah saya test dan berhasil. Jika yang terjadi sebaliknya, artinya anda mencoba dan gagal, saya tidak bertanggung jawab atas dampak apapun yang ditimbulkan.</p>
<p>Silahkan beri komentar untuk ralat, kritik dan saran.</p>
<img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/rudikristanto.wordpress.com/5/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/rudikristanto.wordpress.com/5/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/rudikristanto.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/rudikristanto.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/rudikristanto.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/rudikristanto.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/rudikristanto.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/rudikristanto.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/rudikristanto.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/rudikristanto.wordpress.com/5/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/rudikristanto.wordpress.com/5/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/rudikristanto.wordpress.com/5/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=rudikristanto.wordpress.com&blog=4537776&post=5&subd=rudikristanto&ref=&feed=1" /></div>]]></content:encoded>
			<wfw:commentRss>http://rudikristanto.wordpress.com/2008/08/18/intro/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3b3709f48c19ec27610047308b37554a?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">Rudi</media:title>
		</media:content>
	</item>
	</channel>
</rss>