<?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/"
	>

<channel>
	<title>Türkçe Oracle</title>
	<atom:link href="http://turkceoracle.com/feed" rel="self" type="application/rss+xml" />
	<link>http://turkceoracle.com</link>
	<description>Türkçe Oracle</description>
	<lastBuildDate>Thu, 05 Apr 2012 08:52:31 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.3</generator>
		<item>
		<title>TROUG BI&amp;DW SIG Etkinliği</title>
		<link>http://turkceoracle.com/2012/03/troug-bidw-sig-etkinligi.html</link>
		<comments>http://turkceoracle.com/2012/03/troug-bidw-sig-etkinligi.html#comments</comments>
		<pubDate>Fri, 09 Mar 2012 22:16:47 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[Duyuru]]></category>
		<category><![CDATA[troug]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=531</guid>
		<description><![CDATA[TROUG’un özel ilgi grubu etkinliklerinden “TROUG BI&#38;DW SIG:2012″ toplantısı 22 Mart Perşembe günü Bilginç IT Akademi’de gerçekleşecektir. Konunun uzmanları ile biraraya geleceğiniz etkinlikte İş Zekası ve Veri Ambarı konularında çeşitli sunumlar gerçekleştirilecektir.  Etkinlik TROUG üyelerine ücretsizdir. Toplantı ajandası şu şekildedir: Açılış : 12:45 TROUG Nereye Gidiyor? Sunum ID : 10 Konuşmacı : Hüsnü Şensoy (Global [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://turkceoracle.com/wp-content/uploads/2011/11/300x1051.png"><img class="alignleft size-full wp-image-508" title="300x105" src="http://turkceoracle.com/wp-content/uploads/2011/11/300x1051.png" alt="" width="300" height="105" /></a></p>
<p>TROUG’un özel ilgi grubu etkinliklerinden “TROUG BI&amp;DW SIG:2012″  toplantısı 22 Mart Perşembe günü Bilginç IT Akademi’de gerçekleşecektir.  Konunun uzmanları ile biraraya geleceğiniz etkinlikte İş Zekası ve Veri  Ambarı konularında çeşitli sunumlar gerçekleştirilecektir.  Etkinlik  TROUG üyelerine ücretsizdir.</p>
<p>Toplantı ajandası şu şekildedir:</p>
<p><strong>Açılış : 12:45</strong><br />
TROUG Nereye Gidiyor?</p>
<p><strong>Sunum ID : 10</strong><br />
Konuşmacı : Hüsnü Şensoy (Global Maksimum)<br />
Saat : 13:00 – 13:40<br />
Süre : 40 dk<br />
Sunum Başlığı : ODM Fast Track<br />
İçerik;<br />
Oracle Data Miner ile gerçekleştirilecek demo ile 40 dakikada Data Mining uygulamaları tanıtılacaktır.<br />
Kahve Molası : 13:40 – 13:55 (15 dk)</p>
<p><strong>Sunum ID : 20</strong><br />
Konuşmacı : Şeyhmus Altun (Turkcell)<br />
Saat : 13:55 – 14:35<br />
Süre : 40 dk<br />
Sunum Başlığı : ODI’da Release Management süreci ve 11.1.1.6′ya upgrade deneyimi<br />
İçerik;<br />
Kurumsal ve dinamik geliştirme oratamlarının olduğu kuruluşlarda ODI’ın  Release Management ve Team Coding özellikleri yetersiz kalabiliyor.  Release takviminden bağımsız olarak araya giren projelerin de  geliştirme, test ve canlıya alınmasına olanak sağlayan bir süreç ve araç  konusunda yapılan çalışmalar paylaşılacaktır.<br />
Turkcell’deki Datamining, CDRDM ve Market Optimization uygulamalarının  ODI 10.1.3.5′den 11.1.1.6′ya yükseltilmesi konusunda RCC (Repository  Consistency Check), UA (Upgrade Assistant) ve ayarlama (scheduler dan  tetiklenen çağrılar ve agent ayarları) işleriyle ilgili deneyimler  paylaşılacaktır.<br />
Kahve Molası : 14:35 – 14:50 (15 dk)</p>
<p><strong>Sunum ID : 30</strong><br />
Konuşmacı : Özgür Macit (I2I Systems)<br />
Saat : 14:50 – 15:30<br />
Süre : 40 dk<br />
Sunum Başlığı : Oracle 11G’de İleri SQL<br />
İçerik;<br />
Günümüz veri ambarı uygulamalarında standart SQL cümlecikleri hem  fonksiyonel hem de performans açısından yetersiz kalabilmektedir.  Veritabanı forumları ve blog siteleri SQL’in yetmediği durumda  problemine çözüm arayan birçok veritabanı yazılımcısının sorularıyla  dolup taşmaktadır. Oracle’ın bu problemlere çözüm olarak sunduğu  analitik fonksiyonlar, MODEL ve CONNECT BY cümlecikleri ve Oracle 11G  ile birlikte hayatımıza giren PIVOT/UNPIVOT operatörleri gibi  özellikleri bu problemlere çözüm üretmek için biçilmiş kaftan! Bu  sunumda Oracle 11G odağı ile Oracle’da ileri seviyede SQL yazmak için  örneklerle dolu bir içerik verilecektir.<br />
Kahve Molası : 15:30 – 15:45 (15 dk)</p>
<p><strong>Sunum ID : 40</strong><br />
Konuşmacı : Emrah Mete (Turkcell)<br />
Saat : 15:45 – 16:25<br />
Süre : 40 dk<br />
Sunum Başlığı : Oracle’ın Paralel Execution Yetenekleri ve Performans İncelemesi<br />
İçerik;<br />
Kurumsal yazılım dünyasında geliştirdiğimiz database uygulamalarının  makul sürelerde sonuçlar üretmesi  temel amaçlarımızdan biridir. Bu  temel gereksinimden hareketle Oracle’ın paralel execution yetenekleri  database uygulama geliştiricilerinin sık sık başvurduğu yöntemlerdir.  Paralel sorgulama yöntemleri, sorgu performanslarımıza katkı  sağlamasının yanı sıra  donanım kaynaklarımızıda daha efektif  kullanmamıza olanak sağlayan database altyapılarındandır. Ancak  paralel  çalışan sorgular veya objeler yazmak var olan donanım sistemimizin  özelliklerine görede farklı sonuçlar doğurabilmekte. Bu ana fikirden  hareketle, Oracle’ın paralel execution yeteneklerini ve farklı  donanımlara sahip sistemlerdeki etkilerini incelemek, paralel çalışan  database uygulamaları geliştiren yazılım geliştiriciler için farkındalık  yaratacaktır.</p>
<p><strong>Sunum ID : 50</strong><br />
Konuşmacı : Ayşe Öztop (GTech)<br />
Saat : 16:25 – 17:00<br />
Süre : 35 dk<br />
Sunum Başlığı : Ölçemediğinizi Geliştiremezsiniz : OBI 11G ile Scorecard<br />
İçerik;<br />
Performans ölçümünün önemi ve gerekliliği anlatılacaktır. Balanced  Scorecard, Robert Kaplan, David Norton hakkında genel bir  bilgilendirmenin ardından, OBI scorecard’dan bahsedilecek, faydaları ve  şirketlere kazandırabilecekleri anlatılacak ve OBI scorecard örneğinden  ekran görüntüleri eşliğinde gerçekleştirilecektir.</p>
<p>TROUG’a ücretsiz üye olmak ve yeniliklerden haberdar olmak için <a href="http://apex.oracle.com/pls/apex/f?p=38448:1:0:::::">tıklayınız</a>.</p>
<p>Bilginç IT Akademi’ye erişim için <a href="http://www.bilginc.com/default.aspx?TABLE=icerikler&amp;ID=7&amp;RELID=0">tıklayınız</a>.</p>
<p>Etkinliğe kayıt olmak için <a href="mailto:gurcan.orhan@troug.org">tıklayınız</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2012/03/troug-bidw-sig-etkinligi.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TROUG Üyelerine Packt Kitaplarında İndirim</title>
		<link>http://turkceoracle.com/2011/11/troug-uyelerine-packt-kitaplarinda-indirim.html</link>
		<comments>http://turkceoracle.com/2011/11/troug-uyelerine-packt-kitaplarinda-indirim.html#comments</comments>
		<pubDate>Fri, 18 Nov 2011 13:24:12 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[Duyuru]]></category>
		<category><![CDATA[troug]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=505</guid>
		<description><![CDATA[Türk Oracle Kullanıcı Grubu üyeleri artık “Packt Publishing” yayınevinin Oracle teknolojileri konulu kitaplarını satın alırken 20% indirim hakkına sahip. Bu indirimden faylanmak isteyen üyelerimiz, iletişim sayfamızdan üyelik için kullandıkları e-mail adreslerini belirterek, indirim kuponlarını talep edebilirler. Üyelerimiz internet üzerinden verecekleri siparişlerde bu indirim kuponu kodlarını kullanarak 22% indirim sağlayabilecekler. Packt Publishing IT teknolojileri üzerine 600’den [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://turkceoracle.com/wp-content/uploads/2011/11/Packt-Publishing-Sponsors-SurfaceWeek-2011.png"><img class="size-medium wp-image-506 alignnone" title="Packt-Publishing-Sponsors-SurfaceWeek-2011" src="http://turkceoracle.com/wp-content/uploads/2011/11/Packt-Publishing-Sponsors-SurfaceWeek-2011-300x166.png" alt="" width="257" height="142" /></a><a href="http://turkceoracle.com/wp-content/uploads/2011/11/300x1051.png"><img class="size-full wp-image-508 alignnone" title="300x105" src="http://turkceoracle.com/wp-content/uploads/2011/11/300x1051.png" alt="" width="362" height="130" /></a></p>
<p>Türk Oracle Kullanıcı Grubu üyeleri artık “<a href="http://www.packtpub.com/">Packt Publishing</a>” yayınevinin Oracle teknolojileri konulu kitaplarını satın alırken 20% indirim hakkına sahip. Bu indirimden faylanmak isteyen üyelerimiz, <a href="http://www.troug.org/?page_id=44">iletişim sayfamızdan</a> üyelik için kullandıkları e-mail adreslerini belirterek, indirim kuponlarını talep edebilirler. Üyelerimiz internet üzerinden verecekleri siparişlerde bu indirim kuponu kodlarını kullanarak 22% indirim sağlayabilecekler.</p>
<p>Packt Publishing IT teknolojileri üzerine 600’den fazla, Oracle teknolojileri üzerine ise 100’e yakın kitap yayınlamış, sektörün önde gelen yayınevlerindendir.</p>
<p>Packt’in Oracle teknolojilerine ilişkin kitaplarının listesine şu linkten ulaşabilirsiniz: <a href="http://www.packtpub.com/books/oracle">http://www.packtpub.com/books/oracle</a></p>
<p>TROUG’ye ücretsiz üye olmak için: <a href="http://apex.oracle.com/pls/apex/f?p=38448:1">http://apex.oracle.com/pls/apex/f?p=38448:1</a></p>
<p><strong>Ayrıca 4 Aralık’a kadar sürecek aşağıdaki yarışma ile ücretsiz kitap kazanma şansını kaçırmayın.</strong></p>
<p>Packt Publishing’in yaklaşık 100.000 sayfa kitap içeriği sunan online dijital kütüphanesi <a href="http://packtlib.packtpub.com/">PACKTLIB</a>’e ücretsiz erişmek istermisiniz? Ya da yukarıdaki kitapların basılı ya da elektronik kopyalarına sahip olmak? Bunun için yapmanız gereken tek şey, bunu neden istediğinizi söylemek.  Bu ufak yarışmamız ile</p>
<p>1 kişi <a href="http://packtlib.packtpub.com/">PACKTLIB</a>’e ücretsiz erişim</p>
<p>1 kişi &#8220;<a href="http://www.packtpub.com/oracle-webcenter-11g-ps3-administration-cookbook/book" target="_blank">Oracle WebCenter 11g PS3 Administration Cookbook</a>&#8221; kitabı</p>
<p>1 kişi de &#8220;<a href="http://www.packtpub.com/getting-started-with-oracle-hyperion-planning-11/book" target="_blank">Getting Started with Oracle Hyperion Planning 11</a>&#8221; e-kitabı kazanacak.</p>
<p>Yapmanız gereken yukardaki linklere tıkladığınızda açılacak sayfaların sağ kısmındaki “tweet” butonunu tıklamak ve bu hediyeyi neden istediğinizi kıcasa yazarak @turkishoug ifadesi ile Twitter üzerinden paylaşmak. Her hediyemiz için ayrı ayrı paylaşım yaparak yarışmaya katılabilirsiniz. En iyi gerekçekler seçilerek hediyelerin sahipleri belirlenecektir.</p>
<p>Yarışmaya son katılım tarihi 4 Aralık.</p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/11/troug-uyelerine-packt-kitaplarinda-indirim.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Tuning Advisor ile SQL komutlarının iyileştirilmesi – Bölüm 2</title>
		<link>http://turkceoracle.com/2011/06/sql-tuning-advisor-ile-sql-komutlarinin-iyilestirilmesi-%e2%80%93-bolum-2.html</link>
		<comments>http://turkceoracle.com/2011/06/sql-tuning-advisor-ile-sql-komutlarinin-iyilestirilmesi-%e2%80%93-bolum-2.html#comments</comments>
		<pubDate>Sun, 26 Jun 2011 19:32:01 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[performans iyileştirme]]></category>
		<category><![CDATA[Uğur İnal]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=475</guid>
		<description><![CDATA[SQL Tuning Advisor ile SQL komutlarının iyileştirilmesi yazısının ikinci bölümünde SQL iyileştirme görevlerinin oluşturulması adımından devam ediyorum. 2. SQL iyileştirme görevinin(task) oluşturulması İyileştirilme görevleri tek bir SQL komutunun textinden, birden fazla komutu barındıran bir SQL setinden yada paylaşımlı havuzdaki veya AWR raporundaki bir SQL komutununun SQL ID değeri seçilerek oluşturulabilir. Bununla beraber standart bir kullanıcının [...]]]></description>
			<content:encoded><![CDATA[<p>SQL Tuning Advisor ile SQL komutlarının iyileştirilmesi yazısının ikinci bölümünde SQL iyileştirme görevlerinin oluşturulması adımından devam ediyorum.</p>
<p><strong> 2. SQL iyileştirme görevinin(task) oluşturulması</strong></p>
<p>İyileştirilme görevleri tek bir SQL komutunun textinden, birden fazla komutu barındıran bir SQL setinden yada paylaşımlı havuzdaki veya AWR raporundaki bir SQL komutununun SQL ID değeri seçilerek oluşturulabilir.</p>
<p>Bununla beraber standart bir kullanıcının iyileştirme görevi oluşturabilmesi için; önce ADVISOR hakkına sahip olması ve ardından ilgili kullanıcının şema objeleri üzerinde bu fonsiyonun çalıştırılması gerekmektedir.</p>
<p>Aşağıda SQL iyileştirme görevini oluşturmak için kullanılan PL/SQL paketleri yer almaktadır.</p>
<p>Bir SQL textinden, bind değişkenli yada bind değişkensiz SQL iyileştirme görevi oluşturmak;</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.CREATE_TUNING_TASK(
  sql_text         IN CLOB,
  bind_list        IN sql_binds := NULL,
  user_name        IN VARCHAR2  := NULL,
  scope            IN VARCHAR2  := SCOPE_COMPREHENSIVE,
  time_limit       IN NUMBER    := TIME_LIMIT_DEFAULT,
  task_name        IN VARCHAR2  := NULL,
  description      IN VARCHAR2  := NULL)
</pre>
<p>Bir SQL textinden plan_hash_value değerine göre SQL iyileştirme görevi oluşturmak;</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.CREATE_TUNING_TASK(
  sql_id           IN VARCHAR2,
  plan_hash_value  IN NUMBER   := NULL,
  scope            IN VARCHAR2 := SCOPE_COMPREHENSIVE,
  time_limit       IN NUMBER   := TIME_LIMIT_DEFAULT,
  task_name        IN VARCHAR2 := NULL,
  description      IN VARCHAR2 := NULL)
</pre>
<p>Bir AWR raporundan ilgili snapshot aralığında  SQL iyileştirme görevi oluşturmak;</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.CREATE_TUNING_TASK(
  begin_snap      IN NUMBER,
  end_snap        IN NUMBER,
  sql_id          IN VARCHAR2,
  plan_hash_value IN NUMBER   := NULL,
  scope           IN VARCHAR2 := SCOPE_COMPREHENSIVE,
  time_limit      IN NUMBER   := TIME_LIMIT_DEFAULT,
  task_name       IN VARCHAR2 := NULL,
  description     IN VARCHAR2 := NULL)
</pre>
<p>Bir SQL setinden filtreleme şartlarına uygun SQL iyileştirme görevi oluşturmak;</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.CREATE_TUNING_TASK(
  sqlset_name       IN VARCHAR2,
  basic_filter      IN VARCHAR2 :=  NULL,
  object_filter     IN VARCHAR2 :=  NULL,
  rank1             IN VARCHAR2 :=  NULL,
  rank2             IN VARCHAR2 :=  NULL,
  rank3             IN VARCHAR2 :=  NULL,
  result_percentage IN NUMBER   :=  NULL,
  result_limit      IN NUMBER   :=  NULL,
  scope             IN VARCHAR2 :=  SCOPE_COMPREHENSIVE,
  time_limit        IN NUMBER   :=  TIME_LIMIT_DEFAULT,
  task_name         IN VARCHAR2 :=  NULL,
  description       IN VARCHAR2 :=  NULL
  plan_filter       IN VARCHAR2 :=  'MAX_ELAPSED_TIME',
  sqlset_owner      IN VARCHAR2 :=  NULL)
</pre>
<p>DBMS_SQLTUNE.CREATE_TUNING_TASK paketinde önemli olan bazı parametrelerin ne anlama geldiğine bakarsak;</p>
<p>bind_list: ANY DATA tipinde bind değişkenlerinin sıralı listesi(mesela 100 adlı bind değişkeni için => sql_binds(anydata.ConvertNumber(100))<br />
plan_hash_value: SQL çalıştırma planının hash değeri<br />
sqlset_name: Daha önceden oluşturulan SQL setinin adı<br />
time_limit: Optimizer’ın derleme için harcayacağı saniye değerinden süre<br />
basic_filter:  SQL iyileştirme seti içinden kaynak kullanımı ile ilgili filtreleme yapabilmek için kullanılan filtre değeri veya değerleri<br />
result_limit: Filtre sonucunda göre Top N sıralaması.<br />
result_percentage: Toplam ölçüt değerininin yüzdesi (örneğin paylaşımlı alanının %5 ini kullanan SQL komutlarını bulmak gibi…)<br />
scope: LIMITED veya SCOPE_COMPREHENSIVE değerini alır. Sınırlı yada daha kapsamlı durumlar için tercih edilir, LIMITED seçilirse SQL profil analizi es geçilir.<br />
rank1-2-3: Oracle kaynak kullanım tercihleri(varsayılan “elapsed_time” değeridir, eğer değiştirilmek istenirse veya yeni kaynak verileri eklenmek istenirse rank2,rank3 parametresine eklenir.)<br />
plan_filter: Aynı komut için birden fazla plan seçildiğinde kullanılan plan filtresidir (plan_hash_value) Aşağıdaki değerlerden birisini alır..</p>
<p>LAST_GENERATED: En güncel zaman mührüne sahip plan<br />
FIRST_GENERATED: En eski zaman mührüne sahip plan<br />
LAST_LOADED: En güncel first_load_time istatistiği olan plan<br />
FIRST_LOADED: En eski first_load istatistiğine sahip plan<br />
MAX_ELAPSED_TIME: Maksimum tamamlanma süresine sahip plan<br />
MAX_BUFFER_GETS: Maksmimum tampon alımına sahip plan<br />
MAX_DISK_READS: Maksimum disk okumasına sahip plan<br />
MAX_DIRECT_WRITES: Maksimum direkt yazma değerine sahip plan<br />
MAX_OPTIMIZER_COST: Maksimum optimizer cost değerine sahip plan<br />
Aşağıda bu paket ile ilgili her üç tip veri alım kriteri örnekleri yer almaktadır.</p>
<p>variable test_task VARCHAR2(80);<br />
variable test_task2 VARCHAR2(80);</p>
<p>- SQL text formatından iyileştirme;<br />
EXEC :test_task:= DBMS_SQLTUNE.CREATE_TUNING_TASK(<br />
sql_text => ‘SELECT e.employee_id, d.department_name, e.salary, e.hire_date FROM employees e,departments d WHERE e.salary IN (SELECT AVG(salary) FROM employees GROUP BY department_id) AND e.department_id=d.department_id’,<br />
user_name => ’HR’, task_name => ‘test_task’);</p>
<p>- SQL ID formatı(imleç önbelleğinden);<br />
EXEC :test_task:= DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_id => &#8217;7c6hmwaywnha9&#8242;, task_name => ‘test_task_bycache’);</p>
<p>- LIMITED scope içinde iyileştirme;<br />
EXEC :test_task:= DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_id => &#8217;7c6hmwaywnha9&#8242;, scope => &#8216;LIMITED&#8217;, task_name => ‘test_task_bycachescopelimited’);</p>
<p>- SQL komutunu iyileştirmek için derleme zamanına sadece 10 dakika verilmek istenirse;<br />
EXEC :test_task:= DBMS_SQLTUNE.CREATE_TUNING_TASK(sql_id => &#8217;7c6hmwaywnha9&#8242;, time_limit => 600, task_name => ‘test_task_bycachetimelimited’);</p>
<p>- AWR içinden ilgili SQL ID numarasına göre iyileştirme;<br />
EXEC :test_task2:= DBMS_SQLTUNE.CREATE_TUNING_TASK(begin_snap => 102,<br />
   end_snap => 103, sql_id => &#8216;lq5m4mtflgw9k&#8217;, task_name => ‘test_task_byawr’);</p>
<p>- SQL iyileştirme seti kullanarak iyileştirme; Bu işlemden önce ilgili SQL seti yüklenmelidir. Aşağıdaki örnekte, “buffer_gets” sıralamasına göre bir saat süre boyunca test_sqlset setinden iyileştirme işlemi yer almaktadır.<br />
EXEC :test_task := DBMS_SQLTUNE.CREATE_TUNING_TASK(<br />
  sqlset_name  => &#8216;test_sqlset&#8217;,<br />
  rank1        => &#8216;BUFFER_GETS&#8217;,<br />
  time_limit   => 3600,<br />
  task_name => ‘test_taskbysqlset’);</p>
<p><strong>3. SQL iyileştirme görevinin çalıştırılması</strong></p>
<p>SQL iyileştirme görevini oluşturduktan sonra bu görevin çalıştırılması gerekmektedir. Böylece SQL iyileştirme prosesi başlatılmış olur ve derleme zamanı işlemeye başlar. Bu derleme zamanı, görevi oluştururken verilen “time_limit” değerine bağlıdır. Bu süre sonunda derleme işlemi biter.</p>
<pre class="brush: sql; title: ;">
BEGIN
DBMS_SQLTUNE.EXECUTE_TUNING_TASK(‘test_task’);
END;
/
</pre>
<p>Çalışmakta olan bir SQL iyileştirme görevinin durumunu kontrol etmek için USER_ADVISOR_TASKS veya DBA_ADVISOR_LOGS görünümlerine, görevin çalıştırılma sürecini kontrol etmek için ise V$SESSION_LONGOPS görünümüne sorgu çekilebilir. Aşağıdaki ilk sorgu, derlenmesi devam eden iyileştirme görevlerini listeler, ikinci sorgu ise derlenmiş iyileştirme görevlerini listeler.</p>
<pre class="brush: sql; title: ;">
SELECT SOFAR, TOTALWORK
FROM V$ADVISOR_PROGRESS
WHERE TASK_NAME = ‘test_task';

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

SELECT task_name, status
FROM dba_advisor_log
WHERE owner = 'HR';

TASK_NAME           STATUS
---------------     -----------
test_task           COMPLETED

1 row selected.
</pre>
<p> <strong>   4. SQL iyileştirme görev sonuçlarının raporlanması</strong></p>
<p>Bu adımda çalıştırılan SQL iyileştirme görevlerinin sonuçları rapor olarak alınmaktadır. Bu işlem için DBMS_SQLTUNE.REPORT_TUNING_TASK fonksiyonu çalıştırılmaktadır. Bu raporda SQL iyileştirme tavsiyesicisinin bulguları ve tavsiyeleri yer almaktadır. Text, HTML veya XML formatında rapor alınabilir ve analiz raporu tipik, temel ve kapsamlı(all) şeklinde olabilmektedir.</p>
<p>Hazırlanacak tavsiye raporunda, komut içinde kullanılan tablo birleştirmelerinde varsa eksik indeksler ve anahtarlar tavsiye olarak işaret edilmektedir, ayrıca ulaşılan bloklar ve objeler ile ilgili detaylı bir çalıştırma planı kıyaslaması yer almaktadır. Bununla beraber SQ komutunun yeniden yapılandırılması(sorguda kullanılan birleştirme türlerinin uygunluğu,doğru sürücü tablo(lar) seçimi işareti vb.), objeler üzerinde eksik istatistikler varsa bu eksik istatistiklerin toplanması ve SQL profil oluşturulması gibi tavsiyelerde bu raporda yer alır.</p>
<p>Aşağıda SQL iyileştirme setlerinin raporlanması için kullanılan sentaks yer almaktadır.</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.REPORT_TUNING_TASK(
   task_name     IN  VARCHAR2,
   type          IN  VARCHAR2   := TEXT | HTML |XML ,
   level         IN  VARCHAR2   := TYPICAL | BASIC | ALL ,
   section       IN  VARCHAR2   := FINDING | PLAN | INFORMATION | ERROR | ALL ,
   object_id     IN  NUMBER     := NULL,
   result_limit  IN  NUMBER     := NULL -- rapor içinde bulunacak maksimum SQL komut sayısı-- )
</pre>
<p>Aşağıda bu örnekte kullandığım test_task adlı iyileştirme görevinin raporu yer almaktadır. LEVEL ve SECTION parametre değerlerini ALL olarak atıyorum.</p>
<pre class="brush: sql; title: ;">
SELECT DBMS_SQLTUNE.report_tuning_task('test _task', ‘TEXT’, ‘ALL’, ‘ALL’) FROM dual;

DBMS_SQLTUNE.REPORT_TUNING_TASK('TEST_TASK','TEXT','ALL','ALL')
-----------------------------------------------------------------------

GENERAL INFORMATION SECTION
-----------------------------------------------------------------------
Tuning Task Name                  : test_task
Tuning Task Owner                 : HR
Tuning Task ID                    : 256
Scope                             : COMPREHENSIVE
Time Limit(seconds)               : 1800
Completion Status                 : COMPLETED
Started at                        : 05/09/2011 15:44:49
Completed at                      : 05/09/2011 15:44:55
Number of Index Findings          : 1
-----------------------------------------------------------------------
Schema Name: HR
SQL ID     : 7c6hmwaywnha9
SQL Text   : SELECT e.employee_id, d.department_name, e.salary, e.hire_date FROM employees e,departments d WHERE e.salary IN (SELECT AVG(salary) FROM employees GROUP BY department_id) AND
e.department_id=d.department_id

-----------------------------------------------------------------------
FINDINGS SECTION (1 finding)
-----------------------------------------------------------------------

1- Index Finding (see explain plans section below)
--------------------------------------------------
  The execution plan of this statement can be improved by creating one or more indices.

  Recommendation (estimated benefit: 100%)
  ----------------------------------------
  - Consider running the Access Advisor to improve the physical schema design or creating the recommended index.
  - Create index HR.IDX$$_01000001 on HR.EMPLOYEES('SALARY');

  Rationale
  ---------
Creating the recommended indices significantly improves the execution plan of this statement. However, it might be preferable to run &quot;Access Advisor&quot; using a representative SQL workload as opposed to a single statement. This will allow to get comprehensive index recommendations which takes into account index maintenance overhead and additional space consumption.

-----------------------------------------------------------------------
EXPLAIN PLANS SECTION
-----------------------------------------------------------------------

1- Original
-----------
Plan hash value: 3509108563

-----------------------------------------------------------------------
| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU) | Time     |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |     2 |    96 |     9  (23) | 00:00:01 |
|   1 |  NESTED LOOPS                |             |     2 |    96 |     9  (23) | 00:00:01 |
|*  2 |   HASH JOIN SEMI             |             |     2 |    64 |     8  (25) | 00:00:01 |
|   3 |    TABLE ACCESS FULL         | EMPLOYEES   |   107 |  2033 |     3   (0) | 00:00:01 |
|   4 |    VIEW                      | VW_NSO_1    |     1 |    13 |     4  (25) | 00:00:01 |
|*  5 |     FILTER                   |             |       |       |
|          |
|   6 |      HASH GROUP BY           |             |     1 |     7 |     4  (25) | 00:00:01 |
|   7 |       TABLE ACCESS FULL      | EMPLOYEES   |   107 |   749 |     3   (0) | 00:00:01 |
|   8 |   TABLE ACCESS BY INDEX ROWID| DEPARTMENTS |     1 |    16 |     1   (0) | 00:00:01 |
|*  9 |    INDEX UNIQUE SCAN         | DEPT_ID_PK  |     1 |       |     0   (0) | 00:00:01 |
-----------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$5DA710D3
   3 - SEL$5DA710D3 / E@SEL$1
   4 - SEL$683B0107 / VW_NSO_1@SEL$5DA710D3
   5 - SEL$683B0107
   7 - SEL$683B0107 / EMPLOYEES@SEL$2
   8 - SEL$5DA710D3 / D@SEL$1
   9 - SEL$5DA710D3 / D@SEL$1

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access(&quot;E&quot;.&quot;SALARY&quot;=&quot;$nso_col_1&quot;)
   5 - filter(AVG(&quot;SALARY&quot;)&gt;0)
   9 - access(&quot;E&quot;.&quot;DEPARTMENT_ID&quot;=&quot;D&quot;.&quot;DEPARTMENT_ID&quot;)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) &quot;E&quot;.&quot;SALARY&quot;[NUMBER,22], &quot;E&quot;.&quot;EMPLOYEE_ID&quot;[NUMBER,22],
       &quot;E&quot;.&quot;HIRE_DATE&quot;[DATE,7], &quot;D&quot;.&quot;DEPARTMENT_NAME&quot;[VARCHAR2,30]
   2 - (#keys=1) &quot;E&quot;.&quot;SALARY&quot;[NUMBER,22], &quot;E&quot;.&quot;EMPLOYEE_ID&quot;[NUMBER,22],
       &quot;E&quot;.&quot;HIRE_DATE&quot;[DATE,7], &quot;E&quot;.&quot;DEPARTMENT_ID&quot;[NUMBER,22]
   3 - &quot;E&quot;.&quot;EMPLOYEE_ID&quot;[NUMBER,22], &quot;E&quot;.&quot;HIRE_DATE&quot;[DATE,7],
       &quot;E&quot;.&quot;SALARY&quot;[NUMBER,22], &quot;E&quot;.&quot;DEPARTMENT_ID&quot;[NUMBER,22]
   4 - &quot;$nso_col_1&quot;[NUMBER,22]
   5 - AVG(&quot;SALARY&quot;)[22]
   6 - (#keys=1) &quot;DEPARTMENT_ID&quot;[NUMBER,22], AVG(&quot;SALARY&quot;)[22]
   7 - &quot;SALARY&quot;[NUMBER,22], &quot;DEPARTMENT_ID&quot;[NUMBER,22]
   8 - &quot;D&quot;.&quot;DEPARTMENT_NAME&quot;[VARCHAR2,30]
   9 - &quot;D&quot;.ROWID[ROWID,10]

2- Using New Indices
--------------------
Plan hash value: 2906953147

-----------------------------------------------------------------------
| Id  | Operation                     | Name           | Rows  | Bytes | Cost (% CPU)| Time     |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                |     2 |    96 |     7 (29)| 00:00:01 |
|   1 |   NESTED LOOPS                 |                |     2 |   96 |     7 (29)| 00:00:01 |
|   2 |   NESTED LOOPS                |                |     2 |    64 |     6 (34)| 00:00:01 |
|   3 |    VIEW                       | VW_NSO_1       |     1 |    13 |     4 (25)| 00:00:01 |
|   4 |     HASH UNIQUE               |                |     1 |     7 |     4 (25)| 00:00:01 |
|*  5 |      FILTER                   |                |       |       |     |                |
|   6 |       HASH GROUP BY           |                |     1 |     7 |     4 (25)| 00:00:01 |
|   7 |        TABLE ACCESS FULL      | EMPLOYEES      |   107 |   749 |     3 (0)| 00:00:01  |
|   8 |    TABLE ACCESS BY INDEX ROWID| EMPLOYEES      |     2 |    38 |     1 (0)| 00:00:01  |
|*  9 |     INDEX RANGE SCAN          | IDX$$_01000001 |     2 |       |     0 (0)| 00:00:01  |
|  10 |   TABLE ACCESS BY INDEX ROWID | DEPARTMENTS    |     1 |    16 |     1 (0)| 00:00:01 |
|* 11 |    INDEX UNIQUE SCAN          | DEPT_ID_PK     |     1 |       |     0 (0)| 00:00:01 |
-----------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$5DA710D3
   3 - SEL$683B0107 / VW_NSO_1@SEL$5DA710D3
   4 - SEL$683B0107
   7 - SEL$683B0107 / EMPLOYEES@SEL$2
   8 - SEL$5DA710D3 / E@SEL$1
   9 - SEL$5DA710D3 / E@SEL$1
  10 - SEL$5DA710D3 / D@SEL$1
  11 - SEL$5DA710D3 / D@SEL$1

Predicate Information (identified by operation id):
---------------------------------------------------

   5 - filter(AVG(&quot;SALARY&quot;)&gt;0)
   9 - access(&quot;E&quot;.&quot;SALARY&quot;=&quot;$nso_col_1&quot;)
  11 - access(&quot;E&quot;.&quot;DEPARTMENT_ID&quot;=&quot;D&quot;.&quot;DEPARTMENT_ID&quot;)

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) &quot;E&quot;.&quot;EMPLOYEE_ID&quot;[NUMBER,22], &quot;E&quot;.&quot;HIRE_DATE&quot;[DATE,7],
       &quot;E&quot;.&quot;SALARY&quot;[NUMBER,22], &quot;D&quot;.&quot;DEPARTMENT_NAME&quot;[VARCHAR2,30]
   2 - (#keys=0) &quot;E&quot;.&quot;EMPLOYEE_ID&quot;[NUMBER,22], &quot;E&quot;.&quot;HIRE_DATE&quot;[DATE,7],
       &quot;E&quot;.&quot;SALARY&quot;[NUMBER,22], &quot;E&quot;.&quot;DEPARTMENT_ID&quot;[NUMBER,22]
   3 - &quot;$nso_col_1&quot;[NUMBER,22]
   4 - (#keys=1) AVG(&quot;SALARY&quot;)[22]
   5 - AVG(&quot;SALARY&quot;)[22]
   6 - (#keys=1) &quot;DEPARTMENT_ID&quot;[NUMBER,22], AVG(&quot;SALARY&quot;)[22]
   7 - &quot;SALARY&quot;[NUMBER,22], &quot;DEPARTMENT_ID&quot;[NUMBER,22]
   8 - &quot;E&quot;.&quot;EMPLOYEE_ID&quot;[NUMBER,22], &quot;E&quot;.&quot;HIRE_DATE&quot;[DATE,7],
       &quot;E&quot;.&quot;SALARY&quot;[NUMBER,22],
       &quot;E&quot;.&quot;DEPARTMENT_ID&quot;[NUMBER,22]
   9 - &quot;E&quot;.ROWID[ROWID,10], &quot;E&quot;.&quot;SALARY&quot;[NUMBER,22]
  10 - &quot;D&quot;.&quot;DEPARTMENT_NAME&quot;[VARCHAR2,30]
  11 - &quot;D&quot;.ROWID[ROWID,10]

-----------------------------------------------------------------------
</pre>
<p>Yukardaki raporda iyileştirme görevi kapsamındaki SQL komut textinin 1. kısım mevcut mimaride çalıştırılması halinde çalıştırma planını, 2. kısım ise tavsiye sonucunda çalıştırılması halinde çalıştırma planını göstermektedir.</p>
<p>İyileştirme işlemi tamamlandığında veya ilerde bu SQL iyileştirme görevlerine ihtiyaç kalmadığında, tüm içeriğiyle beraber Oracle sistemden silinebilir.</p>
<pre class="brush: sql; title: ;">
BEGIN
  DBMS_SQLTUNE.drop_tuning_task (task_name =&gt; 'test _task');
  DBMS_SQLTUNE.drop_tuning_task (task_name =&gt; 'test _taskbycache');
  DBMS_SQLTUNE.drop_tuning_task (task_name =&gt; 'test_taskbycachescopelimited');
DBMS_SQLTUNE.drop_tuning_task (task_name =&gt; 'test_taskbycachetimelimited');
DBMS_SQLTUNE.drop_tuning_task (task_name =&gt; 'test_taskbyawr');
  DBMS_SQLTUNE.drop_tuning_task (task_name =&gt; 'test_taskbysqlset');
END;
/
</pre>
<p><span style="color: #0000ff;"><strong>Uğur İnal </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/06/sql-tuning-advisor-ile-sql-komutlarinin-iyilestirilmesi-%e2%80%93-bolum-2.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Tuning Advisor ile SQL komutlarının iyileştirilmesi – Bölüm 1</title>
		<link>http://turkceoracle.com/2011/06/sql-tuning-advisor-ile-sql-komutlarinin-iyilestirilmesi-%e2%80%93-bolum-1.html</link>
		<comments>http://turkceoracle.com/2011/06/sql-tuning-advisor-ile-sql-komutlarinin-iyilestirilmesi-%e2%80%93-bolum-1.html#comments</comments>
		<pubDate>Sun, 26 Jun 2011 19:26:43 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[performans iyileştirme]]></category>
		<category><![CDATA[Uğur İnal]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=472</guid>
		<description><![CDATA[SQL Tuning Advisor(SQL İyileştirme Tavsiyecisi), talep olduğunda bir veya birçok SQL komutunun manuel olarak iyileştirilmesinde de kullanılmaktadır. Birçok komutu iyileştirmek için öncelikle SQL iyileştirme setlerinin oluşturulması gerekmektedir. SQL Tuning Advisor için gerekli olan veriler aşağıdaki gibi pekçok farklı kaynaktan sağlanabilir. ADDM( Automatic Database Diagnostic Monitor) Ana veri sağlama kaynağı ADDM’dir. Varsayılan olarak ADDM proaktif olarak [...]]]></description>
			<content:encoded><![CDATA[<p>SQL Tuning Advisor(SQL İyileştirme Tavsiyecisi), talep olduğunda bir veya birçok SQL komutunun manuel olarak iyileştirilmesinde de kullanılmaktadır. Birçok komutu iyileştirmek için öncelikle SQL iyileştirme setlerinin oluşturulması gerekmektedir.</p>
<p>SQL Tuning Advisor için gerekli olan veriler aşağıdaki gibi pekçok farklı kaynaktan sağlanabilir.</p>
<p><strong>ADDM( Automatic Database Diagnostic Monitor)</strong><br />
Ana veri sağlama kaynağı ADDM’dir. Varsayılan olarak ADDM proaktif olarak her saat başı bir sefer çalışır ve son bir saat boyunca aşırı yüklü SQL komutlarını içeren bir kısım performans problemlerini belirlemek için AWR tarafından toplanan anahtar istatistikleri analiz eder. Eğer aşırı yüklü SQL belirlenirse, ADDM bu SQL komutu üzerinde SQL Tuning Advisor’ı çalıştırmayı tavsiye eder.</p>
<p><strong>AWR(Automatic Workload Repository)</strong><br />
İkinci en önemli veri sağlama kaynağıda AWR’dir. AWR,CPU tüketimi ve bekleme süresi gibi ilişkili istatistikler tarafından sıralanan aşırı yüklü SQL komutlarını içeren sistem aktivitelerinin düzenli snapshotlarını çeker. İlgili AWR raporuna bakıldığında en çok kaynak tüketen SQL komutları belirlenebilir. Oracle, bu SQL komutları için otomatik iyileştirme tavsiyelerini sağlamasına rağmen manuel olarakta SQL Tuning Advisor çalıştırılabilir. AWR normalde çektiği bir snapshotu sekiz gün saklar.</p>
<p><strong>Paylaşımlı SQL alanı</strong><br />
Üçüncü veri kaynağı ise paylaşımlı SQL alanıdır. Henüz AWR tarafında snapshhotu çekilmemiş olan son çalıştırılan SQL komutlarını iyileştirmek için kullanılmaktadır.</p>
<p><strong>SQL iyileştirme seti (STS)</strong><br />
Diğer bir muhtemel veri sağlama kaynağı ise SQL iyileştirme setidir. SQL iyileştirme seti birçok SQL komutunun çalıştırma içeriklerini saklayan bir veritabanı objesidir.</p>
<p>             <strong>SQL İyileştirme Tavsiyecisinin çalıştırılması</strong></p>
<p>SQL iyileştirme tavsiyecisini çalıştırmanın en basit yolu Enterprise Manager konsoludur. Diğer bir yol ise, DBMS_SQLTUNE paketini komut satırından kullanarak SQL iyileştirme tavsiyecisini çalıştırmaktır ki bu yazıda DBMS_SQLTUNE paketi kullanımını inceleyeceğiz.</p>
<p>SQl iyileştirme tavsiyecisinin çalıştırılması için aşağıdaki adımların izlenmesi gerekmektedir.</p>
<p>Eğer birden fazla SQL komutu iyileştirilecekse bir SQL iyileştirme seti oluşturulur.<br />
Bir SQL iyileştirme görevi oluşturulur.<br />
SQL iyileştirme görevi çalıştırılır.<br />
SQL iyileştirme görevinin sonuçları görüntülenir.<br />
Tavsiyeler yerindeyse uygulanır.</p>
<p>Şimdi yukardaki beş adımın her birini sırasıyla inceleyelim. Bu yazıda sadece SQL iyileştirme setinin oluşturulması ve içerisine filtrelenmiş SQL komutlarının nasıl yükleneceğine bakacağız.</p>
<p><strong>1 &#8211; SQL iyileştirme setinin oluşturulması</strong></p>
<p>Birden fazla SQL komutunu tek bir SQL seti içerisinde toplamak için önce bir set oluşturulmalı ve ihtiyaca uygun SQL komutları filtrelenip bu sete yüklenmelidir. İlgili SQL komutlarının filtrelenmesinde paylaşımlı bellek alanı veya herhangi bir AWR raporu kullanılabilir.</p>
<p>İlk adım olarak bir SQL seti aşağıdaki gibi oluşturulmalıdır.</p>
<pre class="brush: sql; title: ;">
BEGIN
DBMS_SQLTUNE.CREATE_SQLSET(sqlset_name =&gt; ‘test_sqlset’);
END;
/
</pre>
<p> &#8211; İmleç önbelleğinden yükleme</p>
<p>Paylaşımlı SQL alanından imleç önbelleğinde bulunan ve filtreleme şartlarına uyan SQL komutlarını seçip, ilgili SQL setine yüklemek için MS_SQLTUNE.SELECT_CURSOR_CACHE ve DBMS_SQLTUNE.LOAD_SQLSET komutlarının birlikte kullanıldığı bir PL/SQL bloğu çalıştırılır.</p>
<p>Aşağıdaki örnekte, imleç önbelleğinde bulunan SQL textlerinin içinde TBL_STOKGIRIS kelimesi geçen ve HR kullanıcısına ait tüm SQL komutları seçilip test_sqlset adlı SQL seti içerisine yüklenmektedir.</p>
<pre class="brush: sql; title: ;">
DECLARE
  testgiris  DBMS_SQLTUNE.sqlset_cursor;
BEGIN
  OPEN testgiris FOR
     SELECT VALUE(X)
     FROM   TABLE( DBMS_SQLTUNE.select_cursor_cache(
                basic_filter   =&gt; 'sql_text LIKE ''%tbl_stokgiris%''  and parsing_schema_name = ''HR''',
                attribute_list =&gt; 'ALL')
            ) X;

  DBMS_SQLTUNE.load_sqlset(sqlset_name     =&gt; 'test_sqlset',
                           populate_cursor =&gt; testgiris);
END;
/
</pre>
<p>DBMS_SQLTUNE.SELECT_CURSOR_CACHE fonksiyonu ile birlikte kullanılan parameterlerin ne anlama geldikleri aşağıda yer almaktadır.</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.SELECT_CURSOR_CACHE (
  basic_filter        IN   VARCHAR2 := NULL,
  object_filter       IN   VARCHAR2 := NULL,
  ranking_measure1    IN   VARCHAR2 := NULL,
  ranking_measure2    IN   VARCHAR2 := NULL,
  ranking_measure3    IN   VARCHAR2 := NULL,
  result_percentage   IN   NUMBER   := 1,  -&gt; sıralamaya bağlı top N listesinin yüzdesel değeri
  result_limit        IN   NUMBER   := NULL, à Top sınır listesi
  attribute_list      IN   VARCHAR2 := NULL à BASIC | TYPICAL | ALL değerlerinden birisi)
</pre>
<p>Aşağıda basic_filter parametresi ile kullanılan bazı örnekler yer almaktadır.</p>
<p>basic filter => &#8216;buffer_gets > 500&#8242;                     &#8212; 500 tampon alımı yapan SQL komutları alır<br />
basic filter => &#8216;elapsed_time > 5000000&#8242;          &#8212; En az 5 saniye çalışan tüm komutları alır<br />
basic_filter => ‘sharable_mem > 5242880’      &#8212; 5 MB üzerinde paylaşımlı bellek kullanan tüm komutları alır<br />
basic_filter => ‘parse_calls > 300 and  executions < 2* parse_calls’       -- En az 300 hard parse yapan tüm komutları alır</p>
<p>Bunun yanında tamamlanma süresine göre büyükten küçüğe TOP 10 SQL sıralamasındaki komutları imleç önbelleğinden almak için;</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.SELECT_CURSOR_CACHE(
basic_filter =&gt; &#8216;ELAPSED_TIME&#8217;,
result_percentage =&gt; 1,
result_limit =&gt; 10)
</pre>
<p>Önbellek içinde tampon alımlarının %80’ini kullanan SQL komutlarını imleç önbelleğinden almak için;</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.SELECT_CURSOR_CACHE(
basic_filter =&gt; 'BUFFER_GETS',
result_percentage =&gt; .8)
</pre>
<p>  - AWR raporundan yükleme</p>
<p>AWR raporundan SQL setine ilgili filtrelenmiş SQL komutlarını yüklemek için;</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.SELECT_WORKLAOD_REPOSITORY (
  begin_snap        IN NUMBER,
  end_snap          IN NUMBER,
  basic_filter      IN VARCHAR2 := NULL,
  object_filter     IN VARCHAR2 := NULL,
  ranking_measure1  IN VARCHAR2 := NULL,
  ranking_measure2  IN VARCHAR2 := NULL,
  ranking_measure3  IN VARCHAR2 := NULL,
  result_percentage IN NUMBER   := 1,
  result_limit      IN NUMBER   := NULL
  attribute_list    IN   VARCHAR2 := NULL)
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
DBMS_SQLTUNE.SELECT_WORKLAOD REPOSITORY (
  baseline_name     IN VARCHAR2,
  basic_filter      IN VARCHAR2 := NULL,
  object_filter     IN VARCHAR2 := NULL,
  ranking_measure1  IN VARCHAR2 := NULL,
  ranking_measure2  IN VARCHAR2 := NULL,
  ranking_measure3  IN VARCHAR2 := NULL,
  result_percentage IN NUMBER   := 1,
  result_limit      IN NUMBER   := NULL)
  attribute_list    IN   VARCHAR2 := NULL)
</pre>
<p>Fonksiyondaki parametrelerin anlamları SELECT_CURSOR_CACHE fonksiyonundaki parametreler ile aynıdır. Sadece AWR raporunun başlangıç ve bitiş snapshot parametreleri(ilk paket) ile snapshot baseline ismi(ikinci paket) ek parametrelerdir.</p>
<p>Şimdi AWR raporlarından SQL komutlarını alıp ilgili SQL setine yükleme örneğini inceleyelim. 713 ve 721 arasındaki AWR snapshotlarında tamamlanma süresi en uzun olan 10 SQL komutu çekilip test_sqlset adlı SQL seti içine yüklenmektedir.</p>
<pre class="brush: sql; title: ;">
DECLARE
  testgiris  DBMS_SQLTUNE.sqlset_cursor;
BEGIN
  OPEN testgiris FOR
     SELECT VALUE(X)
     FROM   TABLE( DBMS_SQLTUNE.select_workload_repository
                begin_snap =&gt; 713
                end_snap =&gt; 721
                basic_filter =&gt; ‘elapsed_time’
                result_limit =&gt; 10
                attribute_list =&gt; 'ALL')
            ) X;                                               

  DBMS_SQLTUNE.load_sqlset(sqlset_name     =&gt; 'test_sqlset',
                           populate_cursor =&gt; testgiris);
END;
/
</pre>
<p><span style="color: #0000ff;"><strong>Uğur İnal </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/06/sql-tuning-advisor-ile-sql-komutlarinin-iyilestirilmesi-%e2%80%93-bolum-1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DBMS_SQLTUNE paketi ile SQL uygulamalarının analizi</title>
		<link>http://turkceoracle.com/2011/06/dbms_sqltune-paketi-ile-sql-uygulamalarinin-analizi.html</link>
		<comments>http://turkceoracle.com/2011/06/dbms_sqltune-paketi-ile-sql-uygulamalarinin-analizi.html#comments</comments>
		<pubDate>Sun, 26 Jun 2011 19:23:28 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[performans iyileştirme]]></category>
		<category><![CDATA[Uğur İnal]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=466</guid>
		<description><![CDATA[Oracle 11g sürümünden itibaren, DBMS_SQLTUNE paketi içinden SELECT_SQL_TRACE fonksiyonu çalıştırılmaktadır. Bu fonsiyonun amacı; SQL izleme dosyasının içeriğini bir SQL iyileştirme seti içerisine yüklemektir. Bu yazımın amacı SELECT_SQL_TRACE fonksiyonunu kullanarak SQL komutlarının içeriğinin SQL izleme dosyasından görülebilmesinin kullanımını ve faydalarını göstermektir. SELECT_SQL_TRACE özelliği Oracle 11.1.0.7 sürümünden itibaren işlemdedir, yani bu sürüm öncesi Oracle 11g sürümlerinde çalışmaz. [...]]]></description>
			<content:encoded><![CDATA[<p>Oracle 11g sürümünden itibaren, DBMS_SQLTUNE paketi içinden SELECT_SQL_TRACE fonksiyonu çalıştırılmaktadır. Bu fonsiyonun amacı; SQL izleme dosyasının içeriğini bir SQL iyileştirme seti içerisine yüklemektir. Bu yazımın amacı SELECT_SQL_TRACE fonksiyonunu kullanarak SQL komutlarının içeriğinin SQL izleme dosyasından görülebilmesinin kullanımını ve faydalarını göstermektir.</p>
<p>SELECT_SQL_TRACE özelliği Oracle 11.1.0.7 sürümünden itibaren işlemdedir, yani bu sürüm öncesi Oracle 11g sürümlerinde çalışmaz. Kısaca DBMS_SQLTUNE.SELECT_SQL_TRACE fonsiyonu ile kullanılan parametrelerin kısaca anlamlarına ve nasıl kullanıldığına gelirsek;</p>
<pre class="brush: sql; title: ;">
dbms_sqltune.select_sql_trace(
            directory =&gt; 'TRACE',
            file_name =&gt; 'aysun_ora_21351.trc',
            select_mode =&gt; 1 | 2 )
</pre>
<p>directory: SQL izleme dosyalarının yer aldığı fiziksel lokasyonu işaret eden sanal dizinin ismidir. CREATE DIRECTORY komutu ile oluşturulur.<br />
file_name: SQL izleme setine yüklenecek olan SQL izleme dosyasının adı.<br />
select_mode: 1 veya 2 integer değerinden birini alır. 1=> SINGLE_EXECUTION, yani tek bir SQL çalıştırmasını döndürür 2=>ALL_EXECUTIONS, yani tüm SQL çalıştırmalarını döndürür</p>
<p>İlk olarak senaryoyu belirleyelim.</p>
<p>Gerekli veritabanı objelerini oluşturup obje istatistiklerini topluyoruz. Bu amaçla 10,000 satırdan oluşan test1 adında bir tablo ile bu tablonun id kolonunu işaret eden primary key indeksini oluşturup, tablonun tüm satırlarını istatistiklemeye dahil etmek üzere tablo istatistiklerini topluyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; CREATE TABLE test1
  2  AS
  3  SELECT rownum AS id, dbms_value.string(‘U’,50) AS adres
  4  FROM dual
  5  CONNECT BY level &lt;= 10000
  6  ORDER BY dbms_random.value;

SQL&gt; ALTER TABLE test1 ADD CONSTRAINT test1_pk PRIMARY KEY (id);

SQL&gt; BEGIN
  2    dbms_stats.gather_table_stats(
  3      ownname          =&gt; hr,
  4      tabname          =&gt; 'test1',
  5      estimate_percent =&gt; 100,
  6      method_opt       =&gt; 'for all columns size 1'
  7    );
  8  END;
  9  /
</pre>
<p>SQL izlemesini etkinleştiriyorum. Bu arada Oracle 11g itibariyle SQL izlemesinde devreye giren PLAN_STAT adlı parametreyide kullanıyorum. PLAN_STAT parametresi, satır kaynak istatistiklerinin hangi sıklıkta izleme dosyalarına yazıldığını belirtmeye yaramaktadır. Bu parametre 3 değer alabilmektedir. NEVER: çalıştırma planı hakkında hiç bir bilgi izleme dosyasına yazılmaz. FIRST_EXECUTION: Çalıştırma planı ile ilgili bilgi ilk çalıştırmadan sonra izleme dosyasına yazılır. ALL_EXECUTIONS: Her çalıştırma sonrasında çalıştırma planı ile ilgili bilgi izleme dosyasına yazılmaktadır. Bu önemli bir parameterdir, çünkü Oracle 10g’de bilhassa imleçleri uzun zaman açık tutan uygulamalar için,  her bir imleç için çalıştırma planları hakkında bilgiye izleme dosyalarında rastlamak mümkün değildi.</p>
<pre class="brush: sql; title: ;">
SQL&gt; execute dbms_monitor.session_trace_enable(binds =&gt; TRUE, plan_stat =&gt; 'ALL_EXECUTIONS')
</pre>
<p>Sistemde bir takım sorgular oluşturuyoruz. Bilhassa imleç işlemleri ile bu basit sorguları çalıştırıyorum. </p>
<pre class="brush: sql; title: ;">
SQL&gt; EXECUTE :id := 5;

SQL&gt; SELECT count(adres) FROM test1 WHERE id &lt; :id;

COUNT(adres)
------------
         4

SQL&gt; EXECUTE :id := 850;

SQL&gt; SELECT count(adres) FROM test1 WHERE id &lt; :id;

COUNT(adres)
----------
       849

SQL&gt; SELECT count(adres) FROM test1 WHERE id &lt; :id;

COUNT(adres)
----------
       849

SQL&gt; EXECUTE :id := 35;

SQL&gt; SELECT count(adres) FROM test1 WHERE id &lt; :id;

COUNT(adres)
----------
        34

SQL&gt; SELECT sum(id) FROM test1;

   SUM(ID)
----------
  50005000
</pre>
<p>SQL izlemesini devredışı bırakıyorum ve SQL izleme dosyasının adını alıyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; execute dbms_monitor.session_trace_disable

SQL&gt; SELECT value
  2  FROM v$diag_info
  3  WHERE name = 'Default Trace File';

VALUE
--------------------------------------------------------------
/u00/app/oracle/diag/rdbms/aysun/aysun/trace/aysun_ora_21351.trc
</pre>
<p>SQL komutları arasından SQL dosyalarını okumak için bir dizin oluşturuyorum. </p>
<pre class="brush: sql; title: ;">
SQL&gt; CREATE DIRECTORY trace AS '/u00/app/oracle/diag/rdbms/aysun/aysun/trace/';
</pre>
<p>Şimdi artık bir SQL izleme dosyası mevcuttur. Şimdi bu dosyanın içeriğini bazı basit sorgular ile nasıl okuyabileceğimizi ve ne tür birgileri dışarı çıkarabileceğimizi göreceğiz.</p>
<p>Bu kullanıcı tarafından çalıştırılan SQL komutlarının listesini tamamlanma süreleri ve çalıştırma sayıları ile alıyorum ve SYS kullanıcısı tarafından çalıştırılan recursive SQL komutlarını hariç tutuyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; SELECT sql_id,
  2         sum(elapsed_time) AS elapsed_time,
  3         sum(executions) AS executions,
  4         round(sum(elapsed_time)/sum(executions)) AS elapsed_time_per_execution
  5  FROM table(dbms_sqltune.select_sql_trace(
  6               directory =&gt; 'TRACE',
  7               file_name =&gt; 'aysun_ora_21351.trc',
  8               select_mode =&gt; 2
  9            )) t
 10  WHERE parsing_schema_name = 'HR'
 11  GROUP BY sql_id
 12  ORDER BY elapsed_time DESC;

SQL_ID          ELAPSED_TIME EXECUTIONS ELAPSED_TIME_PER_EXECUTION
-------------   ------------ ---------- --------------------------
aot15tfsat23u   249757       4          62439
3tgnxpwym1dcq   4200         1          4200
</pre>
<p>Belirli bir SQL komutunun SQL textini alıyoruz.</p>
<pre class="brush: sql; title: ;">
SQL&gt; SELECT sql_text
  2  FROM table(dbms_sqltune.select_sql_trace(
  3               directory =&gt; 'TRACE',
  4               file_name =&gt; 'aysun_ora_21351.trc',
  5               select_mode =&gt; 1
  6            )) t
  7  WHERE sql_id = 'aot15tfsat23u';

SQL_TEXT
---------------------------------------
SELECT count(adres) FROM t WHERE id &lt; :id
</pre>
<p>Belirli bir SQL komutu hakkında daha fazla çalıştırma istatistiklerini alıyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; SELECT plan_hash_value, executions, fetches, elapsed_time, cpu_time, disk_reads, buffer_gets, rows_processed
  2  FROM table(dbms_sqltune.select_sql_trace(
  3               directory =&gt; 'TRACE',
  4               file_name =&gt; 'aysun_ora_21351.trc',
  5               select_mode =&gt; 2
  6            )) t
  7  WHERE sql_id = 'aot15tfsat23u'
  8  ORDER BY elapsed_time DESC;

PLAN_HASH_VALUE EXECUTIONS    FETCHES ELAPSED_TIME   CPU_TIME DISK_READS BUFFER_GETS ROWS_PROCESSED
--------------- ---------- ---------- ------------ ---------- ---------- ----------- --------------
     5294676952          1          2       129056     127981        731         992              1
     5294676952          1          2       113667     112982        691        1434              1
     5294676952          1          2         5993       6999         11          11              1
     5294676952          1          2         1041       1000          0          21              1
</pre>
<p>Bind değişkenlerinin değerlerini alıyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; SELECT elapsed_time,
  2         value(b).gettypename() AS type,
  3         value(b).accessnumber() AS value
  4  FROM table(dbms_sqltune.select_sql_trace(
  5               directory =&gt; 'TRACE',
  6               file_name =&gt; 'aysun_ora_21351.trc',
  7               select_mode =&gt; 2
  8            )) t,
  9       table(bind_list) b
 10  WHERE sql_id = 'aot15tfsat23u'
 11  ORDER BY elapsed_time DESC;

ELAPSED_TIME TYPE       VALUE
------------ ---------- -----
      120543 SYS.NUMBER   990
      112375 SYS.NUMBER   990
        5891 SYS.NUMBER    10
        1172 SYS.NUMBER    20
</pre>
<p>Herşeyin iyi gözükmesine rağmen DBMS_SQLTUNE.SELECT_SQL_TRACE kullanımı ile alınan sonuçta bir takım hatalarda yok değildir. Özellikle, çalıştırma planın hash değeri tüm çalıştırılan SQL komutları için aynı gözüktüğünden dolayı hash değerleri her zaman doğru listelenmeyebilir. Bunun sebebi Oracle 11g ile kullanılmaya başlanan “adaptive cursor sharing” özelliğindendir. Doğru hash değerleri, SQL izleme dosyalarına TKPROF ile bakıldığında ortaya çıkmaktadır. Aşağıda, TKPOF komutunun AGGREGATE parametresinin “NO” değeri ile çalıştırılması sonuçları yer almaktadır. Üçüncü çalıştırmanın(kırmızı olan) hash değerinin farklı olduğuna dikkat ediniz.</p>
<pre class="brush: sql; title: ;">
...
SQL ID: aot15tfsat23u
Plan Hash: 5170755809
SELECT count(adres) FROM t WHERE id &lt; :id
...
SQL ID: aot15tfsat23u
Plan Hash: 5170755809
SELECT count(adres) FROM t WHERE id &lt; :id
...
SQL ID: aot15tfsat23u
Plan Hash: 2966233522
SELECT count(pad) FROM t WHERE id &lt; :id
...
SQL ID: aot15tfsat23u
Plan Hash: 5170755809
SELECT count(adres) FROM t WHERE id &lt; :id
...
</pre>
<p>SELECT_SQL_TRACE fonksiyonu üzerinden alınabilecek diğer bir bilgi ise çalıştırma planıdır. Ne yazıkki, bunu direct olarak bu fonksiyon üzerinden ekstrakt etmek sakıncalıdır. Bunun sebebi format işleminin kendi başımıza yapılması gerekliliğidir. Daha kolayı ise, bir SQL iyileştirme seti oluşturarak bilginin bu SQL iyileştirme setine yüklenmesi ve ardından DBMS_XPLAN paketi ile bu SQL iyileştirme setinin içeriğinin gösterilmesidir. Aşağıdaki örnekte bu olay gösterilmektedir.</p>
<pre class="brush: sql; title: ;">
SQL&gt; DECLARE
  2    c sys_refcursor;
  3  BEGIN
  4    dbms_sqltune.create_sqlset('TEST');
  5    OPEN c FOR
  6      SELECT value(t)
  7      FROM table(dbms_sqltune.select_sql_trace(
  8               directory =&gt; 'TRACE',
  9               file_name =&gt; 'aysun_ora_21351.trc',
 10               select_mode =&gt; 2
 11                )) t;
 12    dbms_sqltune.load_sqlset('TEST', c);
 13    CLOSE c;
 14  END;
 15  /

SQL&gt; SELECT *
  2  FROM table(dbms_xplan.display_sqlset(
  3               sqlset_name =&gt; 'TEST',
  4               sql_id =&gt; 'aot15tfsat23u'
  5            ));

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------
SQL Tuning Set Name: TEST
SQL Tuning Set Owner: HR
SQL_ID: aot15tfsat23u
SQL Text: SELECT count(adres) FROM t WHERE id &lt; :id
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
| Id  | Operation                    | Name                 | Bytes | Cost  |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                      |       |       |
|   1 |  SORT AGGREGATE              |                      |       |       |
|   2 |   TABLE ACCESS BY INDEX ROWID| UNKNOWN_OBJECT_90222 |  9045 |    11 |
|   3 |    INDEX RANGE SCAN          | UNKNOWN_OBJECT_90223 |       |     2 |
-----------------------------------------------------------------------------
</pre>
<p>Bu durumda sadece tek bir çalıştırma planı görülmektedir. Her ne kadar yeni ve iyi bir özellik olsada bekleme olaylarının görülmemesinden dolayı profiler aracının yerine geçmesi mümkün olmamaktadır, ancak bekleme olaylarının gözlenmesinin gerekmediği durumlarda, okuma kolaylığı ve komutların kolayca çalıştırılıp sonuçların düzgün formatta alınmasından dolayı kullanımı elverişli olacaktır.</p>
<p><span style="color: #0000ff;"><strong>Uğur İnal </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/06/dbms_sqltune-paketi-ile-sql-uygulamalarinin-analizi.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Event 10046 izleme dosyaları ile SQL komutlarında bekleme olaylarının analizi</title>
		<link>http://turkceoracle.com/2011/06/event-10046-izleme-dosyalari-ile-sql-komutlarinda-bekleme-olaylarinin-analizi.html</link>
		<comments>http://turkceoracle.com/2011/06/event-10046-izleme-dosyalari-ile-sql-komutlarinda-bekleme-olaylarinin-analizi.html#comments</comments>
		<pubDate>Sun, 26 Jun 2011 19:18:59 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[performans iyileştirme]]></category>
		<category><![CDATA[Uğur İnal]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=458</guid>
		<description><![CDATA[10046 genişletilmiş SQL izleme dosyaları, bir instance için değişik seviyelerde detay almak için kullanılmaktadır. Genişletilmiş SQL izlemeleri, level 4(bind değişkenleri), level 8 (bekleme olayları) veya level 12 (bind değişkenleri ve bekleme olayları) Event(olay) 10046 ayarı ile etkinleştirilir. Olay 10046’yı etkinleştirebilmek için bazı metotlar vardır, genelde Oracle sürümüne bağlı olsada ve oturum içinde interaktif olarak ayaralanamayan [...]]]></description>
			<content:encoded><![CDATA[<p>10046 genişletilmiş SQL izleme dosyaları, bir instance için değişik seviyelerde detay almak için kullanılmaktadır. Genişletilmiş SQL izlemeleri, level 4(bind değişkenleri), level 8 (bekleme olayları) veya level 12 (bind değişkenleri ve bekleme olayları)  Event(olay) 10046 ayarı ile etkinleştirilir. Olay 10046’yı etkinleştirebilmek için bazı metotlar vardır, genelde Oracle sürümüne bağlı olsada ve oturum içinde interaktif olarak ayaralanamayan olaylara dahil olsada, bu metotlar aşağıda yer almaktadır.  </p>
<pre class="brush: sql; title: ;">
  ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 12';
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
  EXEC SYS.DBMS_SYSTEM.SET_EV(SID,SERIAL#,10046,12,'');
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
  EXEC SYS.DBMS_SUPPORT.START_TRACE_IN_SESSION(SID,SERIAL#,WAITS=&gt;TRUE,BINDS=&gt;FALSE);
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
  EXEC DBMS_MONITOR.SESSION_TRACE_ENABLE(SESSION_ID=&gt;SID,SERIAL_NUM=&gt;SERIAL#,WAITS=&gt;TRUE,BINDS=&gt;TRUE)
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
  EXEC SYS.DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(SID,SERIAL#,TRUE);
</pre>
<p>İlgilenilen oturumun V$SESSION görünümünde SID ve SERIAL# kolonlarına sorgu çekilerek, SID ve seri numarası elde edilebilir. SYS.DBMS_SYSTEM.SET_EV metodu, Oracle 11g sürümünde artık desteklenmesede, diğer metotların olmadığı eski sürümlerde çok iyi şekilde çalışmaktadır. Yukardaki metotların bazılarının eski Oracle sürümlerinde çalışmadığını bildirmekte fayda var. Oracle sunucusunun udump dizininde izleme dosyaları oluşturulacaktır(Oracle 11g sürümünden itibaren trace dizini altında oluşturulur). Bununla beraber izlenmesi istenen oturum veya oturumlarda, logon olduklarından itibaren otomatik olarak 10046 izlemesinin aktif olması isteniyorsa, bir logon tetikleyicisi oluşturulabilir. Aynı programı çalıştıran oturumlar veya belirli bir programı çalıştıran tek bir oturum, bu logon tetikleyicisinin hedef alanına dahil edilebilir. 10046 izlemeleri ayrıca SQL*Plus ORADEBUG özelliği ilede etkinleştirilebilir.</p>
<p>Aşağıdaki örnekte ilk üç harfi CRY veya MVX ile başlayan programları çalıştıran oturumlar için logon oldukları andan itibaren 10046 izlemesi başlatılacaktır.  Programın yolu  V$SESSION görünümünün PROGRAM kısmında yer almaktadır. DECODE fonksiyonunu kullanarak ilave program listeleri için tetikleyici etkinleştirilebilir.  </p>
<pre class="brush: sql; title: ;">
CREATE OR REPLACE TRIGGER LOGON_10046_IZLEME AFTER LOGON ON DATABASE
DECLARE
 CALISTIR INTEGER;
BEGIN
  SELECT DECODE(SUBSTR(UPPER(PROGRAM),1,3),'CRY',1,'MVX',1,0)
      +DECODE(INSTR(PROGRAM,'\',-1),0,0,DECODE(SUBSTR(UPPER(SUBSTR(PROGRAM,INSTR(PROGRAM,'\',-1)+1)),1,3),'CRY',1,'MVX',1,0))
    INTO CALISTIR FROM V$SESSION
    WHERE SID=(SELECT SID FROM V$MYSTAT WHERE ROWNUM=1);
  IF CALISTIR &gt; 0 THEN
    EXECUTE IMMEDIATE 'ALTER SESSION SET EVENTS ''10046 TRACE NAME CONTEXT FOREVER, LEVEL 12''';
  END IF;
END;
/
</pre>
<p>Yukardaki komutlardan birisini çalıştırılmadan önce(bilhassa ALTER SYSTEM ile etkinleştirilirse), başlama metoduna bağlı olarak 10046 izlemesinin nasıl devre dışı bırakılacağının belirlenmesi gerekir:</p>
<pre class="brush: sql; title: ;">
  ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT OFF';
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
  EXEC SYS.DBMS_SYSTEM.SET_EV(SID,SERIAL#,10046,0,'');
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
  EXEC SYS.DBMS_SUPPORT.STOP_TRACE_IN_SESSION(SID,SERIAL#);
</pre>
<p>veya</p>
<pre class="brush: sql; title: ;">
  EXEC SYS.DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(SID,SERIAL#,FALSE);
</pre>
<p>10046 SQL izlemesi raporları içinde karşılaşılacak bazı anahtar kelimelerin anlamları aşağıda yer almaktadır:</p>
<p>len = SQL komutundaki karakter sayısı<br />
dep = SQL komutun çalışmasında uygulama/tetikleyici derinliğini gösterir. Mesela; dep  =  0 istemci tarafından çalıştırılmayı işaret eder. dep=1, SQL komutunun bir tetikleyici, Oracle iyileştiricisi veya alan yönetim çağrısı tarafından çalıştırıldığını işaret eder. dep = 2, SQL komutunun bir tetikleyici içinden çağrıldığını işaret eder. dep = 3, SQL komutunun bir tetikleyici içinden çağrılan diğer bir tetikleyici içinden çağrıldığını işaret eder.<br />
tim = 10046 izleme dosyasında izlenen süreç için kullanılabilen 1/1.000.000 saniye içinde ölçülen zaman mühürüdür. En güncel tim= değerinin delta değerini alıp ilk tim= değerini çıkarıp, çıkan sonucu 1,000,000’a bölünmesiyle elde edilecek olan değer, izleme dosyasındaki toplam saniye değerine eşittir.<br />
c = CPU saniyesi, çalıştırmada o noktadaki CPU toplamıdır. 1,000,000 ile bölünerek toplam saniye değeri elde edilir.<br />
e= Tamamlanma süresi, çalıştırmada o noktadaki yüksek hassasiyet saatiyle ölçülen toplam saniye değeridir.  1,000,000 ile bölümü sonucu toplam saniye elde edilir.<br />
p = Diskten yapılan fiziksel okumalar.<br />
cr = Sürekli okumalar<br />
cu = Mevcut mod içindeki sürekli okumalar<br />
mis = Bir çalıştırma evresindeki paylaşımlı havuz kayıplarının sayısı<br />
r = Çağrı sonucu dönen satır sayısı<br />
og = Optimizer hedefi – 1=ALL_ROWS, 2=FIRST_ROWS (ve FIRST_ROWS_n), 3=RULE, 4=CHOOSE<br />
XCTEND rlbk = 0 değeri istemcinin COMMIT yayınladığını işaret eder, rd_only = 1 değeri ise COMMIT işlemi sonrasında veritabanında bir bilgi değişmediğini işaret eder.<br />
ela = geçen süre. 1,000,000 ile bölümü ile toplam saniye elde edilir.<br />
p1 = bekleme olayına bağlıdır<br />
p2 = bekleme olayına bağlıdır<br />
p3 = bekleme olayına bağlıdır<br />
STAT çizgileri satır kaynak çalıştırma planıdır<br />
id = çizgi tanımlayıcısı<br />
cnt = dönen veya işlenen satır sayısı<br />
pid = ebeveyn(parent) operasyon tanımlayıcısı( planın satırbaşını belirlemeye yarar)<br />
obj = Planın evresindeki referans alınan objenin obje numarası</p>
<p>Bütün parçaları birleştirerek, bir 10046 genişletilmiş SQL izlemesinden aşağıdaki formatta işlenmemiş analiz verisi alınır.</p>
<pre class="brush: sql; title: ;">
PARSING IN CURSOR #12 len=170 dep=0 uid=31 oct=3 lid=31 tim=768609360 hv=205969412 ad='a64cba88'
SELECT A1 , SUBSTR(C2,1,20) C2  FROM K2 WHERE
  EXISTS (
    SELECT
      1
    FROM
      K4
    WHERE
      K4.A1=K2.A1)
  AND K2.A1 BETWEEN :1 AND :2
END OF STMT
PARSE #12:c=0,e=29,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=768609356
BINDS #12:
kkscoacd
 Bind#0
  oacdty=02 mxl=22(21) mxlc=00 mal=00 scl=00 pre=00
  oacflg=00 fl2=1000010 frm=00 csi=178 siz=48 off=0
  kxsbbbfp=151423d0  bln=22  avl=02  flg=05
  value=1
 Bind#1
  oacdty=02 mxl=22(21) mxlc=00 mal=00 scl=00 pre=00
  oacflg=00 fl2=1000010 frm=00 csi=178 siz=0 off=24
  kxsbbbfp=151423e8  bln=22  avl=03  flg=01
  value=81000
EXEC #12:c=0,e=807,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=768611110
WAIT #12: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=114176 tim=768611226
WAIT #12: nam='db file sequential read' ela= 184 file#=4 block#=1779171 blocks=1 obj#=114178 tim=768611561
WAIT #12: nam='db file scattered read' ela= 213 file#=4 block#=1779172 blocks=5 obj#=114178 tim=768612046
WAIT #12: nam='db file sequential read' ela= 103 file#=4 block#=1138380 blocks=1 obj#=114177 tim=768612399
WAIT #12: nam='db file sequential read' ela= 87 file#=4 block#=1754469 blocks=1 obj#=114177 tim=768612648
WAIT #12: nam='db file sequential read' ela= 88 file#=4 block#=1138382 blocks=1 obj#=114177 tim=768612865
WAIT #12: nam='db file sequential read' ela= 81 file#=4 block#=1138374 blocks=1 obj#=114176 tim=768613103
FETCH #12:c=0,e=2195,p=10,cr=51,cu=0,mis=0,r=14,dep=0,og=1,tim=768613513
WAIT #12: nam='SQL*Net message from client' ela= 3432 driver id=1413697536 #bytes=1 p3=0 obj#=114176 tim=768617150
STAT #12 id=1 cnt=14 pid=0 pos=1 obj=0 op='FILTER  (cr=51 pr=10 pw=0 time=2170 us)'
STAT #12 id=2 cnt=14 pid=1 pos=1 obj=0 op='NESTED LOOPS  (cr=51 pr=10 pw=0 time=2137 us)'
STAT #12 id=3 cnt=14 pid=2 pos=1 obj=0 op='SORT UNIQUE (cr=7 pr=6 pw=0 time=984 us)'
STAT #12 id=4 cnt=14 pid=3 pos=1 obj=114178 op='TABLE ACCESS FULL K4 (cr=7 pr=6 pw=0 time=900 us)'
STAT #12 id=5 cnt=14 pid=2 pos=2 obj=114176 op='TABLE ACCESS BY INDEX ROWID K2 (cr=44 pr=4 pw=0 time=1131 us)'
STAT #12 id=6 cnt=14 pid=5 pos=1 obj=114177 op='INDEX UNIQUE SCAN SYS_C0010352 (cr=30 pr=3 pw=0 time=820 us)'
</pre>
<p>İzleme dosyasını zaman çizelgesine adreslemek her zaman en iyi yaklaşım olmayabilir, ancak belirli bir SQL komutunun rolünü anlamak, performans probleminin sebebini anlamaktan daha kritik öneme sahiptir.</p>
<p>Elbette eğer STATISTICS_LEVEL parametresi ALL olarak ayarlanmışsa veya GATHER_PLAN_STATISTICS hinti sağlanırsa, test sorgusunun çalışmasının hemen arkasından aşağıdaki sorgu çalıştırıldığında test sorgusunun güncel çalıştırma planı dönecektir.</p>
<pre class="brush: sql; title: ;">
SELECT
  *
FROM
  TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL,NULL,'ALLSTATS LAST'))
</pre>
<p>Bu sorgu sonucunda SQL komutunun çıktısı aşağıdaki gibi olmaktadır:</p>
<pre class="brush: sql; title: ;">
SQL_ID  cgfjqr745ep41, child number 0
-------------------------------------
SELECT A1 , SUBSTR(C2,1,20) C2  FROM K2 WHERE       EXISTS (       SELECT         1       FROM         K4       WHERE
K4.A1=K2.A1)    AND K2.A1 BETWEEN :1 AND :2

Plan hash value: 1996673128

--------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------
|*  1 |  FILTER                       |              |      1 |        |     14 |00:00:00.01 |      51 |     10 |       |       |          |
|   2 |   NESTED LOOPS                |              |      1 |      1 |     14 |00:00:00.01 |      51 |     10 |       |       |          |
|   3 |    SORT UNIQUE                |              |      1 |      1 |     14 |00:00:00.01 |       7 |      6 |  9216 |  9216 | 8192  (0)|
|*  4 |     TABLE ACCESS FULL         | K4           |      1 |      1 |     14 |00:00:00.01 |       7 |      6 |       |       |          |
|   5 |    TABLE ACCESS BY INDEX ROWID| K2           |     14 |      1 |     14 |00:00:00.01 |      44 |      4 |       |       |          |
|*  6 |     INDEX UNIQUE SCAN         | SYS_C0010352 |     14 |      1 |     14 |00:00:00.01 |      30 |      3 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(:1&lt;=:2)
   4 - filter((&quot;K4&quot;.&quot;A1&quot;&gt;=:1 AND &quot;K4&quot;.&quot;A1&quot;&lt;=:2))
   6 - access(&quot;K4&quot;.&quot;A1&quot;=&quot;K2&quot;.&quot;A1&quot;)
       filter((&quot;K2&quot;.&quot;A1&quot;&lt;=:2 AND &quot;K2&quot;.&quot;A1&quot;&gt;=:1))
</pre>
<p>Eğer bekleme olaylarınınP1, P2 ve P3 değerlerinin birbirine yakın olduğu incelendiğinde, işlenmemiş 10046 genişletilmiş SQL izlemesinin DBMS_XPLAN çıktısına nazaran bir kısım ek avantajlara sahip olduğu görülecektir.</p>
<p>nam=&#8217;db file scattered read&#8217; ela= 213 file#=4 block#=1779172 blocks=5 obj#=114178 tim=768612046</p>
<p>Yukarda,  1779172 bloğundan başlayarak  4 numaralı salt dosyasının çoklu blok okumasının tamamlanması için 0.000213 saniye gerekmekte ve 5 blok uzaması  uygulanmıştır.  Bloklar 114178 numaralı objeye aittir ve izleme dosyasındaki diğer çizgilerin ardışık zamanını referans edebilmek üzere, izleme dosyasının 768612046 ardışık zamanında gerçekleşmiştir.</p>
<p>Oracle 10.2 üzerinde bir izleme dosyası oluşturmayı deneyelim. Önce, her biri 10,000 kayıt içerek olan iki tane tablo oluşturuyorum ve tablolar ile birincil anahtar indeksleri için istatistikleri topluyorum.</p>
<pre class="brush: sql; title: ;">
CREATE TABLE T1 (
  A1 NUMBER,
  C2 VARCHAR2(255),
  PRIMARY KEY (A1));

CREATE TABLE T2 (
  A1 NUMBER,
  C2 VARCHAR2(255),
  PRIMARY KEY (A1));

INSERT INTO
  T1
SELECT
  ROWNUM,
  DBMS_RANDOM.STRING(‘U’,255)
FROM
  DUAL
CONNECT BY
  LEVEL&lt;=10000;

INSERT INTO
  T2
SELECT
  ROWNUM,
 DBMS_RANDOM.STRING(‘U’,255)
FROM
  DUAL
CONNECT BY
  LEVEL&lt;=10000;

COMMIT;

EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;UGUR,TABNAME=&gt;'T1',CASCADE=&gt;TRUE)
EXEC DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=&gt;UGUR,TABNAME=&gt;'T2',CASCADE=&gt;TRUE)
</pre>
<p>Her biri 10,000 satır içeren iki tablomuz mevcut. Şimdi SQL*Plus üzerinden aşağıdaki planda yer alan işlemleri sırasıyla uygulayacağız.</p>
<p>Fiziksel okumaları zorlaması için tampon önbelleğini iki sefer boşaltıyorum.<br />
Her bir satır alıp getirme(fetch) çağrısı için SQL*Plus üzerinde varsayılan değer olan 15 satır olarak ayarlıyorum.<br />
İstemci taraflı gecikmeleri sınırlandırmak için veritabanından dönecek olan satırların çıktısını devre dışı bırakıyorum.<br />
1 ve 2 değerlerine sahip iki adet bind değişkeni oluşturuyorum.<br />
Seviye 12’de genişletilmiş 10046 SQL izlemesini etkinleştiriyorum.<br />
İzleme dosyasını kolayca bulabilmek için kolay bir isim belirliyorum.<br />
Her iki tabloyu birleştirecek bir sorgu oluşturuyorum.<br />
Fetch dizin boyutunu her bir fetch çağrısı için 50 olarak ayarlıyorum.<br />
İkinci bind değişkeninin değerini 10,000’e çıkarıyorum.<br />
Yedinci adımda çalıştırdığımız sorguyu tekrar çalıştırıyoruz. </p>
<pre class="brush: sql; title: ;">
ALTER SYSTEM FLUSH BUFFER_CACHE; -- 1. adım --
ALTER SYSTEM FLUSH BUFFER_CACHE;

SET ARRAYSIZE 15   -- 2.adım --
SET AUTOTRACE TRACEONLY STATISTICS    -- 3.adım --

VARIABLE U1 NUMBER    -- 4.adım --
VARIABLE U2 NUMBER

EXEC :U1 := 1
EXEC :U2 := 2

EXEC DBMS_SESSION.SESSION_TRACE_ENABLE(WAITS=&gt;TRUE, BINDS=&gt;TRUE)  -- 5.adım --
ALTER SESSION SET TRACEFILE_IDENTIFIER='10046_TEST_BULMA';   -- 6.adım --

SELECT     -- 7.adım --
  T1.A1,
  T2.C2
FROM
  T1,
  T2
WHERE
  T1.A1=T2.A1
  AND T1.A1 BETWEEN :U1 AND :U2;

SET ARRAYSIZE 50    -- 8.adım --
EXEC :U1 := 1
EXEC :U2 := 10000   -- 9.adım --

SELECT      -- 10.adım --
  T1.A1,
  T2.C2
FROM
  T1,
  T2
WHERE
  T1.A1=T2.A1
  AND T1.A1 BETWEEN :U1 AND :U2;

SELECT SYSDATE FROM DUAL;

EXEC DBMS_SESSION.SESSION_TRACE_DISABLE;

Her iki sorgunun bekleme olaylarının SQL*Plus çıktısı aşağıda yer almaktadır.

Statistics
---------------------------------------------------
          1  recursive calls
          0  db block gets
          9  consistent gets
          5  physical reads
          0  redo size
        897  bytes sent via SQL*Net to client
        347  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed

Statistics
---------------------------------------------------
          0  recursive calls
          0  db block gets
      10791  consistent gets
        404  physical reads
          0  redo size
    2727906  bytes sent via SQL*Net to client
       2641  bytes received via SQL*Net from client
        211  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      10000  rows processed
</pre>
<p>Yukardaki sonuçtan, ilk çalıştırılan sorgunun 9 sürekli alımına ihtiyaç duyduğu ve bu alınan bloklardan 5 tanesinin diskten blok okumasını kapsadığı görülmektedir. Sunucu, istemciye 2 gidiş-dönüş yolculuğundan 897 byte veri göndermiş ve 2 satır almıştır. İkinci sorgu ise 10,791 sürekli blok alımına ihtiyaç duymuş ve bunlardan 404 tanesi fiziksel okumaları kapsamıştır  Sunucu, istemciye 10,000 satır içinde 211 gidiş-dönüş yolculuğunda toplamda 2,72 MB veri göndermiştir  Güzel bir analiz, ancak ne olduğu hakkında daha fazla bilgi sahibi olunması gerekmekte. Böylece, daha fazlasını görebilmek için aşağıdaki gibi TKPROF ile SQL izleme dosyasını inceleyeceğiz. </p>
<blockquote><p>tkprof aysun_ora_3702_10046_test_bulma.trc aysun_ora_3702_10046_test_bulma.txt</p></blockquote>
<p>Yukardaki örnek için TKPROF çıktısının bir bölümü aşağıdaki gibi olmaktadır.</p>
<pre class="brush: sql; title: ;">
****************************************************************
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
****************************************************************

SELECT
  T1.A1,
  T2.C2
FROM
  T1,
  T2
WHERE
  T1.A1=T2.A1
  AND T1.A1 BETWEEN :U1 AND :U2

call     count   cpu   elapsed disk query  current  rows
-------  ------  ----- ------- ---- ------ -------  ------
Parse    2       0.00  0.00    0    0      0        0
Execute  3       0.00  0.00    0    0      0        0
Fetch    203     0.28  0.38    409  10991  0        10002
-------  ------  ----- ------- ---- ------ -------  ------
total    208     0.28  0.38    409  10991  0        10002

Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 31 

Rows     Row Source Operation
-------  ---------------------------------------------------
      2  FILTER  (cr=9 pr=5 pw=0 time=19577 us)
      2   NESTED LOOPS  (cr=9 pr=5 pw=0 time=19569 us)
      2    TABLE ACCESS BY INDEX ROWID T2 (cr=5 pr=3 pw=0 time=13843 us)
      2     INDEX RANGE SCAN SYS_C0010411 (cr=3 pr=2 pw=0 time=9231 us)(object id 107421)
      2    INDEX UNIQUE SCAN SYS_C0010422 (cr=4 pr=2 pw=0 time=5788 us)(object id 107424)

Elapsed times include waiting on following events:

Event waited on                 Times_Waited  Max. Wait  Total Waited
------------------------------- ----------    ---------  ------------
SQL*Net message to client       204           0.00       0.00
db file sequential read         409           0.00       0.21
SQL*Net message from client     204           0.00       0.07
SQL*Net more data to client     1200          0.00       0.02
</pre>
<p>Yukardaki sonuç aslında çalıştırılan test SQL komutu için izleme dosyası içerisinde ne bulunduğu ile ilgili güzel bir özet bilgi… Peki ne yazmakta? Her bir çağrı için 1 seferden toplamda 2 çözümleme(parse) çağrısının olduğunu ve (execute-parse) formulü sonucunda, bu çağrılardan birisinin “hard parse” ile sonuçlandığını, yani önbellekten sonuçlarının bütünlüğünü sağlayamadığından tekrardan çözümleme için ilaveten bir fiziksel I/O işlemi yaptığını anlatmaktadır. Toplamda alınan 10,002 satır için 203 fetch çağrısı olduğunu ki buradanda istemcinin fetch çağrısı başına ortalama 49,27 satır alıp getirme yaptığını görüyoruz. Çalıştırma için tüm süre, 0,28 saniye CPU süresi ve çalıştırma için geçen 0.38 saat saniye toplamındaki fetch çağrısında meydana gelmiştir. Toplamda 10,991 sürekli alıma gerek duyulmuş ve diskten 409 blok okunmuştur. </p>
<p>Yukardaki çalıştırma planı, iki satır birarada listelendiği için yanıltıcı olabilir. Gerçi, Oracle 11.1.6.0 sürümünden itibaren her bir komut ayrı çalıştırma planına sahiptir. T2 tablosunun birincil anahtarı olan SYS_C0010411 indeksi üzerinde, 1 ve 2 değerleri arasında olan tüm A1 değerlerinin yerinin saptanması için indeks aralığı taraması uygulanmaktadır. Çalıştırma planının en üst satırında, toplamda sorgunun 9 sürekli alım, 5 fiziksel blok okuması ve çalıştırma için 0,019577 saniyeye gerek duyduğu görülmektedir(FILTER  (cr=9 pr=5 pw=0 time=19577 us). SYS_C0010411 indeks aralığı taramasında 3 sürekli alım ve bu 3 sürekli alımı karşılamak üzere 2 fiziksel blok okumasının gerektiği görülmektedir(INDEX RANGE SCAN SYS_C0010411 cr=3 pr=2 pw=0 time=9231 us). T2 tablosu ise ilave olarak 2 sürekli okuma ve 1 fiziksel blok okumasına gerek duymaktadır(TABLE ACCESS BY INDEX ROWID T2 (cr=5 pr=3 pw=0 time=13843 us). İlave olarak 4 sürekli okuma ve 2 fiziksel blok okuması daha gerektiren T1 tablosunun birincil anahtarına doğru  içiçe döngü(nested loop) işlemi gerçekleşmiştir. Peki ikinci sefer çalıştırılan aynı SQL komutu ile ilgili neler söyleyebiliriz?</p>
<p>Bekleme olaylarında,diskten bir seferde fiziksel olarak 1 blok okunduğunu işaret eden 409 adet “db file sequential read” bekleme olayı olduğu gözlemlenmektedir. Bu değerin TKPROF özetinde “fetch” satırının “disk” kolonundaki değerle aynı olduğuna dikkat çekerim. Diskten okunması gereken her bir blok, blok okuması başına 0.000513 ortalama okuma zamanıyla tek seferde 1 blok okumaktadır. Blokların dosya sistemi, RAID kontroller veya SAN gibi yapılardaki gelişmiş önbelleklenme mimarisi sonucunda ortalama okuma süresi fazlasıyla hızlanmaktadır. “SQL*Net more data to client” bekleme olayında 1200 bekleme olduğu ve böylece paketlerin istemciye gönderilme aşamasında SDU boyutunun 1200 kez dolduğu görülmektedir. Bu bekleme olayı ilgili analiz yazımı burdan okuyabilirsiniz.  </p>
<p>Bununla beraber çıktının analizini işlenmemiş 10046 izleme dosyasındanda yapmakta fayda vardır. Bu noktada izleme dosyasının işlenmemiş çıktısı neye benzeyecektir? Bu konuya girmeden önce işlenmemiş izleme dosyasını okurken bize yardımcı olacak indeks ve tabloların obje ID’lerini aşağıdaki gibi bulmak yararlı olacaktır.</p>
<pre class="brush: sql; title: ;">
COLUMN TABLE_NAME FORMAT A10

SELECT
  TABLE_NAME,
  INDEX_NAME
FROM
  DBA_INDEXES
WHERE
  TABLE_NAME IN ('T1','T2')
ORDER BY
  TABLE_NAME;

TABLE_NAME INDEX_NAME
---------- ------------
T1         SYS_C0010422
T2         SYS_C0010411

COLUMN OBJECT_NAME FORMAT A15

SELECT
  OBJECT_ID,
  OBJECT_NAME,
  OBJECT_TYPE
FROM
  DBA_OBJECTS
WHERE
  OBJECT_NAME IN ('T1','T2','SYS_C0010422','SYS_C0010411')
ORDER BY
  OBJECT_NAME;

 OBJECT_ID OBJECT_NAME     OBJECT_TYPE
---------- --------------- -----------
    107424 SYS_C0010422    INDEX
    107421 SYS_C0010411    INDEX
    114209 T1              TABLE
    114207 T2              TABLE
</pre>
<p>Yukardaki sonuçtan, T1 tablosundaki SYS_C0010422 adlı indeksin obje ID’sinin 107424, T2 tablosunun SYS_C0010411 adlı indeksinin obje ID’sinin ise 107421 olduğunu buluyoruz. T1 tablosunun obje ID’si 114209, T2 tablosunun obje ID’si ise 114207’dir.  İşlenmemiş 10046 izleme dosyasının bir bölümü altta yer almaktadır.  </p>
<pre class="brush: sql; title: ;">
PARSING IN CURSOR #3 len=91 dep=0 uid=31 oct=3 lid=31 tim=4963261335 hv=3021110247 ad='982ab100'
SELECT
  T1.A1,
  T2.C2
FROM
  T1,
  T2
WHERE
  T1.A1=T2.A1
  AND T1.A1 BETWEEN :U1 AND :U2
END OF STMT
PARSE #3:c=0,e=1113,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=4963261327
BINDS #3:
kkscoacd
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=00 csi=00 siz=48 off=0
  kxsbbbfp=13ce8870  bln=22  avl=02  flg=05
  value=1
 Bind#1
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=00 csi=00 siz=0 off=24
  kxsbbbfp=13ce8888  bln=22  avl=02  flg=01
  value=2
</pre>
<p>Yukarda ilk çözümleme işleminin “hard parse” olduğunu(parse #3  satırındaki mis=1 değernden anlaşılıri), bu işlem için 0 CPU zamanı ve 0.001113 saat saniyesi gerektiği görülmektedir. İlave olarak, iki bind değişkeni geçilmiştir. Seviye 4 veya seviye 12 deki 10046 genişletilmiş SQL izleme dosyasında, yukarda görüldüğü gibi önerilmiş bind değişkenleride dahil olacaktır(Bind#0 ve Bind#1).   Bind değişken veri tipinin(oacdty) numara ile tanımlanmış olan kodunu çözmek için aşağıdaki liste referans alınabilir.</p>
<p>    0 &#8211; Arguman içermeyen bir prosedürün yer göstericisi satırıdır.<br />
  1 &#8211; VARCHAR2 (or NVARCHAR)<br />
  2 &#8211; NUMBER<br />
  3 &#8211; NATIVE INTEGER (for PL/SQL&#8217;s BINARY_INTEGER)<br />
  8 &#8211; LONG<br />
 11 &#8211; ROWID<br />
 12 &#8211; DATE<br />
 23 &#8211; RAW<br />
 24 &#8211; LONG RAW<br />
 96 &#8211; CHAR (or NCHAR)<br />
112 &#8211; CLOB or NCLOB<br />
113 &#8211; BLOB<br />
114 &#8211; BFILE<br />
106 &#8211; MLSLABEL<br />
250 &#8211; PL/SQL RECORD<br />
251 &#8211; PL/SQL TABLE<br />
252 &#8211; PL/SQL BOOLEAN</p>
<p>İzleme dosyası aşağıdaki gibi devam etmektedir:</p>
<pre class="brush: sql; title: ;">
EXEC #3:c=0,e=3538,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=4963265927
WAIT #3: nam='SQL*Net message to client' ela= 5 driver id=1413697536 #bytes=1 p3=0 obj#=-1 tim=4963266031
WAIT #3: nam='db file sequential read' ela= 4816 file#=4 block#=1138316 blocks=1 obj#=107421 tim=4963271120
WAIT #3: nam='db file sequential read' ela= 3934 file#=4 block#=1138318 blocks=1 obj#=107421 tim=4963275219
WAIT #3: nam='db file sequential read' ela= 4443 file#=4 block#=1138310 blocks=1 obj#=114207 tim=4963279805
WAIT #3: nam='db file sequential read' ela= 5221 file#=4 block#=1093148 blocks=1 obj#=107424 tim=4963285172
WAIT #3: nam='db file sequential read' ela= 236 file#=4 block#=1093150 blocks=1 obj#=107424 tim=4963285569
FETCH #3:c=15625,e=19589,p=5,cr=5,cu=0,mis=0,r=1,dep=0,og=1,tim=4963285717
WAIT #3: nam='SQL*Net message from client' ela= 364 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963286240
WAIT #3: nam='SQL*Net message to client' ela= 4 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963286494
FETCH #3:c=0,e=180,p=0,cr=4,cu=0,mis=0,r=1,dep=0,og=1,tim=4963286588
</pre>
<p>Yukarda, (T2 tablosunun SYS_C0010411 adlı indeksinin)107421 numaralı objenin 1138316 ve 1138318 bloklarından 2 tekil blok okumasını, (T2 tablosunun) 114207 nolu objenin 1138310 bloğundan tek tekil blok okumasını ve (T1 tablosunun SYS_C0010422 adlı indeksinin) 107424 numaralı objenin 1093148 ve 1093150 bloklarından 2 adet tekil okumasıyla birlikte toplamda 5 fiziksel blok okuması yapıldığı görülmektedir.  Bu toplam 5 fiziksel blok okumasının 0.000236 saniyede tamamlandığıda burada görülmektedir. İlk “fetch” çağrısı tek satır döndürmesine rağmen, “fetch” dizin boyutu  15 olarak ayarlanmıştı. Ancak, bu “fetch” işleminin ardından 5 fiziksel blok okumasına gerek duyan sürekli 5 okumaya gerek duymuştur.  İlk satır istemciye gönderilmiş, ardından (4963286588 – 4963285717)/1,000,000 = 0.000871 saniye sonra ikinci satır alınıp getirilmiştir. İzleme dosyasının devamı aşağıda yer almaktadır.</p>
<blockquote><p>WAIT #3: nam=&#8217;SQL*Net message from client&#8217; ela= 319 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963287035<br />
*** SESSION ID:(141.14281) 2011-04-29 12:35:24.251<br />
STAT #3 id=1 cnt=2 pid=0 pos=1 obj=0 op=&#8217;FILTER  (cr=9 pr=5 pw=0 time=19577 us)&#8217;<br />
STAT #3 id=2 cnt=2 pid=1 pos=1 obj=0 op=&#8217;NESTED LOOPS  (cr=9 pr=5 pw=0 time=19569 us)&#8217;<br />
STAT #3 id=3 cnt=2 pid=2 pos=1 obj=114207 op=&#8217;TABLE ACCESS BY INDEX ROWID T2 (cr=5 pr=3 pw=0 time=13843 us)&#8217;<br />
STAT #3 id=4 cnt=2 pid=3 pos=1 obj=107421 op=&#8217;INDEX RANGE SCAN SYS_C0010411 (cr=3 pr=2 pw=0 time=9231 us)&#8217;<br />
STAT #3 id=5 cnt=2 pid=2 pos=2 obj=107424 op=&#8217;INDEX UNIQUE SCAN SYS_C0010422 (cr=4 pr=2 pw=0 time=5788 us)&#8217;<br />
WAIT #0: nam=&#8217;SQL*Net message to client&#8217; ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963289021<br />
WAIT #0: nam=&#8217;SQL*Net message from client&#8217; ela= 2329 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963291420</p></blockquote>
<p>3 numaralı imleç kapanmıştır, böylece Oracle, TKPROF çıktısında görüldüğü gibi STAT satırlarının çıktısını alır. Bu izleme dosyasına giriş yapmadan önce PARSING IN CURSOR  satırındaki “oct” kısmı Oracle komut tipini belirtmektedir ve V$SESSION görünümünün COMMAND kolonu ile ve V$SQL görünümünün COMMAND_TYPE kolonu ile ilişkilidir. Aşağıda yaygın komut tiplerinin değerleri yer almaktadır.</p>
<p>  1 &#8211; CREATE TABLE<br />
  2 &#8211; INSERT<br />
  3 &#8211; SELECT<br />
  6 &#8211; UPDATE<br />
  7 &#8211; DELETE</p>
<p>Şimdi izleme dosyasına bakalım.</p>
<pre class="brush: sql; title: ;">
...
PARSING IN CURSOR #4 len=91 dep=0 uid=31 oct=3 lid=31 tim=4963302762 hv=3021110247 ad='982ab100'
SELECT
  T1.A1,
  T2.C2
FROM
  T1,
  T2
WHERE
  T1.A1=T2.A1
  AND T1.A1 BETWEEN :U1 AND :U2
END OF STMT
PARSE #4:c=0,e=118,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=4963302756
BINDS #4:
kkscoacd
 Bind#0
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=00 csi=00 siz=48 off=0
  kxsbbbfp=13ce8870  bln=22  avl=02  flg=05
  value=1
 Bind#1
  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00
  oacflg=03 fl2=1000000 frm=00 csi=00 siz=0 off=24
  kxsbbbfp=13ce8888  bln=22  avl=02  flg=01
  value=10000
EXEC #4:c=0,e=699,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=4963304299
WAIT #4: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963304383
FETCH #4:c=0,e=94,p=0,cr=5,cu=0,mis=0,r=1,dep=0,og=1,tim=4963304564
WAIT #4: nam='SQL*Net message from client' ela= 718 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963305403
WAIT #4: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=107424 tim=4963305590
WAIT #4: nam='SQL*Net more data to client' ela= 29 driver id=1413697536 #bytes=2146 p3=0 obj#=107424 tim=4963305766
WAIT #4: nam='SQL*Net more data to client' ela= 20 driver id=1413697536 #bytes=1862 p3=0 obj#=107424 tim=4963305913
WAIT #4: nam='SQL*Net more data to client' ela= 17 driver id=1413697536 #bytes=2128 p3=0 obj#=107424 tim=4963306065
WAIT #4: nam='db file sequential read' ela= 2272 file#=4 block#=1138311 blocks=1 obj#=114207 tim=4963308471
WAIT #4: nam='SQL*Net more data to client' ela= 27 driver id=1413697536 #bytes=1868 p3=0 obj#=114207 tim=4963308686
WAIT #4: nam='SQL*Net more data to client' ela= 18 driver id=1413697536 #bytes=2122 p3=0 obj#=114207 tim=4963308841
WAIT #4: nam='SQL*Net more data to client' ela= 13 driver id=1413697536 #bytes=2128 p3=0 obj#=114207 tim=4963309001
FETCH #4:c=0,e=3573,p=1,cr=54,cu=0,mis=0,r=50,dep=0,og=1,tim=4963309109
</pre>
<p>Bu sefer “hard parse” olayının olmadığını gözlemliyoruz(parse #4 satırında mis=0 değerinden) . Bu noktada ilk iki “fetch” işlemi tamamlanmaktadır. İlk “fetch” tek satır döndürürken(r=1), ikinci “fetch” işlemi 50 satır döndürmektedir(r=50). İkinci “fetch” satırından önce, “SQL*Net more data to client” beklemesinin olduğunu görüyoruz ki bu bekleme olayının her biri bir önceki istemciye gönderilen SDU boyutunun aşıldığını göstermektedir. Ayrıca, sadece tek bir fiziksel blok okumasının olduğunu ve bu okuma işleminde ilk 51 satırın alınıp getirilmesi esnasında 0.0002272 saniye gerektiği görülmektedir(diğer bloklar zaten tampon önbelleğindedir). İzleme dosyası aşağıdaki gib devam etmektedir.</p>
<pre class="brush: sql; title: ;">
WAIT #4: nam='SQL*Net message from client' ela= 256 driver id=1413697536 #bytes=1 p3=0 obj#=114207 tim=4963309476
WAIT #4: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=114207 tim=4963309654
WAIT #4: nam='db file sequential read' ela= 226 file#=4 block#=1138312 blocks=1 obj#=114207 tim=4963309995
WAIT #4: nam='SQL*Net more data to client' ela= 32 driver id=1413697536 #bytes=2116 p3=0 obj#=114207 tim=4963310197
WAIT #4: nam='SQL*Net more data to client' ela= 14 driver id=1413697536 #bytes=2096 p3=0 obj#=114207 tim=4963310353
WAIT #4: nam='SQL*Net more data to client' ela= 13 driver id=1413697536 #bytes=1834 p3=0 obj#=114207 tim=4963310488
WAIT #4: nam='db file sequential read' ela= 1762 file#=4 block#=1138308 blocks=1 obj#=114207 tim=4963312390
WAIT #4: nam='SQL*Net more data to client' ela= 23 driver id=1413697536 #bytes=2096 p3=0 obj#=114207 tim=4963312551
WAIT #4: nam='SQL*Net more data to client' ela= 16 driver id=1413697536 #bytes=2096 p3=0 obj#=114207 tim=4963312783
WAIT #4: nam='SQL*Net more data to client' ela= 13 driver id=1413697536 #bytes=1834 p3=0 obj#=114207 tim=4963312904
FETCH #4:c=0,e=3345,p=2,cr=55,cu=0,mis=0,r=50,dep=0,og=1,tim=4963312955
</pre>
<p>114207 numaralı objenin iki fazla fiziksel blok okuması isteciye bir sonraki 50 satırı döndürür. İzleme dosyasındaki son iki “fetch” işlemine tekrardan dalarsak;</p>
<pre class="brush: sql; title: ;">
...
FETCH #4:c=0,e=1259,p=2,cr=55,cu=0,mis=0,r=50,dep=0,og=1,tim=4963757700
WAIT #4: nam='SQL*Net message from client' ela= 842 driver id=1413697536 #bytes=1 p3=0 obj#=114207 tim=4963758586
WAIT #4: nam='SQL*Net message to client' ela= 1 driver id=1413697536 #bytes=1 p3=0 obj#=114207 tim=4963758653
WAIT #4: nam='SQL*Net more data to client' ela= 16 driver id=1413697536 #bytes=2124 p3=0 obj#=114207 tim=4963758766
WAIT #4: nam='db file sequential read' ela= 242 file#=4 block#=1773782 blocks=1 obj#=114207 tim=4963759071
WAIT #4: nam='SQL*Net more data to client' ela= 17 driver id=1413697536 #bytes=2104 p3=0 obj#=114207 tim=4963759182
WAIT #4: nam='SQL*Net more data to client' ela= 13 driver id=1413697536 #bytes=1841 p3=0 obj#=114207 tim=4963759268
WAIT #4: nam='SQL*Net more data to client' ela= 17 driver id=1413697536 #bytes=2104 p3=0 obj#=114207 tim=4963759365
WAIT #4: nam='SQL*Net more data to client' ela= 13 driver id=1413697536 #bytes=1841 p3=0 obj#=114207 tim=4963759453
WAIT #4: nam='db file sequential read' ela= 226 file#=4 block#=1773852 blocks=1 obj#=114207 tim=4963759715
WAIT #4: nam='SQL*Net more data to client' ela= 20 driver id=1413697536 #bytes=2104 p3=0 obj#=114207 tim=4963759867
FETCH #4:c=0,e=1290,p=2,cr=54,cu=0,mis=0,r=49,dep=0,og=1,tim=4963759912
</pre>
<p>Yukardaki sonuçtan, Oracle her bir “fetch” çağrısı için ortalama iki tekil blok fiziksel okumanın gerçekleştiği görülmektedir ve sonuç “fetch” çağrısı ile 49 satır alınmıştır(r=49). İzleme dosyasına devam edersek;</p>
<pre class="brush: sql; title: ;">
WAIT #4: nam='SQL*Net message from client' ela= 792 driver id=1413697536 #bytes=1 p3=0 obj#=114207 tim=4963760775
*** SESSION ID:(141.14281) 2011-04-29 12:54:51.107
STAT #4 id=1 cnt=10000 pid=0 pos=1 obj=0 op='FILTER  (cr=10982 pr=404 pw=0 time=680024 us)'
STAT #4 id=2 cnt=10000 pid=1 pos=1 obj=0 op='NESTED LOOPS  (cr=10982 pr=404 pw=0 time=670018 us)'
STAT #4 id=3 cnt=10000 pid=2 pos=1 obj=114207 op='TABLE ACCESS BY INDEX ROWID T2 (cr=781 pr=387 pw=0 time=590006 us)'
STAT #4 id=4 cnt=10000 pid=3 pos=1 obj=107421 op='INDEX RANGE SCAN SYS_C0010411 (cr=218 pr=17 pw=0 time=10038 us)'
STAT #4 id=5 cnt=10000 pid=2 pos=2 obj=107424 op='INDEX UNIQUE SCAN SYS_C0010422 (cr=10201 pr=17 pw=0 time=77882 us)'
WAIT #0: nam='SQL*Net message to client' ela= 2 driver id=1413697536 #bytes=1 p3=0 obj#=114207 tim=4963764774
WAIT #0: nam='SQL*Net message from client' ela= 2789 driver id=1413697536 #bytes=1 p3=0 obj#=114207 tim=4963767585
</pre>
<p>Yukardan, TKRPOF çıktısında gözükmeyen bir bilgi olan ikinci çalıştırmanın çalıştırma planı görülmektedir. Satır sayısının oldukça geniş olduğu durumlarda, iki “full table scan” ile “hash join” birleştirmesi, indeks üzerinden “nested loop” birleşmelerine nazaran muhtemelen daha verimli olacaktır. Bu bind değişkenleri kullanıldığında potensiyel problemlerden birisi olmaktadır. Oracle 11.1.0.6 sürümünden itibaren, farklı bind değişkenleri ataması ile satır sayılarında belirgin miktarda  değişiklik olduğunu Oracle hissettiğinde, gelecekteki çalıştırmalar için çalıştırma planında değişiklikler yapabilmektedir, bu olay “adaptive cursor sharing “ olarak adlandırılmaktadır. Bir sonraki yazıda 10046 bekleme olayı ile ilgili benzer bir analizin Oracle 11.2 sürümündeki incelemesini yazacağım.</p>
<p><span style="color: #0000ff;"><strong>Uğur İnal </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/06/event-10046-izleme-dosyalari-ile-sql-komutlarinda-bekleme-olaylarinin-analizi.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>TKPROF ile SQL uygulamalarının performans analizi</title>
		<link>http://turkceoracle.com/2011/06/tkprof-ile-sql-uygulamalarinin-performans-analizi.html</link>
		<comments>http://turkceoracle.com/2011/06/tkprof-ile-sql-uygulamalarinin-performans-analizi.html#comments</comments>
		<pubDate>Sun, 26 Jun 2011 19:06:58 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[performans iyileştirme]]></category>
		<category><![CDATA[Uğur İnal]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=449</guid>
		<description><![CDATA[TKPROF, SQL izleme(trace) dosyalarını sırasıyla analiz etmek ve bu izleme dosyalarında yer alan bilgilerden okunabilir formda raporlar hazırlamak için işletim sistemi seviyesinde kullanılan bir Oracle yardımcı aracıdır. TKPROF aracını kullananarak ayrıntıların çağrılması platformdan platforma değişiklik göstermesine rağmen, TKPROF tüm Oracle sürümlerince desteklenmektedir ve tüm Oracle veritabanı sürümlerinde aynı işleve sahiptir. SQL izlemesi, bütün bir instance [...]]]></description>
			<content:encoded><![CDATA[<p>TKPROF, SQL izleme(trace) dosyalarını sırasıyla analiz etmek ve bu izleme dosyalarında yer alan bilgilerden okunabilir formda raporlar hazırlamak için işletim sistemi seviyesinde kullanılan bir Oracle yardımcı aracıdır.  TKPROF aracını kullananarak ayrıntıların çağrılması platformdan platforma değişiklik göstermesine rağmen, TKPROF tüm Oracle sürümlerince desteklenmektedir ve tüm Oracle veritabanı sürümlerinde aynı işleve sahiptir.</p>
<p>SQL izlemesi, bütün bir instance için veya bireysel oturumlar için etkinleştirilen veya devredışı bırakılan bir işlemdir. Bir oturum için SQL izlemesi etkinleştirildiğinde, oturumu tutan Oracle prosesi, tüm veritabanı çağrılarını ve operasyonları ile ilgili detaylı bilgileri bir izleme dosyasına yazar. Özel veritabanı olayları, bind variables(bağlaç değişkenler) gibi daha spesifik bilgilerin sırasıyla Oracle’ın izleme dosyasına yazılmasına sebep vermek içinde ayarlanabilir.</p>
<p>SQL izlemesi, bireysel SQL komutlarındaki performans bilgilerini içerir. Her bir komut için aşağıdaki istatistikleri oluşturur:</p>
<p>Çözümleme(parse), çalıştırma(execute) ve satır alıp getirme(fetch) sayıları<br />
CPU süresi ve tamamlama süresi<br />
Fiziksel okumalar ve mantıksal okumalar<br />
İşlem gören satır sayısı<br />
Library cache üzerindeki kayıplar(misses)<br />
Her bir çözümleme işlemindeki kullanıcı adı<br />
Her bir commit and rollback işlemi<br />
Her bir SQL komutu için bekleme olayı ve her bir izleme dosyası için özet bilgisi<br />
Eğer SQL oturumunu için SQL komutunun imleci(cursor) kapanmışsa, SQL izlemesi aynı zamanda aşağıdakiler ile ilgilide satır kaynak bilgilerini sağlayacaktır.</p>
<p>Her bir SQL komutunun güncel çalışma planını gösteren satır işlemleri<br />
Satır üzerindeki her bir işlem için tamamlama süresi, satır sayısı, ardışık okumalar(consistent reads) ve fiziksel yazma sayısı<br />
Bir instance veya oturum için SQL izlemesini etkinleştirmek münkün olmasına rağmen, bunların yerine DBMS_SESSION veya DBMS_MONITOR paketlerinin kullanılması tavsiye edilmektedir. Bir oturum veya instance için SQL izlemesi etkin olduğunda, kullanıcı oturumu veya instance oturumu içinde çalıştırılan tüm SQL komutlarına ait performans istatistikleri izleme dosyalarına yazılır. SQL izlemesinin kullanılması veritabanında şiddetli performans etkisi oluşturabilir ve aşırı CPU kullanımı, yetersiz disk alanı gibi artan sistem yüklerine sebebiyet verebilir.</p>
<p>Aslında, SQL izleme dosyaları text dosyaları olduğundan bir editor programla açıldığında rahatlıkla okunabilir formattadır, yani binary değildir. Ancak, aşırı oranda satırlar tekrarlı olmaktadır, çok ayrıntılıdır ve kısmen karışık formattadır. Örneğin, eğer bir uygulama bir imleç açıp bir seferde tek satır imlecinden 1,000 satır alıp getirirse, izleme dosyası içinde 1,000 tane farklı giriş olacaktır.  Tabii, çıplak gözle bunların ne olduğunu anlamak imkansız hale gelecektir. İşte bu sebeple, izleme dosyasını sırasıyla daha kolayca anlaşılabilecek bir formata dönüştürmek için, işletim sistemi komut satırından çağrılan bir araç olan, TKPROF kullanılır.</p>
<p>Her bir SQL komutunun ne kadar çözümlendiği, çalıştırıldığı ve satır getirdiği(fetch) sayılarıyla birlikte bu raporda gösterilir. CPU süresi, tamamlanma süresi, mantıksal ve fiziksel okumalar ve işlenen satırların library cache içindeki kayıpları ve tekrarlama(recursion) seviyesiyle birlikte ayrıca raporlanır. TKPROF, ayrıca opsiyonel olarak rapor içindeki her bir SQL komutu için, çalışma planının her bir adımında ne kadar satır işlendiği sayısıyla birlikte, bütün bir çalışma planıda(execution plan)içerebilir.</p>
<p>Eğer istenirse, bu TKPROF raporu içinde SQL komutlarının ne kadar kaynak tükettiğide sırasıyla listelenebilir. Ayrıca, SYS kullanıcısı tarafında “data dictionary” objeleri yönetmek için yinelemeli yayınlanan SQL komutlarıda dahil edilebilir veya hariç tutulabilir. TKPROF, izlenen oturumdan SQL komutlarını bir kuyruk(spool) dosyasınada yazabilir.</p>
<p>SQL izlemesini instance seviyesinde etkinleştirmek için SQL_TRACE başlangıç parametresinin TRUE olarak ayarlanması ve veritabanının yeniden başlatılması gerekmektedir. Bu işlemden sonra veritabanında açılan tüm oturumlar SQL izleme modunda olacaktır, yani tüm SQL işlemleri izleme dosyalarına kayıt edilecektir, hatta PMON ve SMON işlemleri bile.</p>
<p>Pratikte SQL izlemesinin instance seviyesinde etkinleştirilmesi genelde uygun olmaz, tüm gerekli gereksiz SQL komutlarının izlenmesi sisteme oldukça yüksek ek yük getirecektir. Bu sebeple sadece performansı etkileyen oturumların izlenmesi ve/veya istenen SQL komutlarının oturum katmanında izlenmesi tavsiye edilir. Oturum katmanında SQL izlemesini etkinleştirmek (TRUE) ve devredışı bırakmak (FALSE) için aşağıdaki komut kullanılmaktadır.</p>
<pre class="brush: sql; title: ;">
ALTER SESSION SET sql_trace = TRUE | FALSE;
</pre>
<p>İzlenmesini istediğimiz oturumda ALTER SESSION komutunun yürütülmesinin mümkün olmadığı durumlarda (önceden paketlenmiş uygulamalar gibi), veritabanına DBA kullanıcısı olarak başka bir oturumdan bağlanarak DBMS_SYSTEM paketi ile SQL izlemesi açılabilir veya kapanabilir. Bunu yapmak için V$SESSION görünümüne sorgu çekilerek izlenmesi istenen oturumun SID ve seri numarası bulunabilir ve ardından aşağıdaki gibi DBMS_SYSTEM paketi çalıştırılabilir.</p>
<pre class="brush: sql; title: ;">
EXECUTE SYS.dbms_system.set_sql_trace_in_session (&lt;SID&gt;, &lt;serial#&gt;, TRUE | FALSE);
</pre>
<p>Bir oturum için ilk seferinde SQL izlemesi etkinleştirildiğinde, oturumu tutan Oracle sunucusu user_dump_dest başlangıç parametresince belirtilen dizinde izleme dosyasını oluşturur. Oracle sunucusu, veritabanı işlemlerini gerçekleştirmek için uygulama tarafından çağrıldıkça sunucu prosesi izleme dosyasının üzerine yazmaya devam eder.</p>
<p>Multi-thread sunucu(MTS) kullanarak veritabanını izlemek biraz daha karışıktır, çünkü uygulamadaki her bir veritabanı çağrısı farklı sunucu proseslerince toplanacaktır. Bu durumda, her bir sunucu prosesi o proses tarafından gerçekleştirilen işlemler hakkında izleme bilgilerini içeren bir izleme dosyası oluşturacaktır. Yani, uygulamanın veritabanı ile nasıl entegre olduğu hakkında büyük resmi görebilmek için birden çok izleme dosyası birlikte kombine olarak kullanılacaktır. Bununda ötesinde, eğer tek seferde birden çok oturum izleniyorsa, izleme dosyasındaki bir işlemin hangi oturuma ait olduğunun söylenmesi zor olacaktır.  Bu sebepler yüzünden, SQL izlemesi ile veritabanı oturumu izlemesinde “dedicated” sunucu modu kullanılmalıdır.</p>
<p>SQL izleme dosyası detaylı süre bilgisi içermektedir. Varsayılan olarak Oracle 11g sürümünde süre izlemesi etkindir. Eğer süre devredışı bırakılırsa, zaman izlemesi olmayacağından dolayı izleme dosyası içindeki bütün zaman görüntüleri sıfır olarak gözükecektir. Süre bazlı izlemeyi etkinleştirmek için başlangıç parametresindeki parametre aşağıdaki gibi değiştirilmeli ve instance yeniden başlatılmalıdır.</p>
<pre class="brush: sql; title: ;">
ALTER SYSTEM SET timed_statistics=true SCOPE=SPFILE;
</pre>
<p>Oturum katmanında süre bazlı izlemenin etkinleştirilmesi için aşağıdaki komut bu oturumdan çalıştırılır.</p>
<pre class="brush: sql; title: ;">
ALTER SESSION SET timed_statistics = TRUE | FALSE;
</pre>
<p>SQL izlemesinin etkinleştirilmesi sonucunda sistem üzerine ek bir yük bineceğinden bahsetmiştik, hatta bazı DBA’ler bunun %25’e kadar performansta olumsuz etki yapacağını belirtmektedirler. Bunun yanında SQL izlemesinin etkinleştirilmesi, gereğinden fazla izleme dosyalarının oluşturulmasına sebebiyet verecektir. Bu sebeplerle, SQL izlemesini gerektiğinde ve kararınca kullanmak gerekmektedir.</p>
<p>Linux/UNIX sistemlerde Oracle temel izinleri ayarlayarak, sadece oracle kullanıcısı ve dba adlı Unix grubu tarafından izleme dosyaları okunabilir. Unix/Linux sistemlerden oturum açan diğer sistem kullanıcılarının izleme dosyalarını okuyabilmesi isteniyorsa, bu durumda aşağıdaki başlangıç parametresi ayarlanmalıdır. Ancak bunun bir güvenlik zaafiyeti oluşturacağını unutmamanız gerekmektedir.</p>
<pre class="brush: sql; title: ;">
ALTER SYSTEM SET “_trace_files_public” = true SCOPE=SPFILE;
</pre>
<p>Eğer veritabanı sunucusuna olması gerektiğinden çok çağrı yapan oturumlar tespit edilmişse ve bunlar izlenecekse, izleme dosyası oldukça büyük tutulmalıdır. İzleme dosyasının maksimum büyüklüğü max_dump_file_size parametresince tanımlanmaktadır. UNIX/Linux sistemlerde bu parameyre 512 bytelık blok birimleri olarak belirlenmiştir. Böylece, 10240 lık bir ayar izleme dosyasını 5MB büyüklüğündeki bir parçaya kadar sınırlandırmış olacaktır. Bunun yanında 2GB dan daha büyük izleme dosyasının UNIX/Linux sistemlerde izlenmesinde “could not open trace file xxx_xx_xxx.trc” hata mesajına karşılık izleme dosyası lokasyonu içerisinde mkfifo komutu yeni bir pipe oluşturularak bir prosesin dosyaya yazarken başka bir prosesin bu dosyayı okumasına imkan vererek verinin normal anonim pipe şeklinde akmasına imkan sağlanır. 2GB dan daha büyük SQL izleme dosyası kullanıldığında TKPROF işleminin başarılı okuma yapması için aşağıdaki adımlar uygulanabilir. Aşağıdaki örnekte test_ora_3419.trc adlı SQL izleme dosyası 2 GB üzerindedir ve normalde TKPROF ile çağrıldığında hata mesajı vermektedir. 2GB üzerindeki her bir izleme dosyasının TKPROF ile çağrılması için aşağıdaki 3 adımın uygulanması gerekmektedir. Alternatif olarak 2GB dan daha büyük bir kuyruk dosyası oluşturarakta bu sorun çözülebilir(detaylar için bakınız Metalink Note 94486.1)</p>
<p>izleme dosyaların bulunduğu lokasyon içinde yeni bir pipe oluşturulur.<br />
$ mkfifo izlemepipe</p>
<p>tkprof ile bu pipe dosyasından çıktı oluşturulur.<br />
$ tkprof izlemepipe test_ora_3419.out</p>
<p>Başka bir oturumdan izleme dosyasının olduğu dizin değiştirilir ve aşağıdaki komut çalıştırılır.<br />
$ cat test_ora_3419.trc &gt; izlemepipe</p>
<p>SQL izleme dosyası maksimum büyüklüğü aştığında, veritabanı sunucu prosesi izleme dosyasına izleme bilgisini yazmayı durdurur. UNIX/Linux sistemlerde eğer max_dump_file_size parametresi ayarlanmadıysa izleme dosya büyüklüğünde maksimum bir limit yoktur.</p>
<p>Eğer bir oturum izleniyorsa ve izleme dosyası max_dump_file_size parametresince belirlenen limiti aşmak üzere olduğu anlaşıldıysa, dinamik olarak limit gözardı edilebilir ve böylece izleme bilgisi kaybedilmez. Bunu yapmak izleme dosyasına yazan prosesin ORACLE PID’sini bulmak için V$PROCESS görünümünün PID kolonuna sorgu yapılır. Ardından SQL*Plus içinden aşağıdaki komutlar çalıştırılır.</p>
<pre class="brush: sql; title: ;">
CONNECT / AS SYSDBA
ORADEBUG SETORAPID &lt;pid&gt;
ORADEBUG UNLIMIT
</pre>
<p>İzleme dosyasında TKPROF aracının çalıştırılması</p>
<p>TKPROF kullanılmadan önce izleme dosyasının oluşturulması ve yerinin belirlenmesi gerekmektedir. Oracle izleme dosyalarını &#8212; PMON gibi daemon prosesleri haricindeki işlemleri &#8212;  user_dump_dest başlangıç parametresinde belirlenen dizine yazar. Unix/Linux sistemlerde, izleme dosyası, bu dosyaya yazan sunucu prosesinin işletim sistemi PID’si ile örtüşen bir isme sahiptir.</p>
<p>Eğer user_dump_dest dizininde çok sayıda izleme dosyası varsa, istenen dosyanın bulunması biraz teferrüatlı olabilir. Bunun üstesinden gelmenin en önemli yolu dosyaların oluşturulma zamanına bakmaktır. Diğer bir metot ise oturum katmanında izleme dosyasının etkinleştirilmesinde kullanılan komut içine bu izleme dosyasını diğerlerinden farklı kılıp anlaşılması için bir “yorum” eklemektir. Bununla ilgili örnek aşağıda yer almaktadır.</p>
<pre class="brush: sql; title: ;">
ALTER SESSION /* Module hr_22042011.c */ SET sql_trace = TRUE;
</pre>
<p>Bunun yanında hangi oturumların hangi izleme dosyasına işlem yaptığını görmek için aşağıdaki sorguda kullanılabilir. Bunun neticesinde izlenmesi istenen oturumun SQL komutlarının yer aldığı izleme dosyasına TKPROF ile izleme başlatılabilir.</p>
<pre class="brush: sql; title: ;">
select b.username, c.value || '\' || lower(d.value) || '_ora_' ||
       to_char(a.spid, 'fm00000') || '.trc' &quot;TRACE_FILE&quot;
from v$process a, v$session b, v$parameter c, v$parameter d
where a.addr   = b.paddr
and c.name     = 'user_dump_dest'
and d.name     = 'db_name'
and b.username is not null;

USERNAME TRACE_FILE
-------- ------------------------------------------------------------
SYS      /u01/app/oracle/diag/rdbms/ugur/ugur/trace/UGUR_ora_3345.trc
HR       /u01/app/oracle/diag/rdbms/ugur/ugur/trace/UGUR_ora_3564.trc
ARDA     /u01/app/oracle/diag/rdbms/ugur/ugur/trace/UGUR_ora_3708.trc
</pre>
<p>Bunun yanında Oracle 11g itibariyle hangi oturumun hangi izleme dosyasına yazdığını bulmak daha kolaydır. Bulunması istenen izlenen dosyasının adı ilgili oturumundan aşağıdaki sorgunun çalıştırılmasıyla kolayca bulunur.</p>
<pre class="brush: sql; title: ;">
select value from v$diag_info where name=’Default Trace File’;
</pre>
<p>Unix/Linux platformlarında TKPROF uygulamasını çalıştırmak için terminal penceresinden aşağıdaki komut çalıştırılır.</p>
<p>tkprof &lt;trace file&gt; &lt;output file&gt; [explain=&lt;username/password&gt;] [sys=yes | no] [table=&lt;schema&gt;.&lt;table&gt;] [insert=&lt;filename&gt;] [record=&lt;filename&gt;] [sort=&lt;keyword&gt;]</p>
<p>Eğer TKPROF komutunu herhangi bir arguman kullanmadan çalıştırırsanız tüm seçenekler ekrana listelenecektir. Basit formda, TKPROF komutu bir çıktı dosya ismi ve bir SQL izleme dosyası ile tanımlanır. TKPROF, izleme dosyasını okuyacak ve belirlenen bir çıktı ismi altında bu rapor dosyasını oluşturacaktır. TKPROF, veritabanına bağlanmaz ve bu rapor SQL komutları için çalıştırma planları içermez. SYS kullanıcısı tarafında yinelemeli olarak çalıştırılan SQL komutlarıda bu rapor içinde yer alır ve SQL komutları izlenen oturumunda çalıştırma sırasına göre listelencektir.</p>
<p>Eğer “explain” kelimesi eklenirse TKPROF veritabanına bağlanır ve izleme dosyası içinde bulunan her bir SQL komutu için bir EXPLAIN PLAN çalıştırır. Açıklama planı sonuçları bu rapor dosyası içinde yer alacaktır. TKPROF komutunda tanımlanan kullanıcı adının izlenen oturumun kullanıcısı ile aynı olması gerekmektedir. Sırasıyla explain kelimesini kullanmak için bir plan tablosuna gerek yoktur, TKPROF bir tane oluşturacak ve gerektiğinde kendi plan tablosunu düşürecektir.</p>
<p>Eğer sys=n olarak tanımlanırsa, TKPROF, SYS kullanıcısı olarak Oracle tarafından işlenen SQL komutlarını rapora dahil etmeyecektir. Bu raporu daha özlü hale getirecek ve sadece uygulama tarafından halihazırda çalıştırılan komutları içerecektir. Aslında bu idealdir, çünkü Oracle dahili SQL komutları Oracle veritabanı kernel yazılımcıları tarafından en üst seviyede optimize edilmiştir ve bizim bunlar üzerinde kafa yormamıza gerek yoktur.</p>
<p>Eğer “insert” kelimesi kullanılırsa bu rapora ilave olarak bir SQL scripti oluşturulacaktır. Bu SQL scripti tkprof_table adında bir tablo oluşturacak ve raporda yer alan her bir SQL komutu için bir satır ekleyecektir. Bu satır, izlenen SQL komutunun textini ve rapor içinde görünen tüm istatistiklerini içerecektir. Bu özelliği TKPROF raporunu efektif olarak veritabanına yüklemek ve istatistikleri analiz ve manipüle etmek için SQL’i kullanır. Nadiren kullanımı olsa gerektiği anlarda faydalı bir özelliktir.</p>
<p>Eğer “record” kelimesi eklenirse, izleme etkinken uygulama tarafından yayınlanan her bir SQL komutunun bir kopyasını içeren bir SQL scripti oluşturulur. Aslında bu bilgi TKPROF raporunun kendisindende elde edilebilir, ancak bu durumda kayıt etmek için kopyala-yapıştır gibi zahmetli işlemlere girilecektir.</p>
<p>“Sort” kelimesi pekçok durumda kullanışlıdır. Tipik olarak bir TKPROF raporu yüzlerce SQL komutu içerebilir, ancak pek çok durumda sadece belirli SQL komutlarını analiz etmek ihtiyacı duyulmaktadır.  İşte bu durumlarda, “sort” kelimesi SQL komutlarının listesini sıralamaya izin verecek, böylece tüm dosyayı taramak zahmetine girilmeyecektir.  Bazı durumlarda sort komutları işlem yapmaz, örneğin “tüketilen CPU zamanı”  bazında komutlar tasnif(sort) edilmez , bunun yerine “çözümleme(parsing) için harcanan CPU zamanı” veya “satırları alıp getirme(fetching) için harcanan CPU zamanı” bazında tasnif yapılabilir. Tasnif(sort) seçenekleri aşağıda yer almaktadır.</p>
<blockquote><p>PRSCNT          Çözümleme sayısı<br />
PRSCPU         Çözümleme için harcanan CPU zamanı<br />
PRSELA          Çözümleme süresince geçen(elapsed) zaman<br />
PRSDSK          Çözümleme esnasında diskten yapılan fiziksel okuma sayısı<br />
PRSQRY          Çözümleme süresince sürekli blok okuma sayısı<br />
PRSCU            Çözümleme esnasında mevcut blok okuma sayısı<br />
PRSMIS           Çözümleme süresince library cache kayıpları sayısı<br />
EXECNT         Çalışma(execute) sayısı<br />
EXECPU        Çalışma için harcanan CPU zamanı<br />
EXEELA         Çalışma süresince geçen zaman<br />
EXEDSK         Çalışma esnasında diskten yapılan fiziksel okuma sayısı<br />
EXEQRY          Çalışma süresince sürekli blok okuma sayısı<br />
EXECU           Çalışma esnasında mevcut blok okuma sayısı<br />
EXEROW        Çalışma esnasında işlenen satır sayısı<br />
EXEMIS          Çalışma süresince library cache kayıpları sayısı<br />
FCHCNT        Fetch sayısı<br />
FCHCPU        Satırları alıp getirme(fetching) için harcanan CPU zamanı<br />
FCHELA         Satırları alıp getirme esnasında geçen zaman<br />
FCHDSK         Satırları alıp getirme esnasında diskten yapılan fiziksel okuma sayısı<br />
FCHQRY         Satırları alıp getirme süresince sürekli blok okuma sayısı<br />
FCHCU          Satırları alıp getirme esnasında mevcut blok okuma sayısı<br />
FCHROW       Alıp getirilen satır sayısı.<br />
USERID          İmleci çözümleyen kullanıcının userid’si</p></blockquote>
<p>Aşağıda  UGUR_ora_3564.trc adlı SQL izlemesinin TKPROF ile çağrılma işlemi yer almaktadır. HR şemasının SQL komutları ile ilişkili sort seçenekleri OUT.PRF adı altında bir çıktı dosyasına yazılacak ve STOREHR.SQL adı altında bir SQL scripti oluşturulacaktır.</p>
<blockquote><p>TKPROF UGUR_ora_3564.trc OUTPUT.PRF<br />
EXPLAIN=hr/hr INSERT=STOREHR.SQL SYS=NO<br />
SORT=EXECPU,FCHCPU,EXECU,EXEROW,PRSDSK,FCHROW</p></blockquote>
<p>İlave olarak, tüm izleme dosyası için bekleme olayları dosyanın sonunda özetlenir. Oturum için bekleme olaylarının izleme dosyasına yazıldığından emin olmak için aşağıdaki komut çalıştırılır.</p>
<pre class="brush: sql; title: ;">
ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';
</pre>
<p>Bu 10046 izleme olayını ilerki yazıda detaylı olarak örneklerle inceleyeceğim için bu yazıda kullanımına ve detaylarına girmeyeceğim.</p>
<p>Eğer bekleme bilgiside TKPROF raporunda yer alırsa, ilgili bekleme olayları TKPROF çıktısında aşağıdaki gibi bir bölümde yer alacaktır.</p>
<pre class="brush: sql; title: ;">
Event waited on             Times Waited Max.Wait Total Waited
--------------------------  ------------ -------- ------------
db file sequential read     7884         0.12     5.43
direct path write           953          0.00     0.00
direct path write temp      861          0.00     0.05
db file parallel read       12           1.61     6.12
db file scattered read      4452         0.08     1.39
direct path read            7173         0.00     0.05
direct path read temp       7201         0.00     0.46
rdbms ipc reply             27           0.00     0.04
SQL*Net message to client   2            0.00     0.00
SQL*Net message from client 2            0.00     0.00
</pre>
<p><strong>TKPROF raporlarının okunması</strong><br />
Bütün TKPROF raporları; TKPROF sürümü, raporun hazırlandığı tarih ve zaman, kullanılan izleme dosyasının adı, kullanılan tasnif seçenekleri ve rapor içindeki kolon başlıklarının özet tanımını listeleyen bir başlık ile başlar ve özet istatistik serileri ile biter. Aşağıda örnek bir TKPROF başlığı yer almaktadır.</p>
<pre class="brush: sql; title: ;">
TKPROF: Release 11.1.0.7.0 - Production on Wed Apr 27 12:28:45 2011

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

Trace file: UGUR_ora_3564.trc
Sort options: default

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

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>TKPROF raporunun ana gövdesi, SQL izlemesi etkinken veritabanında çalıştırılan her bir farklı SQL komutuna ait bir girişten meydana gelir. Bir önceki cümle ile oynarken bir takım incelikler vardır. Eğer bir uygulama, mesela “müşteriler” tablosuna 50 sefer sorgu çekerse ve her seferinde farklı musteri_id değeri kullanırsa, bu durumda TKPROF raporunda 50 adet farklı giriş olacaktır. Ancak, eğer musteri_id değeri için bind değişkeni kullanılırsa, rapor içinde bu komutun 50 sefer çalıştırıldığı işareti ile birlikte sadece tek bir giriş gözükecektir.  Dahada ötesinde ayrıca bu raporda, veritabanının kendisi tarafından başlatılan “tekrarlamalı işlemler” olarakta adlandırılan “data dictionary” ve “dictionary cache” gibi işlemleri uygulayan SQL cümleleride işlem sırasına göre yer alacaktır.</p>
<p>TKPROF raporu içindeki her bir SQL cümlesi tek satırda ardışık yıldızlarla ayrılmaktadır. Her bir girişin ilk bölümü SQL komutunu ve bu SQL komutu ile ilişkili çözümleme, çalıştırma ve satır alıp getirme istatistiklerini listeler. Aşağıda örnek bir giriş yer almaktadır.</p>
<pre class="brush: sql; title: ;">
**************************************************************

SELECT   *
FROM     emp
ORDER BY emp_id

call     count  cpu  elapsed  disk  query current  rows
------- ------  ---- -------  ----- ----- -------  ----
Parse   1       0.01 0.02     0     0     0        0
Execute 1       0.00 0.00     0     0     0        0
Fetch   14      0.59 0.99     0     33633 0        194
------- ------  ---- -------  ----- ----- -------  ----
total   16      0.60 1.01     0     33633 0        194

Misses in library cache during parse: 1
Optimizer goal: CHOOSE
Parsing user id: HR  [recursive depth: 0]

**************************************************************
</pre>
<p>Dosyanın içine baktığımızda; ilk satırda, SQL izlemesi etkinken uygulamanın bu komutu bir sefer çözümlediğini(parse) görüyoruz. Çözümleme işlemi için 0.01 saniyelik CPU tüketimi 0.02 saniye geçen sürede meydana gelmektedir. Buna rağmen herhangi bir fiziksel I/O ve hatta herhangi bir tampon(buffer) okuması gerekmeketedir.</p>
<p>İkinci satırda ise çalıştırma(execute) sayısının tek sefer olduğunu görüyüruz. Bu tek sefer çalıştırma için sistem 0.01 saniyenin altında CPU tüketmekte ve çalıştırma için geçen süre 0.01 saniye altında olmaktadır. Tekrardan, herhangi bir fiziksel I/O işlemi veya tampon okuması olmamaktadır. Burada ilginç olan nokta, çözümleme ve çalıştırma sürecinde Oracle’ın kaynakları çalıştırma yerine çözümleme esnasında kullanması ve böylece çözümleme sonrası çalıştırma tüketiminin genelde çok düşük kalmasıdır.</p>
<p>Bir sonraki satır, SQL komutunun 14 satır alıp getirme(fetch) işlemiyle 14 satır çağırdığını ve toplamda 194 satır aldığını göstermektedir. Bu 14 çağrı süresince toplamda 0.59 saniye CPU tüketilmiş ve işlem için geçen süre 0.99 saniye olmaktadır. Fizisel bir I/O işlemi olmamış ve sürekli okuma modunda 33,633 tampon okuması meydana gelmektedir. Diğer bir kelime ile “fetch” işleminde, tampon bellek içinde 33,633 hit olmakta ve herhangi bir kayıp meydana gelmemektedir(fiziksel I/O oluşmadığından). Ben bu sorguyu SQL*Plus üzerinden çalıştırdığımdan, tek bir “fetch” çağrısında pekçok satır alınıp getirilmesinden dolayı SQL*Plus’ın dizin arayüzü kullandığını görüyoruz.</p>
<p>İlk bölüm dışında kalan kısımlarda; tek bir library cache kaybının olduğunu (yani SQL komutu henüz paylaşımlı havuzda değildir), çalıştırma planının CHOOSE optimizer modu ile gerçekleştiğini, çözümleme işleminin ise HR şeması tarafından gerçekleştirildiğini gözlemliyoruz.</p>
<p>SQL komutlarının yinelemelerine ve library cache istatistiklerine bakarak, uygulamanın Oracle paylaşımlı SQL olanaklarına uygun olup olmadığı belirlenebilir. Bind değişkenleri kullanılıyormu veya her bir sorgu boştan çözümleme gerektiren tekil bir komutamı ait?</p>
<p>Çözümleme, çalıştırma ve satırları alıp getirme sayılarından, uygulamanın Oracle API’lerini düzgün şekilde kullanıp kullanmadığıda görülebilmektedir. Uygulamalar tek seferde satırları alıp getiriyormu? Uygulama, bir imleci açık bırakıp bir sonraki  çözümlemeleri engelleyeceği yerde, aynı imleci yüzlerce sefer yeniden çözümlüyormu?  Uygulama SQL cümlelerini PL/SQL blokları içine gömmek yerine, oldukça fazla sayıdaki basit SQL işlemlerimi gönderiyor veya dizin bind’lerini mi kullanıyor?</p>
<p>CPU ve I/O istatistiklerine bakarak en çok sisTem kaynaklarını tüketen komutlar gözlemlenebilir. Bazı uygulamaların yapısı yeniden geliştirilerek, daha az CPU ve I/O tüketimi olabilirmi? Az biraz tampon okumaları traşlanarak çalıştırma planında biraz rahatlama yapılabilirmi? belki komutlar olması gerektiğinden sık çalıştırılıyor, bu yinelemeler azaltılabilirmi? Bunun yanında tablolar yanlış birleştirme (join) metodu kullanıldığından dolayı sırasına göre alıp getirmesi gerekenden daha fazla satırmı işlemekte? veya birbirinin aynısı(duplicate) kayıtların çağrılması gerekmediği halde çağrılıyormu?</p>
<p>TKPROF raporu olduğundan uzun gözükebilir ve bakıldığında ilkel bir rapor formatına sahip olabilir, ancak çok eski sürümlerden bugünlere gelmesine rağmen bilhassa SQL komutlarının performansının geliştirilmesinde çok kritik bir öneme ve faydaya sahiptir. Her ne kadar SQL komutlarının analizi ve performansının iyileştirilmesi Oracle 11g sürümünde “advisor” lar ile otomatikleştirilmiş olsada, sistem üzerindeki yüklerin analizi ve bu bekleme olaylarına göre SQL komutlarının omurgalarının iyileştirmesinde TKPROF’a alternatif bir Oracle built-in aracı bulunmamaktadır.</p>
<p>Daha sonraki yazımda 10046 izleme olayının TKPROF ile entegrasyonu ve 10046 izleme sonucunda kompleks sorgularda gözlemlenen bekleme olaylarının genel veritabanı performansı üzerine etkisinin analizini işleyeceğim.</p>
<p><span style="color: #0000ff;"><strong>Uğur İnal </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/06/tkprof-ile-sql-uygulamalarinin-performans-analizi.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Indekslerin daha büyük bloğa sahip tablespace içerisine taşınması ve performanslarının durumu</title>
		<link>http://turkceoracle.com/2011/06/indekslerin-daha-buyuk-bloga-sahip-tablespace-icerisine-tasinmasi-ve-performanslarinin-durumu.html</link>
		<comments>http://turkceoracle.com/2011/06/indekslerin-daha-buyuk-bloga-sahip-tablespace-icerisine-tasinmasi-ve-performanslarinin-durumu.html#comments</comments>
		<pubDate>Sun, 26 Jun 2011 19:01:20 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[performans iyileştirme]]></category>
		<category><![CDATA[Uğur İnal]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=444</guid>
		<description><![CDATA[Eğer bir indeks daha büyük blok büyüklüğündeki tablespace içinde yeniden inşa edilirse IFFS(Index Fast Full Scan) performansında iyi veya kötü yönde bir değişiklik olurmu? Rastgele giriş yapılan indeksler %70-75 aralığında PCT_USED değerine sahipken, bu indeksler, doldurulan farklı evreler içinde eş zamanlı olarak rastgele 50-50 blok bölünmesi meydana getirir. Bir indeksi yeniden insa ederek, %15 kadar [...]]]></description>
			<content:encoded><![CDATA[<p>Eğer bir indeks daha büyük blok büyüklüğündeki tablespace içinde yeniden inşa edilirse IFFS(Index Fast Full Scan) performansında iyi veya kötü yönde bir değişiklik olurmu?</p>
<p>Rastgele giriş yapılan indeksler %70-75 aralığında PCT_USED değerine sahipken, bu indeksler, doldurulan farklı evreler içinde eş zamanlı olarak rastgele 50-50 blok bölünmesi meydana getirir. Bir indeksi yeniden insa ederek, %15 kadar indeks yoğunluğu artabilir ve böylece tüm indeks büyüklüğü azalabilir. Azalan blok geneli aynı zamanda indeks büyüklüğü ve blok büyüklüklerinin farklılıklarına bağlı olarak, indeksi de bir miktar azaltabilir. Fast Full Index Scan üyelik maliyetleri indeksin tüm büyüklüğü ile orantılı olduğundan, bir indeksi birleştirmek(defragmantation), en fazla potensiyel faydalar sunan erişim yolu olmaktadır. Bir indeksin büyüklüğünü azaltmak bu yüzden daha sonraki performansı etkiler.  Oysaki, mevcut blok büyüklüğünde indeksin yeniden inşası muhtemelen aynı benzer sonuca ulaşır(artı blok genel giderleri), indeksi sıkılaştırır ve potensiyel olarak daha iyi performans ile sonuçlanır. Buna karşın, indeks bloğu bir kez tekrardan bölünmeye başladımı, neticede bu indeks kendisinin önceki durumuna tekrar geri döner. İşte bu yüzden, daha büyük blok büyüklüğünün ötesinde, indeksin birleştirilmesi (defragmentation) genel bir performans iyileştirme yolu olmaktadır.</p>
<p>İndeksi daha büyük bloğa sahip tablespace içinde saklayarak, bu indeksin ait olduğu tablodan farklı bir fiziksel veri dosyası içinde saklamak gerekmektedir. Bu veri dosyası performansı arttırmak için nispeten daha hızlı bir disk olmalı ve indeksler dışında başka dosyalar içermemelidir. Daha büyük blok büyüklüğünden ziyade, indeksin depolandığı yeni yerin fiziksel karakteristikleri esasında performansı etkiler. Eğer bir indeks aynı blok büyüklüğünde, daha büyük bloğa sahip indeksler ile aynı fiziksel karakteristiklere sahip yerde yeniden inşa edilirse, daha sonraki performans aynı şekilde artar(veya azalır).<br />
Tabii bunun yanında pekçok muhtemel sebepler vardır, sistem daha büyük blok büyüklüğüne sahip indeksler kullanırken, daha az meşgul olmakla beraber indeksin daha büyük kısmı fiziksel olarak önbelleklenir.</p>
<p>Indeks Fast Full Scan, nadirende olsa bir ölçeklenebilirlik sorunudur. Bu noktada, aslında gerçekten kullandığımız uygulamaların yüzlerce büyüklükte eşzamanlı indeks fast full scan yapmasını istermiyiz? Uygulamayı bu gereksiz indeks fast full scan giderlerinden kurtarmak, indeksleri boş yere daha geniş bloğa sahip tablespace içine taşımaktan daha verimli bir yol olacaktır. Tabii bu başka bir yazıda tartışma konusu olur. </p>
<p>Peki, esas bu yazının ana konusuna gelelim. Indeks Fast Full Scan işleminin performansı indeksin daha büyük bloğa sahip tablespace içine taşınması neticesinde değişirmi? Kesinlikle, değişir…Ancak, bu bahsedilen değişim, indeksin daha büyük bloğa sahip olması sonucunda çoklu blok(multiblock) okuma performansının geliştirilmiş olması anlamına gelmez.  </p>
<p>Oracle, çoklu blok okuması gerçekleştirirken, çoklu blok başına ne kadar blok okuduğunu belirlemek için db_file_multiblock_read_count parametresindeki değeri kullanır. db_file_multiblock_read_count değerini belirlemek için, Oracle, sistem istatistiklerini kullanarak en uygun değeri atar. Yani, eğer db_file_multiblock_read_count değeri 16 olarak atanmışsa, çoklu-blok okuma işlemi süresince Oracle bir kerede 16 blok okumak için çalışacaktır. Bu parametre değerinin veritabanının varsayılan blok büyüklüğüne dayandığını unutmamak gerekir. Yani, eğer veritabanı varsayılan blok büyüklüğü 8K ve db_file_multiblock_read_count değeri 16 ise, çoklu-blok işlemleri süresince Oracle bir kerede 16k x 8 blok okumasına çalışacak ve okuyacaktır.</p>
<p>Ancak, eğer varsayılan blok büyüklüğünde olmayan(mesela 16k) bir segment varsa, blok okuma süresince Oracle o an okunan blok sayısını genişletir, böylece tüm çoklu blok okumalarının maksimum büyüklüğü, o varsayılan blok büyüklüğü ile özdeş olur</p>
<p>Eğer db_file_multiblock_read_count değeri 16 ve varsayılan blok büyüklüğü 8K ise, bir objenin çoklu blok okuması bir kerede sadece 8 blok olacaktır(16 blok değil)… 2K tablespace blok büyüklüğünde bir tablespace içindeki bir objenin çoklu blok okuması ise bir kerede 64 blok olacaktır. İşte bu yüzden, bir çoklu-blok okumasının gerçek büyüklüğü veritabanı içindeki bir objenin blok büyüklüğüne bağlı kalmaksızın aynıdır.</p>
<p>Bu olayı vurgulamanın en kolay yolu, bir oturumun izlenmesi ve birbirine benzeyen çoklu-blok okumalarının belirli büyüklüklerini görmektir. Indeks Fast Full Scan olayı gerçekleştiren 8K blok büyüklüğündeki bir indeks üzerindeki izleme(trace) örneği aşağıdaki gibidir.</p>
<blockquote><p>WAIT #1: nam=’db file scattered read’ ela= 1487 file#=8 block#=1050 blocks=16 obj#=78294 tim=615409554677<br />
WAIT #1: nam=’db file scattered read’ ela= 1377 file#=8 block#=1066 blocks=16 obj#=78294 tim=615409557777<br />
WAIT #1: nam=’db file scattered read’ ela= 1143 file#=8 block#=1082 blocks=16 obj#=78294 tim=615409561563</p></blockquote>
<p>Oracle çoklu-blok okuma işlemi başına 16 x 8K blok (128K) okuma olmaktadır. Ancak, eğer indeks 16 k blok büyüklüğünde bir tablespace içerisinde yeniden oluşturulduğunda Fast Full Index Scan şu şekil olacaktır:</p>
<blockquote><p>WAIT #1: nam=’db file scattered read’ ela= 1413 file#=6 block#=14 blocks=8 obj#=78296 tim=626802128684<br />
WAIT #1: nam=’db file scattered read’ ela= 1447 file#=6 block#=22 blocks=8 obj#=78296 tim=626802131649<br />
WAIT #1: nam=’db file scattered read’ ela= 2014 file#=6 block#=30 blocks=8 obj#=78296 tim=626802135222</p></blockquote>
<p>Oracle artık, çoklu-blok başına 8 x 16K blok (128K) okumaktadır. Her iki indekste etkili olarak aynı işi yapmaktadır, her ikiside çoklu-blok başına 128K ya kadar etkili olarak okuma yapmaktadır. Peki o zaman performansta kırılma nerede oluyor?</p>
<p>Şimdi bu tezi incelemek üzere bir örnek yapalım ve canlı olarak performanstaki değişimleri gözlemleyelim.</p>
<p>Bu senaryo doğrultusunda önce 16K blok büyüklüğünde bir tablespace oluşturacağım. Ardından, başlangıçta 2 milyon kayıt bulunan basit bir tablo oluşturacağım.</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter system set db_16k_cache_size = 80m;
System altered.

SQL&gt; create tablespace ts_16k
datafile '/u02/app/oracle/tbs_16k_test1.dbf'
size 1024M uniform size 1M
segment space management manual
blocksize 16K;
Tablespace created.

SQL&gt; CREATE TABLE test_tbl AS
SELECT rownum id, add_months(sysdate,8)+7/trunc(mod(rownum,100) date
FROM dual
CONNECT BY LEVEL &lt;=2000000;
Table created.
</pre>
<p>Ardından varsayılan blok büyüklüğünde(8K) bir tablespace içerisinde indeks oluşturacağım.</p>
<pre class="brush: sql; title: ;">
SQL&gt; CREATE INDEX test_tbl_ix ON test_tbl(date);
Index created.
</pre>
<p>İndeksi defragmante etmek için tablo içindeki toplam 2 milyon kaydın yarısını siliyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; DELETE test_tbl WHERE mod(id,2)=1;
1000000 rows deleted.

SQL&gt; COMMIT;
Commit complete.
</pre>
<p>Mevcut istatistikleri topluyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; exec dbms_stats.gather_table_stats(
ownname=&gt;'UGUR',
tabname=&gt;'TEST_TBL',
estimate_percent=&gt;null,
method_opt=&gt;'FOR ALL COLUMNS SIZE 1');

PL/SQL procedure successfully completed.
</pre>
<p>db_file_multiblock_read_count parametre değerinin 16 olarak ayarlandığını kontrol ediyoruz.</p>
<pre class="brush: sql; title: ;">
SQL&gt; show parameter db_file_multiblock

NAME                         TYPE        VALUE
---------------------------- ----------- -----
db_file_multiblock_read_count integer    16

SQL&gt; set autotrace traceonly
</pre>
<p>Önbellek içinde muhtemel blokların olmadığından emin olmak ve senaryo çalışmasının eksiksiz olmasını sağlamak için önbellek boşaltılır.</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter system flush buffer_cache;
System altered.
</pre>
<p>Oturumu izlemeye(trace) başlıyoruz.</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter session set events '10046 trace name context forever, level 12';
Session altered.
</pre>
<p>Ardından Indeks Fast Full Scan yoluyla test_tbl_ix indeksinden çoklu-blok okuması gerçekleştirmek için bazı SQL sorgularını çalıştırıyoruz. “Parsing” olayına bağlı maliyetleri düşürmek için bu SQL komutunu “flush buffer_cache” komutundan önce çalıştırmanız tavsiye edilir.</p>
<pre class="brush: sql; title: ;">
SQL&gt; SELECT /*+ index_ffs (test_tbl, test_tbl_ix) */ date_field FROM test_tbl where date_field &gt; '’20- DEC-2011';

1000000 rows selected. 

Execution Plan
----------------------------------------------------------
Plan hash value: 251320893
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 7812K| 1173 (2)| 00:00:15 |
|* 1 | INDEX FAST FULL SCAN| TEST_TBL_IX | 1000K| 7812K| 1173 (2)| 00:00:15 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(&quot;DATE_FIELD&quot;&gt;TO_DATE('2011-12-20 00:00:00', 'yyyy-mm-dd
hh24:mi:ss'))

Statistics
----------------------------------------------------------
0           recursive calls
0           db block gets
6320        consistent gets
5307        physical reads
0           redo size
5167309     bytes sent via SQL*Net to client
11385       bytes received via SQL*Net from client
1001        SQL*Net roundtrips to/from client
0           sorts (memory)
0           sorts (disk)

1000000 rows processed
</pre>
<p>Bu arada sürekli okumaların(consistent reads) değerinin 6320 olduğuna dikkat edin. İzleme işini kapatıyoruz.</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter session set events '10046 trace name context off';
Session altered.
</pre>
<p>Eğer bu sorgunun TKPROF raporuna bakarsak;</p>
<pre class="brush: sql; title: ;">
SELECT /*+ index_ffs (test_tbl, test_tbl_i) */ date_field FROM test_tbl where date_field &gt; '20-DEC-2011’

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     0.73   1.23     5307   6320   0      1000000
------- ------    ----- -------   ------ ----  ------ -------
total    1003     0.73   1.23     5307   6320   0      1000000
</pre>
<p>CPU maliyetinin 0.73 saniye, geçen sürenin(elapsed) 1.23 saniye ve sorgu okumasının 6320 olduğunu gözlemliyoruz.</p>
<blockquote><p>WAIT #8: nam=&#8217;db file scattered read&#8217; ela= 738 file#=5 block#=242233 blocks=16 obj#=59933 tim=341634522940</p></blockquote>
<p>Bu arada izleme dosyasında, db_file_multiblock_read_count değerininin 16 olarak ayarlanmasından beklendiği gibi, dağınık okumalar(scattered reads) bir kerede 16 blok okumaktadır. Şimdi bu performansı geliştirmeye çalışacağız. Şimdi indeksin daha büyük bloğa sahip bir tablespace içerisine taşınması yoluyla neler olacağını gözlemleyeceğiz…</p>
<p>Bu amaçla; ilk olarak 16k blok büyüklüğünde daha önceden oluşturduğumuz tablespace içerisine indeksi taşıyoruz, ardından önbelleği boşaltıyor ve izlemeyi açıyoruz.</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter index test_tbl_ix rebuild tablespace ts_16k;
Index altered.

SQL&gt; alter system flush buffer_cache;
System altered.

SQL&gt; alter session set events '10046 trace name context forever, level 12';
Session altered.
</pre>
<p>Şimdi bir önceki çalıştırdığım sorguyu tekrardan çalıştırarak performansta bir değişme olup olmadığını test ediyorum.</p>
<pre class="brush: sql; title: ;">
SQL&gt; SELECT /*+ index_ffs (test_tbl, test_tbl_i) */ date_field FROM test_tbl where date_field &gt; '20-DEC-2011;

1000000 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 251320893
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 7812K| 367 (4)| 00:00:05 |
|* 1 | INDEX FAST FULL SCAN| TEST_TBL_IX | 1000K| 7812K| 367 (4)| 00:00:05 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(&quot;DATE_FIELD&quot;&gt;TO_DATE('2011-12-20 00:00:00', 'yyyy-mm-dd
hh24:mi:ss'))

Statistics
----------------------------------------------------------
1           recursive calls
0           db block gets
2317        consistent gets
1310        physical reads
0           redo size
5167309     bytes sent via SQL*Net to client
11385       bytes received via SQL*Net from client
1001        SQL*Net roundtrips to/from client
0           sorts (memory)
0           sorts (disk)

1000000 rows processed
</pre>
<p>Başlangıç olarak, sürekli okumaların 6230’dan 2317’ye düştüğünü gözlemliyoruz.</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter session set events '10046 trace name context off';
Session altered.

SELECT /*+ index_ffs (test_tbl, test_tbl_i) */ date_field FROM test_tbl where date_field &gt; '20-DEC-2011’

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     0.79   1.08      1310  2317    0      1000000
------- ------    ----- -------   ------ ----  ------- -------
total    1003     0.79   1.08      1310  2317    0      1000000
</pre>
<p>Güzel bir sonuç! Geçen(elapsed) sürede 1,23 ten 1.08’e düştü. Yaklaşık %1.1 lik bir gelişme fena sonuç değil. Bunun yanında cevap süreside iyileşti, ve sonuçta indeksin 16K blok büyüklüğünde bir tablespace içine taşınmasıyla genel performansta ortalama %10’luk bir iyileşme meydana geldi.</p>
<blockquote><p>WAIT #1: nam=&#8217;db file scattered read&#8217; ela= 767 file#=7 block#=46 blocks=8 obj#=59933 tim=342035983379
</p></blockquote>
<p>Bu arada dağınık(scattered) okumaların varsayılan 8K büyüklükte 16 blok okuması yerine 8 blok okuması yaptığını ve böylece çoklu-blok okumalarının aynı kaldığını gözlemliyoruz.</p>
<p>16K blok büyüklüğünde bir tablespace içerisinde indeksin yeniden inşası sonucu performans gelişmesine karşılık, acaba 8K blok büyüklüğündeki eski tablespace içerisinde indeks basitçe yeniden inşa edilirse ne olur peki? Buna da bakalım hemen…</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter index test_tbl_ix rebuild tablespace test_tbl;
Index altered.

SQL&gt; set autotrace traceonly

SQL&gt; alter system flush buffer_cache;
System altered.

SQL&gt; alter session set events '10046 trace name context forever, level 12';
Session altered.

SQL&gt; SELECT /*+ index_ffs (test_tbl, test_tbl_i) */ date_field FROM test_tbl where date_field &gt; '20-DEC-2011';

1000000 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 251320893
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000K| 7812K| 594 (3)| 00:00:08 |
|* 1 | INDEX FAST FULL SCAN| TEST_TBL_IX | 1000K| 7812K| 594 (3)| 00:00:08 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(&quot;DATE_FIELD&quot;&gt;TO_DATE('2011-12-20 00:00:00', 'yyyy-mm-dd
hh24:mi:ss'))

Statistics
----------------------------------------------------------
0           recursive calls
0           db block gets
3664        consistent gets
2655        physical reads
0           redo size
5167309     bytes sent via SQL*Net to client
11385       bytes received via SQL*Net from client
1001        SQL*Net roundtrips to/from client
0           sorts (memory)
0           sorts (disk)

1000000 rows processed
</pre>
<p>Yukardada görüldüğü üzere dağınık okumalar 16K blok büyüklüğündeki tablespace içindeki indeksin altına düşmese bile eski orijinal durumundaki gibide yüksek değil!</p>
<pre class="brush: sql; title: ;">
SQL&gt; alter session set events '10046 trace name context off';
Session altered.

SELECT /*+ index_ffs (test_tbl, test_tbl_i) */ date_field FROM test_tbl where date_field &gt; '20-DEC-2011'

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     0.65   0.99     2655   3664   0      1000000
------- ------    ----- -------   ------ ----  ------ -------
total    1003     0.65   0.99      2655  3664   0      1000000
</pre>
<p>İndeksin varsayılan blok büyüklüğündeki tablespace içerisinde inşası sonrasında geçen süre değeri, 16K blok büyüklüğündeki tablespace içinde bu indeksin inşası sonrasındaki değerinden bile daha düşük…Bu arada CPU süresi’de yaklaşık %10 daha iyi.</p>
<blockquote><p>WAIT #1: nam=&#8217;db file scattered read&#8217; ela= 668 file#=5 block#=222953 blocks=16 obj#=59933 tim=342792899797</p></blockquote>
<p>Bu arada dağınık okumalar tekrardan bir seferde 16 blok okumaya geri döndüler. Yani, bir indeksi daha büyük bloğa sahip tablespace içerisinde inşa atmek kadar, o indeksi yeniden inşa etmekte indeks maliyetini önemli derecede düşürmektedir.</p>
<p><span style="color: #0000ff;"><strong>Uğur İnal </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/06/indekslerin-daha-buyuk-bloga-sahip-tablespace-icerisine-tasinmasi-ve-performanslarinin-durumu.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>“db file sequential read” bekleme olayı üzerine detaylı bir inceleme</title>
		<link>http://turkceoracle.com/2011/06/%e2%80%9cdb-file-sequential-read%e2%80%9d-bekleme-olayi-uzerine-detayli-bir-inceleme.html</link>
		<comments>http://turkceoracle.com/2011/06/%e2%80%9cdb-file-sequential-read%e2%80%9d-bekleme-olayi-uzerine-detayli-bir-inceleme.html#comments</comments>
		<pubDate>Sun, 26 Jun 2011 18:57:29 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[performans iyileştirme]]></category>
		<category><![CDATA[Uğur İnal]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=441</guid>
		<description><![CDATA[db file sequential read bekleme olayı, indekslere,rollback(veya undo) segmentlerine, rowid yoluyla erişilen tablolara, kontrol dosyalarına ve veri dosyası başlıklarına karşı tek-blok okuma işlemi gerçekleştiren işlemlerin SQL komutlarınca(hem kullanıcı hemde tekrarlamalı) başlatılır. Bu bekleme olayı sistem çapında beklemelere göre genellikle top 5 bekleme olayları içinde yer almaktadır. Bu objeler için fiziksel I/O istekleri gayet normaldir, yani [...]]]></description>
			<content:encoded><![CDATA[<p>db file sequential read bekleme olayı, indekslere,rollback(veya undo) segmentlerine, rowid yoluyla erişilen tablolara, kontrol dosyalarına ve veri dosyası başlıklarına karşı tek-blok okuma işlemi gerçekleştiren işlemlerin SQL komutlarınca(hem kullanıcı hemde tekrarlamalı) başlatılır. Bu bekleme olayı sistem çapında beklemelere göre genellikle top 5 bekleme olayları içinde yer almaktadır.</p>
<p>Bu objeler için fiziksel I/O istekleri gayet normaldir, yani db file sequential read bekleme olayının veritabanındaki varlığı, illada veritabanı veya uygulama ile ilgili birşeylerin yanlış olduğu anlamına gelmez. Bir oturumun bu olay üstünde uzun zaman harcaması da her zaman kötü bir şey olmayabilir. Buna karşılık, bir oturum eğer kuyruğa ekleme(enqueue) veya “latch free” olayları için çok fazla zaman harcıyorsa, işte bu durum iyiye işaret olmaz. İşte bu iki olay tekli blok okuma konusunu çetrefilli bir duruma sokar. Peki ne zaman “db file sequential read” olayı sorun haline gelir? Aşırılık nasıl tanımlanır? Ne zaman ve nereye bir çizgi çekmelisiniz?  Aslında bu sorulara Oracle uzmanlarınında şu ana kadar kesin cevapları yoktur, hala araştırılır ve standart cevaplar bulunmamıştır hala ne yazıkki… Mesela, db file sequential read beklemesi proses yanıt süresinin büyük bir bölümünü temsil ediyorsa o zaman “aşırılık” kelimesi bir anlam kazanır. Diğer bir yol ise, bilimsel olmayan bir avam yaklaşımı takınarak, kullanıcılar bu bekleme olayından sıkıntı yaşayıp çığlık atana kadar beklemek olacaktır. Tabii bu durum profesyonel bir yaklaşım olmaz, hele hele proaktif olarak performans geliştirme iddiasında iseniz.</p>
<p>“db file sequential read” bekleme olayının üç parametresi vardır: file#, first block# ve block count. Bu bekleme olayı “User I/O” bekleme sınıfı altında yer almaktadır. db file sequential read bekleme olayı ile karşılaşıldığında aşağıdaki anahtar noktalara dikkat edilmesi gerekir.</p>
<p>Bir Oracle prosesi, SGA içinde olmayan bloğa ihtiyaç duymakta olup bu veritabanı bloğunun diskten SGA alanına okunmasını beklemektedir.<br />
Bireysel oturumlarda bakılması gereken en önemli iki değer, TIME_WAITED ve AVERAGE_WAIT kolonları olacaktır.<br />
Dikkate değer db file sequential read bekleme olayı sıklıkla uygulama katmanından kaynaklanır.<br />
Aslında, V$SESSION_EVENT görünümünden “db file sequential read” bekleme olayında hangi oturumların yüksek TIME_WAITED değerine sahip olduğunu kolayca keşfedebiliriz. TIME_WAITED değeri LOGON_TIME değeri ile birlikte değerlendirilmeli ve daha kesin bir analiz için bu oturuma ait diğer boşta olmayan olaylar ile kıyaslanmalıdır.  Günler ve hatta haftalar boyunca açık olan oturumlarda db file sequential read olayı süresi dolgunca miktarda birikir.  Bu durumda, TIME_WAITED değeri sorun olmayabilir. Ayrıca, TIME_WAITED diğer boşta olmayan olaylar ile birlikte bir perspektife konduğunda, bu durum bizleri gafil avlanmaktan korur. Daha büyük önem taşıyan başka bekleme olayları bulunabilir. Aşağıdaki örneğe dayalı olarak, SID # 31 dikkati çekmeli ve diğerlerine göre daha kısa zamandan beri oturum açık olmasına rağmen yüksek bekleme süresinin nedeni incelenmelidir. </p>
<pre class="brush: sql; title: ;">
select a.sid,
       a.event,
       a.time_waited,
       a.time_waited / c.sum_time_waited * 100 pct_wait_time,
       round((sysdate - b.logon_time) * 24) hours_connected
from   v$session_event a, v$session b,
       (select sid, sum(time_waited) sum_time_waited
        from   v$session_event
        where  event not in (
                    'Null event',
                    'client message',
                    'KXFX: Execution Message Dequeue - Slave',
                    'PX Deq: Execution Msg',
                    'KXFQ: kxfqdeq - normal deqeue',
                    'PX Deq: Table Q Normal',
                    'Wait for credit - send blocked',
                    'PX Deq Credit: send blkd',
                    'Wait for credit - need buffer to send',
                    'PX Deq Credit: need buffer',
                    'Wait for credit - free buffer',
                    'PX Deq Credit: free buffer',
                    'parallel query dequeue wait',
                    'PX Deque wait',
                    'Parallel Query Idle Wait - Slaves',
                    'PX Idle Wait',
                    'slave wait',
                    'dispatcher timer',
                    'virtual circuit status',
                    'pipe get',
                    'rdbms ipc message',
                    'rdbms ipc reply',
                    'pmon timer',
                    'smon timer',
                    'PL/SQL lock timer',
                    'SQL*Net message from client',
                    'WMON goes to sleep')
        having sum(time_waited) &gt; 0 group by sid) c
where  a.sid         = b.sid
and    a.sid         = c.sid
and    a.time_waited &gt; 0
and    a.event       = 'db file sequential read'
order by hours_connected desc, pct_wait_time;

 SID EVENT                        TIME_WAITED PCT_WAIT_TIME HOURS_CONNECTED
---- -----------------------      ----------    -----------  ---------------
 18  db file sequential read      64446         77.0267848   105
 28  db file sequential read      1458405       90.992838    105
 19  db file sequential read      1458708       91.0204316   105
 32  db file sequential read      1462557       91.1577045   105
 13  db file sequential read      211325        53.6281055    11
 45  db file sequential read      247236        56.0469755    11
 31  db file sequential read      263113        89.0193625     2
…
</pre>
<p>db file sequential read bekleme olayını azaltmak için yapılması gereken iki şey vardır:</p>
<p>Fiziksel ve mantıksal okumalarının sayısını azaltarak pek çok bekleme olayını başlatan SQL komutunu en uygun hale getirmek.<br />
Ortalama bekleme süresini düşürmek.<br />
Bir oturumu “event 10046” veya sürekli çalışan olay verisi toplama aracı olmadan kümülatif bekleme olaylarına sebebiyet veren SQL komutlarını belirlemek zordur. Eğer hale benim gibi Oracle 9i çalışan sisteminizde varsa, aslında TOAD programı içindeki “SGA Trace” ve “Session Browser” araçları ile kümülatif bekleme olaylarına sebebiyet veren SQL komutlarını belirlemekte oldukça hızlı ve kesin sonuçlar döndürecektir.</p>
<p>Yukardaki SID #31 kaynaklı sıkıntıya sebep veren bekleme darboğazında dönersek; 263113 senti saniye bekleme olayı muhtemelen uzun çalışan bir SQL komutundan veya çok hızlı SQL komutlarından olmaktadır. Sonraki durum sorun olmayabilir. Bununla birlikte, halihazırda çalışan SQL komutuda bu bekleme olaylarına sebebiyet verebilir, ancak sebebiyet vermeyebilirde. İşte bu sebeple, geçmiş verisi olmadan interaktif teşhis sıklıkla verimsiz olmaktadır. Yüksek “ortalama DISK_READS” değerine sahip komutlar için V$SQL görünümüne sorgu çekilebilir, ancak bu durumda bunların ilgili oturuma sahip olduğunu bulabilecekmiyiz?  Bu kısıtlamalar yüzünden  kusurlu SQL komutların etrafında odaklanmak için, bu oturumu bir dahaki sefere izlemeye almak ve kusurlu SQL komutlarını belirlemek gerekmektedir. Bu kusurlu SQL komutları bulununca, bunları en uygun hale getirmek için fiziksel ve mantıksal okumaların sayısını azaltmak hedefimiz olmalıdır.  Bunun yanında V$SQL ve V$SQL_AREA görünümlerinde yer alan USER_IO_WAIT_TIME,  DIRECT_WRITES, APPLICATION_WAIT_TIME, CONCURRENCY_WAIT_TIME, CLUSTER_WAIT_TIME, PLSQL_EXEC_TIME ve  JAVA_EXEC_TIME kolonlarıda oldukça yararlı bilgiler vermektedir, bilhassa  USER_IO_WAIT_TIME kolonu ile en yüksek kümülatif veya ortalama bekleme olayına sebep veren SQL komutları tespit edilebilir.</p>
<p>db file sequential read bekleme olayının etkisini azaltmak için uygulanacak diğer bir yol ise AVERAGE_WAIT süresinin düşürülmesidir. Bu süre, diskten tek-blok getirme(fetch) işlemi için oturumun beklemek zorunda kaldığı ortalama süredir ve V$SESSION_WAIT görünümünden elde edilebilir. Yeni nesil depolama alt sistemleri mimarisinde, ortalama tek-blok okumaları 8 milisaniye veya 1 sentisaniye üzerinde olmamaktadır. Geniş önbelleği sebebiyle SAN depolama birimlerinde ise ortalama bekleme süresinin 4 milisaniye ile 8 milisaniye arasında olması beklenmektedir. Yüksek bekleme süresi maliyeti yüksek tek blok okuma işlemini temsil ettiğinden, tüm proses yanıt süresi zahmetli olacaktır.  Öteki taraftan, daha düşük ortalama bekleme süresine daha fazla tahammül edilir ve bu düşük ortalama bekleme süreleri pekçok tek-blok okuması gerçekleştiren proseslerin yanıt süreleri üzerinde daha az etkiye sahiptir. Burada, SQL optimizasyonunu engellemek için ortalama bekleme süresini geliştirmeye teşvik etmiyorum.  Eğer bir uygulama, aşırı miktarda tek blok okuması gerçekleştiren SQL komutlarına sahipse, öncelikli olarak bunlar kontrol edilmeli ve optimize edilmelidir.</p>
<p>Oturumu izlerken db file sequential read olayı ile karşılaşılırsa, bu oturumun P1 ve P2 parametrelerini temsil ettiği objeye bakmak gerekir. Objenin normalde indeks veya tablo olduğunu bulmak gerekir. Obje isim çözümlemelerinde sıklıkla DBA_EXTENTS görünümü kullanılır. Ancak, DBA_EXTENTS görünümü ilgili performans işlemi için, kompleks kalır ve kullanıcı dostu bir görünümde değildir aslında. Obje isim çözümlendirme işlemi, X$BH ve DBA_OBJECTS görünümleri kullanarak daha hızlı yapılabilir. Bu 2 görünüm için yapılması gereken bir uyarı; bloğun önbellek tamponu içine okunması için beklenmesi gerekeceğidir, aksi durumda X$BH görünümü P1 ve P2 parametreleri tarafından referans alınan tamponda bir bilgi tutmayacaktır. Ayrıca, DBA_OBJECTS görünümü, P1 ve P2 parametrelerinin referans alabileceği rollback veya undo segment objeleri içermez.</p>
<pre class="brush: sql; title: ;">
select b.sid,
       nvl(substr(a.object_name,1,30),
                  'P1='||b.p1||' P2='||b.p2||' P3='||b.p3) object_name,
       a.subobject_name,
       a.object_type
from   dba_objects a, v$session_wait b, x$bh c
where  c.obj = a.object_id(+)
and    b.p1 = c.file#(+)
and    b.p2 = c.dbablk(+)
and    b.event = 'db file sequential read'
union
select b.sid,
       nvl(substr(a.object_name,1,30),
                  'P1='||b.p1||' P2='||b.p2||' P3='||b.p3) object_name,
       a.subobject_name,
       a.object_type
from   dba_objects a, v$session_wait b, x$bh c
where  c.obj = a.data_object_id(+)
and    b.p1 = c.file#(+)
and    b.p2 = c.dbablk(+)
and    b.event = 'db file sequential read'
order  by 1;

SID   OBJECT_NAME          SUBOBJECT_NAME   OBJECT_TYPE
---  -------------         ---------------  --------------
14    P1=18 P2=310801 P3=1
32       I_LINK1_PK                         INDEX
36          MPHED30_PK                      INDEX
</pre>
<p>İndekslere dayalı sıralı(sequential) okumalar<br />
İndekslere dayalı sıralı okumalarda ana sorun indeks erişimi değil, aşırı ve yersiz indeks okumalarından kaynaklanan beklemelerdir. Önbelleği gereksiz işgal eden indeksleri görmek için alttaki sorgu kullanılabilir.</p>
<pre class="brush: sql; title: ;">
select distinct b.owner, b.segment_name
   from x$bh a, dba_extents b
   where b.file_id=a.dbarfil
     and a.dbablk between b.block_id
     and b.block_id+blocks-1
     and segment_type='INDEX'
     and b.owner = upper('&amp;OWNER')
</pre>
<p>Eğer db file sequential read olayı oturumun yanıt süresinin önemli bölümünü ortaya koyarsa, bunun hepsi uygulamanın pekçok indeks okuması yaptığını söyler ve bu da uygulama geliştirme sorununa işaret eder. Bu durumda indeksler üzerinden verilere erişen SQL komutlarının çalışma(execution) planlarını denetlemek gerekir. Bu durumda aşağıdaki sorulara cevap aramak gerekecektir.</p>
<p>SQL komutlarının verilere erişmek için indeks aramaları yapması uygunmudur?<br />
Kullanılan uygulama OLTP mi, yoksa DSS mi?<br />
FTS(Full Table Scan) yapmak daha verimli olurmuydu?<br />
Komutlar doğru sürücü(driving) tablo kullanıyormu?<br />
İndekslerde fragmantasyon varmı?<br />
Doğru indeksler kullanılıyormu?<br />
Tabii bu sorular daha uzar da gider… Bu noktada optimizasyon hedefi, mantıksal ve fiziksel I/O sayısını azaltmak olacaktır. Eğer çalışan uygulamanın koduna erişirseniz, uygulama mantığı incelenebilir.Bu noktada, tüm mantığa bakmak ve ne yapmaya çalıştığını anlamak en iyi yol olacaktır. Bu durumda daha iyi bir yaklaşım tavsiyesi noktasına gelinecektir.</p>
<p>İndeks okuma performansı, yavaş I/O alt sistemleri kullanımı ve/veya zayıf veritabanı dosya yapılandırması gibi daha yüksek ortalama bekleme süreleri ile sonuçlanan pekçok kriterden etkilenir. Buna rağmen, I/O iyileştirmesi pek çok DBA’in yaptığı gibi uygulama ve SQL iyileştirmesinden daha öncelikli duruma getirilmemelidir. I/O iyileştirmesi, SQL komutları optimize edilmeden ve fiziksel I/O talebinin hala yüksek seviyelerde devam etmesi durumunda bu sorunu çözmeyecektir. Genellikle, uygulama geliştiriciler SQL ve uygulama iyileştirmesi yapmak yerine işin kolayına kaçarak “karar vericileri” daha gelişmiş ve güçlü donanımlar satın almaya teşvik ederler. Bu durumda, uygulama geliştiricilere dişlerimizi göstermemiz gerekir(aynı olay geçen Aralık ayında benimde başıma gelmişti. Aşırı I/O okuma sorunu yaşanan bir veritabanında, uygulamayı geliştiren firmanın danışmanları “application tuning” yerine, daha kuvvetli depolama birimine geçmemiz gerektiği tavsiye etmişler, hatta CIO’yu ikna etmişler ancak son anda CIO’ya hazırladığım yaklaşık 20 sayfalık bir darboğaz raporu sonucunda geri adım atıp “application tuning” noktasında ikna olmuşlardı.) Eğer kullanılan uygulama üçüncü parti bir uygulama ise, yüksek beklemeye sebebiyet veren noktalarda yeni indeksler ekleyebilir, doğru sürücü tablo kullanımını optimize edebilir, mevcut anahtarları daha uygun anahtarlarla değiştirmeyi deneyebilir, tek tek SQL ad-hoc sorguları kullanmak yerine PL/SQL paketleri içine gömülü SQL ad-hoc sorguları kullanabilirsiniz.  </p>
<p>SQL iyileştirmesine ilave olarak, eğer çalışma planı “table access by index rowid” olayını çağırıyorsa bu durumda indeks kümeleme faktörünü(indeks clustering factor) kontrol etmekte zaman harcamaya değer bir çalışma olacaktır. Bir indeksin kümeleme faktörü, tablo içinde satırların nasıl sıralandığını belirtir ve bütün bir işlem için gereken I/O sayısını etkiler. Eğer indeksin DBA_INDEXES.CLUSTERING_FACTOR değeri tablo içindeki &#8220;toplam blok&#8221; sayısına yaklaşırsa, bu durumda tablo içindeki pek çok satır sıralanmış olacaktır. Ancak, eğer kümeleme faktörü tablo içindeki &#8220;toplam satır&#8221; sayısına yaklaşırsa, bu demek olur ki tablo içindeki satırlar rastgele sıralanmıştır. Bu durumda, aynı yaprak bloğu içindeki indeks girişleri için aynı veri bloğu içindeki satırları göstermek olası olmaz, böylece işlemi tamamlamak için daha fazla I/O’ya ihtiyaç duyulur.İndeksin kümeleme faktörü, önce tablonun yeniden inşası(veya &#8220;alter table &#8230; shrink space compact&#8221; komutu ile tablonun sıkıştırılması), ve sonrasında kümeleme faktörü yüksek olan indeksin yeniden inşa edilmesi ile geliştirilebilir, böylece satırlar tekrardan indeks anahtarına bağlı olarak sıralanmaya başlar. </p>
<p>Ayrıca aşağıdaki  sorguyu kullanarak, uygulamaya kısa zamanda yeni bir indeks işleme girişi olup olmadığı kontrol edilmelidir. Veritabanında yeni bir indeksin işleme girmesi optimizer’ın tabloya erişen SQL komutunda farklı bir çalışma planı seçmesine sabebiyet verebilir.</p>
<pre class="brush: sql; title: ;">
select owner,
       substr(object_name,1,30) object_name,
       object_type,
       created
from   dba_objects
where  object_type in ('INDEX','INDEX PARTITION')
order by created;
</pre>
<p>OPTIMIZER_INDEX_COST_ADJ ve OPTIMIZER_INDEX_CACHING başlangıç parametreleri, optimizerın “nested loop- içiçe döngü” işlemlerini kayırmasına yardım edebilir ve FTS üzerinden indeks erişim yolunu seçebilir.</p>
<p>OPTIMIZER_INDEX_COST_ADJ parametresinin varsayılan değeri 100’dür. Daha düşük bir değer optimizer’ın  indeks erişim yollarının daha ucuz olduğunu düşünmesine iter. Maliyet(cost) formulünde bu başlangıç parametresinin etkisini anlamak için nasıl çalıştığına bir bakalım.</p>
<p>İndeksin kök bloğuna erişir.<br />
İlk anahtarları içeren yaprak bloklara yönelmek için branch bloklar üzerinden gidilir.<br />
Her bir anahtarın arama kriterini karşılaması için, veri bloğunu referans eden rowid’ler ekstrakt edilir, ardından rowid’ce referans edilen veri bloklarına erişilir.<br />
OPTIMIZER_INDEX_CACHING parametresi için varsayılan değer ise 0’dır. Daha yüksek bir değer, optimizer’a yüksek oranda indeks bloklarının halihazırda önbellek tamponda bulunduğunun ve “nested loop” işlemlerinin daha ucuz olduğu bilgisini verir. Bazı üçüncü parti uygulamaları bu metodu indeks kullanımını desteklemek için kullanır. Bu parametrelerin uygun olmayan şekilde kullanımı anlamlı I/O bekleme olayına sebebiyet verebilir.  Bu sebeple oturumların hangi değerler ile çalıştığını bulmak önemlidir.  Oracle 9i sürümünde bu bilgi, oturumların ancak birinci seviyede “trace 10053”  ile izlenmesiyle elde edilebilmekteydi, ancak Oracle 10g itibariyle V$SES_OPTIMIZER_ENV görünümünden kolayca elde edilebilir, ayrıca AWR raporlaroıda faydalıdır.</p>
<p>Tüm obje istatistikleri mevcut veriyi temsil ederken, hatalı istatistiklerin ise optimizer’ın o an kullanımda olmayan indeks okumalarını çağırarak zayıf çalışma planı oluşturmasına sebep olacağını bilmemiz gerekir. Tablolar veya indeksler düşük ESTIMATE değeri ile analiz edilirken, Oracle genellikle tek-blok okuması yapar ve bunu db file sequential read istatistiğine ilave eder (oturum için V$SESSION_EVENT görünümüne, instance için V$SYSTEM_EVENT görünümü içine kaydeder).</p>
<p>Tablolara dayalı sıralı okumalar<br />
P1 ve P2 parametrelerinin indeks yerine bir tabloyu çözmeye çalıştığı durumda, db file sequential read bekleme olayı görülebilir.Bu olay, indekslerden elde edilen rowid’lerle tablolara erişen SQL komutlarında gayet normaldir. Aşağıda bu olay ile ilgili bir çalışma planı yer almaktadır. Oracle, rowid’lerle bir tablo okurken tek-blok I/O işlemi kullanır.</p>
<pre class="brush: sql; title: ;">
LVL   OPERATION                           OBJECT
---- -----------------------------       ---------------------
  1   SELECT STATEMENT
  2         TABLE ACCESS BY INDEX ROWID   SRC_TBSN_NTP
  3                  INDEX RANGE SCAN     SRC_TBSN_SNP_1IX
</pre>
<p>Bunun yanında kayıp zamanların bulunmasında ve bir olay için ortalama bekleme süresi bulunmasında  V$EVENT_HISTOGRAM görünümüde oldukça faydalı bilgiler vermektedir. Pek çok datanın tek bir numara içine tıkılması durumunda kritik bilgiler noktasında resmin genel bütünü gözönüne serilemeyebilir. İşte $EVENT_HISTOGRAM belirli zaman aralığında toplanan bekleme olaylarının devamlılığını gözler önüne serer, aşağıda Jonathan Lewis’in yazısından bir anektot yer almaktadır. Bu görünümden elde edilen bilgi, bekleme olayının adrese yazmaya ihtiyaç duyulan devamlı bir problem mi, yoksa tekil bir olaymı olduğunu belirlemeye yardımcı olur.</p>
<pre class="brush: sql; title: ;">
select
        *
from    v$event_histogram
where  event = 'db file sequential read'
order by
        wait_time_milli
;
EVENT#     EVENT                     WAIT_TIME_MILLI WAIT_COUNT
---------- ------------------------- --------------- ----------
       115 db file sequential read                 1     230721
       115 db file sequential read                 2     161702
       115 db file sequential read                 4    4254007
       115 db file sequential read                 8   14293447
       115 db file sequential read                16    4148671
       115 db file sequential read                32    1683639
       115 db file sequential read                64     571850
       115 db file sequential read               128      40053
       115 db file sequential read               256       1114
       115 db file sequential read               512         70
       115 db file sequential read              1024         23
       115 db file sequential read              2048         20
</pre>
<p>Sonuçtan da görüldüğü üzere WAIT_TIME_MILI değeri katlanarak artmaktadır. 230,721 okuma 1 milisaniye altında olmasına rağmen, 161,702 okuma 1 ile 2 milisaniye arasında sürmektedir. Burada ilginç olan en son satırdaki 20 okumanın yaklaşık 2 saniye sürmesidir. Bunun muhtemel sebebi, verimsiz SQL komutlarının çok hızlı şekilde blokları yeniden kullanıma sokarak herkes için  Oracle önbelleğini bozması ama ikincil tampondan bu blokları yeterince hızlı şekilde kurtarmak için blokları tekrar ziyaret etmeyi yönetmesidir. Aynı şekilde V$SYSTEM_EVENT çalıştırılsaydı ortalama 16 milisaniye bekleme süresi görülecekti, ancak yukardaki histogramda okumaların büyük bir kesmi 16 milisaniyeden daha fazladır,hatta 2 saniyelik beklemede okumalarda azda olsa vardır(son 2 satır).</p>
<p>Sistem tabanlı teşhisler<br />
V$SYSTEM_EVENT görünümü, sistem seviyesinde teşhis verilerini sağlar. I/O ilişkili olaylar için dikkat edilmesi gereken AVERAGE_WAIT ve  TIME_WAITED kolonlarıdır.</p>
<p>Instance başlangıcı ile birlikte TIME_WAITED değerini değerlendirmeye almak gerekir. Eski bir instance’ın daha yüksek db file sequential read bekleme zamanı göstermesi normaldir. Ayrıca, aşağıdaki örnekte görüldüğü gibi doğru bir TIME_WAITED bilgisi almak için  her zaman V$SYSTEM_EVENT görünümünün kullanılması gerekmektedir. Bu bize db file sequential read beklemesinin sistem içindeki diğer anlamlı bekleme olayları ile kıyaslama yapma imkanı verir. Eğer db file sequential read bekleme zamanı top 5 kategorisi içinde değilse, o zaman bu bekleme olayını pek dikkate almak gerekmez. db file sequential read bekleme olayı top 5 bekleme listesinde yer alsa bile, bu bize veritabanının pek çok tek-blok I/O çağrısı gördüğünü söyler. Daha öncedende bahsettiğim gibi bu durum kısa süreli çalışan OLTP uygulamasından veya uzun süre çalışan batch proseslerden veya her ikisinden kaynaklanır. Sistem seviyesinde kimin I/O çağrısı yaptığı, ne zaman bu çağrıların yapıldığı, hangi objelere erişildiği ve hangi SQL komutlarının bu çağrılar ile ilişkili olduğu gibi soruların cevapları net olarak bulunamaz.  Kısacası, instance seviyesinde teşhis kapasitesi oldukça sınırlıdır.</p>
<pre class="brush: sql; title: ;">
select a.event,
       a.total_waits,
       a.time_waited,
       a.time_waited/a.total_waits average_wait,
       sysdate – b.startup_time days_old
from   v$system_event a, v$instance b
order by a.time_waited;
</pre>
<p>AVERAGE_WAIT kolonu oldukça faydalıdır. Ortalama tek-blok okuma bekleme zamanı tahammül sınırlanızı aşıyorsa, I/O altsistemine ve disk üzerinde sıcak noktaların olup olmadığını kontrol etmek gerekir. Eğer veritabanı dosya sistemleri üzerine inşa edilmişse, veritabanı mount dosyalarının sadece Oracle dosyalarını içerdiğinden emin olmak gerekir. Veritabanı mount dosyalarını başka uygulamalar ile paylaşmayın ve mümkünse ilgili tüm I/O cihazlarını başka uygulamalarla paylaşmayın. Linux sistemlerde /etc/vfstab dizinine bakarak nelerin mount edildiğini kontrol edebilirsiniz.</p>
<p>Ayrıca, veri dosyalarının sıcak noktalar oluşmasını önlemek amacıyla farklı fiziksel disklere düzgünce serpiştirildiğinden emin olun. I/O aktivitesini iostat ve sar komutları ile izlemek gerekir.Disk kuyruk uzunluğu, disk hizmet süresi ve I/O çıktısına dikkat etmek gerekir. Eğer bir fiziksel cihaz oldukça meşgulsa, bu durumda bu cihaz üzerindeki bazı veri dosyalarını başka disklere serpiştirmek gerekir. Aşağıdaki sorgu sonucunda fiziksel dosyalardan yapılan fiziksel okuma ve fiziksel yazma sonuçları gelmektedir. Bunun sonucunda hangi veri dosyasının yeniden serpiştirilmeye ihtiyacı var teşhis edilebilir.</p>
<pre class="brush: sql; title: ;">
select d.name,s.PHYRDS,s.PHYWRTS
from v$datafile d, v$filestat s
where d.file#=s.file#
order by 1;
</pre>
<p>Benim geçen yılın sonunda yaşağıdım aşırı I/O bekleme süresi sorununda aldığım rapor sonucu aşağıdadır.</p>
<pre class="brush: sql; title: ;">
NAME                                PHYRDS      PHYWRTS
--------------------------------    --------    --------

/u02/oradata/XTLLIVE/system01.dbf   42873922    1527643
/u08/oradata/XTLLIVE/tmvxsd02.dbf   430128921   4995429
/u03/oradata/XTLLIVE/perfstat01.dbf 6320646     1311381
/u03/oradata/XTLLIVE/undotbs01.dbf  2025353     72899148
/u09/oradata/XTLLIVE/tmvxarch01.dbf 40357       28876
/u04/oradata/XTLLIVE/tmvxld01.dbs   40402       28876
/u04/oradata/XTLLIVE/tmvxmi01.dbf   44549       29263
/u06/oradata/XTLLIVE/tmvxrunt01.dbf 1719652399  22578180
/u07/oradata/XTLLIVE/tmvxsi01.dbf   328681641   31554730
/u04/oradata/XTLLIVE/tmvxsi02.dbf   211186362   25967626
/u11/oradata/XTLLIVE/tmvxsi03.dbf   112669265   15674990
/u04/oradata/XTLLIVE/tmvxsi04.dbf   1935556     1130918
/u04/oradata/XTLLIVE/tmvxti01.dbf   121885      44619
/u05/oradata/XTLLIVE/drsys01.dbf    40407       28876
/u05/oradata/XTLLIVE/example01.dbf  40390       28876
/u05/oradata/XTLLIVE/tmvxli01.dbf   40386       28876
/u05/oradata/XTLLIVE/tmvxmd01.dbf   42838       29639
/u10/oradata/XTLLIVE/tmvxsd01.dbf   1917529473  20655289
/u05/oradata/XTLLIVE/tmvxtd01.dbf   43467       28876
/u05/oradata/XTLLIVE/tools01.dbf    40398       28876
/u08/oradata/XTLLIVE/users01.dbf    98295940    44697434
</pre>
<p>Yukardaki senaryoda yaptığımız I/O iyileştirmesi; sorunlu 2 veri dosyasının (tmvxrunt01.dbf ve tmvxsd01.dbf) ait olduğu tablespaceler’e ilave ikişer adet veri dosyasının yeni ayrı fiziksel disklerde oluşturulması(/u12, /u13,/u14 ve /u15 diskleri) ve bu mevcut iki veri dosyası içinde bulunan aşırı fiziksel okuma yapılan ilgili tablolaların, bu yeni oluşturulan veri dosyaları üzerinde eşit yükte yeniden inşası neticesinde I/O işlemleri istenen seviyeye geldi. Tabii, bu arada indeks kümeleme faktörünün yeniden optimal seviyelere gelmesi için &#8211; yanılmıyorsam 5 tabloyu- ilgili indeksleri ile yeniden inşa etmiştik(tmvxsd02.dbf veri dosyası içinde yer alan). Tabii fiziksel depolama alt sisteminde de bazı mount noktaları için ek kontroller devreye sokulmuştu(/u6 ve /10 diskleri için)</p>
<p>Solaris sistemlerde, kontroller ve cihaz I/O istatistik bilgileri   iostat –dxnC komutu ile elde edilebilir. Ancak, sıcak noktaların iyileştirilmesini söylemek uygulamaktan daha zor olmaktadır. Bu iyileştirme için uygulamanın I/O yu nasıl kullandığını bilmek gerekir. Dahada ötesinde, eğer uygulama daha gelişmemişse ve devamlı yeni fonsiyonellikler ekleniyorsa sıcak noktalar hedef harekat noktası olabilir. Genelde DBA’ler uygulamadaki yeni geliştirmelerden haberdar edilmediğinden, reaktif olarak devamlı bir keşif içinde olmalıdır. İşte bu sebeple I/O dengelemesi hiç bitmeyen bir hikaye olur. Oracle 10g itibariyle ASM,  I/O dengelemesinde alternatif bir yardımcı olmaktadır.  </p>
<p>Sistem çapında db file sequential read ortalama bekleme olayına ilave olarak V$SYSTEM_EVENT görünümü ile bmünden her bir veri dosyası için tek-blok okuma istatistiklerini sağlar. Dosya seviyesinde tek-blok ortalama bekleme süresi SINGLEBLKRDTIM değerinin SINGLEBLKRDS değeri ile bölünmesiyle hesaplanabilir. Böylece hangi dosyaların kabul edilemez ortalama bekleme süresine sahip olduğu kolayca keşfedilebilir ve mount noktaları veya cihazları araştırmaya başlayıp veritabanı için exclusive olduğundan emin olunabilir.</p>
<pre class="brush: sql; title: ;">
select a.file#,
       b.file_name,
       a.singleblkrds,
       a.singleblkrdtim,
       a.singleblkrdtim/a.singleblkrds average_wait
from   v$filestat a, dba_data_files b
where  a.file# = b.file_id
and    a.singleblkrds &gt; 0
order by average_wait;

FILE#  FILE_NAME                           SINGLEBLKRDS  SINGLEBLKRDTIM AVERAGE_WAIT
-----  ----------------------------------- ------------  -------------- ------------

17     /u06/oradata/XTLLIVE/tmvxrunt01.dbf   1704565376    30274581   0,0808258929944448
2      /u03/oradata/XTLLIVE/undotbs01.dbf    1995969       298792     0,149697715746086
10     /u10/oradata/XTLLIVE/tmvxsd01.dbf     1233644990    194123462  0,157357638197031
20     /u08/oradata/XTLLIVE/tmvxsd02.dbf     297022693     47960426   0,161470578276657
15     /u04/oradata/XTLLIVE/tmvxti01.dbf     92943         20714      0,222867779176485
1      /u02/oradata/XTLLIVE/system01.dbf     28582149      6759115    0,236480294046469
6      /u08/oradata/XTLLIVE/users01.dbf      74297964      19660265   0,264613778649439
14     /u07/oradata/XTLLIVE/tmvxsi01.dbf     314775010     118162427  0,375386937482744
12     /u05/oradata/XTLLIVE/tmvxli01.dbf     11502         4686       0,407407407407407
13     /u04/oradata/XTLLIVE/tmvxmi01.dbf     15654         6414       0,409735530854734
11     /u05/oradata/XTLLIVE/tmvxtd01.dbf     14577         6130       0,420525485353639
18     /u04/oradata/XTLLIVE/tmvxsi02.dbf     203732487     88190747   0,432875229172459
19     /u11/oradata/XTLLIVE/tmvxsi03.dbf     108599871     47420985   0,436657839123953
5      /u03/oradata/XTLLIVE/perfstat01.dbf   6147231       2793057    0,45436018265785
21     /u04/oradata/XTLLIVE/tmvxsi04.dbf     1898848       864557     0,455306059252768
3      /u05/oradata/XTLLIVE/drsys01.dbf      11523         5474       0,475049900199601
9      /u05/oradata/XTLLIVE/tmvxmd01.dbf     13550         7047       0,520073800738007
4      /u05/oradata/XTLLIVE/example01.dbf    11505         5994       0,520990873533246
7      /u05/oradata/XTLLIVE/tools01.dbf      11513         6080       0,528098671067489
16     /u09/oradata/XTLLIVE/tmvxarch01.dbf   11472         6324       0,551255230125523
8      /u04/oradata/XTLLIVE/tmvxld01.dbs     11518         6599       0,572929328008335
</pre>
<p><span style="color: #0000ff;"><strong>Uğur İnal </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/06/%e2%80%9cdb-file-sequential-read%e2%80%9d-bekleme-olayi-uzerine-detayli-bir-inceleme.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>11gR2&#8242;de Adım Adım Physical Standby Database Yaratılması</title>
		<link>http://turkceoracle.com/2011/05/step-by-step-creating-a-physical-standby-database-on-11gr2.html</link>
		<comments>http://turkceoracle.com/2011/05/step-by-step-creating-a-physical-standby-database-on-11gr2.html#comments</comments>
		<pubDate>Wed, 04 May 2011 19:05:11 +0000</pubDate>
		<dc:creator>turkceoracle</dc:creator>
				<category><![CDATA[oracle]]></category>
		<category><![CDATA[kamil türkyılmaz]]></category>
		<category><![CDATA[oracle dataguard]]></category>

		<guid isPermaLink="false">http://turkceoracle.com/?p=396</guid>
		<description><![CDATA[10gR2 için dataguard kurulumundan bahsetmiştik, şimdi aynı işlemleri 11gR2 için yapıp bir sonraki adımda da dgmgrl ile switcover failover işlemlerinden bahsetmeyi planlıyorum.  İlk yazımda bahsetmiş olduğum bazı tanım ve ön gereksinimler kısmına artık burada değinmiyorum.  10gR2 için dataguard kurulumundan bahsederken manuel kurulum yapmıştık. Dbf’ leri biz taşımıştık, initfile’ deki parametreleri biz edit ederek üzerinde değişiklikler [...]]]></description>
			<content:encoded><![CDATA[<p>10gR2 için dataguard kurulumundan bahsetmiştik, şimdi aynı işlemleri  11gR2 için yapıp bir sonraki adımda da dgmgrl ile switcover failover  işlemlerinden bahsetmeyi planlıyorum.  İlk yazımda bahsetmiş olduğum  bazı tanım ve ön gereksinimler kısmına artık burada değinmiyorum.  10gR2  için dataguard kurulumundan bahsederken manuel kurulum yapmıştık. Dbf’  leri biz taşımıştık, initfile’ deki parametreleri biz edit ederek  üzerinde değişiklikler yapmıştık. 11gR2 için dataguard kurulumunda bu  adımların hiçbirini yapmayacağız. Rman’ i kullanarak tüm işi oracle’ a  bırakarak nasıl yapacağımız üzerinde konuşacağız.</p>
<p>Kurulumuna başlamadan önce elimizdekilere bir bakalım.  2 tane  işletim sistemi linux 5.5 olan sunucumuz, sunucuların birinde oracle  11gR2 database kurulu diğerinde ise sadece software kurulu durumda.  Primary sunucumuzun SID=dg1, dataguard olacak olan database’ imizin  SID’si dg2.</p>
<p>Bu özet bilgilerden sonra physical standby database’ imizi create etmeye başlayabiliriz ;</p>
<ul>
<li>Primary database’ imizi force logging moda alıyoruz;</li>
</ul>
<p>Alter database force logging</p>
<ul>
<li>Primary database’ in archive modda olması gerekiyor.</li>
</ul>
<p>Aşağıdaki script ile kontrol edebilirsiniz. Sonuç NOARCHIVELOG  dönerse aşağıdaki adımları takip ederek archive moda alabilirsiniz.</p>
<pre class="brush: sql; title: ;">
select log_mode from v$database  ;

SHUTDOWN IMMEDIATE;
STARTUP MOUNT;

ALTER DATABASE ARCHIVELOG;
ALTER DATABASE OPEN;
</pre>
<p>–  archive ile ilgili iki önemli parametreyi set ediyoruz.</p>
<pre class="brush: plain; title: ;">
ALTER SYSTEM SET log_archive_format=’arch_%t_%s_%r_.arc’ SCOPE=spfile
ALTER SYSTEM SET log_archive_dest_1=’location=D:\arch’ SCOPE=spfile
</pre>
<ul>
<li>Primary database’ inde yok ise bir password file create edilir;</li>
</ul>
<p>orapwd file=PWDist.ora password=oracle entries=5 force=Y</p>
<ul>
<li>Primary Database’ ine Standby Redo logların create ve configure edilmesi ;</li>
</ul>
<p>Burada önerilen, primary database’ deki redo logların size’ ı ile  standby için create edilecek redo log’ ların size’ larının aynı  olmasıdır.  Kaç tane oluşturulacağını şu şekilde hesaplayabiliriz ;</p>
<p>Create Edilecek Standby Redo Log Sayısı = (maximum number of logfiles for each thread + 1) * maximum number of threads</p>
<p>Bir örnekle açıklayalım ;</p>
<p>Primary database’ indeki redo loglarımız,</p>
<pre class="brush: sql; title: ;">
SQL&amp;gt; select group#,THREAD#,BYTES,status from v$log;

GROUP#    THREAD#      BYTES STATUS
———- ———- ———- —————-
1          1   52428800 INACTIVE
2          1   52428800 INACTIVE
3          1   52428800 CURRENT
</pre>
<p>thread başına düşen log sayısı = 3<br />
maximum number of thread = 1<br />
Dolayısıyla create edilecek log sayısı = (3+1)*1 = 4</p>
<p>Bu örnek benim primary database’ im deki ile aynı dolayısıyla bende 4 tane standby redo logları create ediyorum.</p>
<pre class="brush: plain; title: ;">
ALTER DATABASE ADD STANDBY LOGFILE GROUP 4 (‘c:\oracle10g\standby_redo\standby_redo04.log’) SIZE 50M
Database altered

ALTER DATABASE ADD STANDBY LOGFILE GROUP 5 (‘c:\oracle10g\standby_redo\standby_redo05.log’) SIZE 50M
Database altered

ALTER DATABASE ADD STANDBY LOGFILE GROUP 6 (‘c:\oracle10g\standby_redo\standby_redo06.log’) SIZE 50M
Database altered

ALTER DATABASE ADD STANDBY LOGFILE GROUP 7 (‘c:\oracle10g\standby_redo\standby_redo07.log’) SIZE 50M
Database altered
</pre>
<p>Buradaki Group noları önemli, sıra ile devam etmesi gerekiyor, aralarda atlamalar olmayacak şekilde create ediyoruz.</p>
<p>Primary database’ ine standby redolog ları neden oluşturuyoruz  sorusuna, dataguard kurulumunda aslında buna gerek yok ama kurulumdan  sonra herhangi bir zamanda</p>
<p>gereklidir.</p>
<p>Standby redologlar create edildikden sonra aşağıdaki sorgu ile kontrol edebiliriz ;</p>
<pre class="brush: sql; title: ;">
SELECT GROUP#,THREAD#,SEQUENCE#,ARCHIVED,STATUS FROM V$STANDBY_LOG

GROUP#    THREAD#        SEQUENCE#    ARCHIVED       STATUS
——          ——-               ———                        ——–              ———-
4           0                      0                      YES                  UNASSIGNED
5           0                      0                      YES                  UNASSIGNED
6           0                      0                      YES                  UNASSIGNED
7           0                      0                      YES                  UNASSIGNED

4 rows selected
</pre>
<ul>
<li>Primary database’ in initial parametrelerinin düzenlenmesi  ;</li>
</ul>
<p>Redo logların transferi için primary database üzerinde bazı initial  parametrelerinin düzenlenmesi gerekmektedir. Bunun yanısıra yine olası  bir switchover durumunda hata alınmaması için (standby gibi  davranabilmesi için)  bazı eklemelerinde yapılması faydalı olacaktır.</p>
<p>Bilmemiz gerekenler şunlar;</p>
<p>Primary database’ imin                           db_unique_name = dg1</p>
<p>Net_service_name = dg1</p>
<p>Standby database’ imin               db_unique_name = dg2</p>
<p>Net_service_name = dg2</p>
<p>Pfile’ de yapılacak olan değişiklerin bir kısmı zaten şu anki pfile’  inizde olan parametreler, kontrol etmeniz yeterli olacaktır.</p>
<p>DB_NAME, CONTROL_FILES, REMOTE_LOGIN_PASSWORDFILE  (exclusive olması  gerekiyor), LOG_ARCHIVE_FORMAT (db archive modda olduğunda bu  parametrede pfile’ inizde olacaktır.)</p>
<p>Aşağıdaki parametreleri ekliyoruz.</p>
<pre class="brush: plain; title: ;">
*.control_files=’/data/oracle/oradata/dg1/control01.ctl’,'/data/oracle/flash_recovery_area/dg1/control02.ctl’

*.db_name=’dg1′

*.DB_UNIQUE_NAME=dg1

*.log_archive_dest_1=’location=/data/oracle/arch’

*.log_archive_dest_state_1=’ENABLE’

*.log_archive_dest_state_2=’ENABLE’

*.log_archive_format=’arch_%t_%s_%r_.arc’

*.remote_login_passwordfile=’EXCLUSIVE’

*.LOG_ARCHIVE_CONFIG=’DG_CONFIG=(dg1,dg2)’

*.LOG_ARCHIVE_DEST_1=’LOCATION=/data/oracle/arch/ VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=dg1′

*.LOG_ARCHIVE_DEST_2=’SERVICE=dg2 ASYNC VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=dg2′

*.LOG_ARCHIVE_DEST_STATE_1=ENABLE

*.LOG_ARCHIVE_DEST_STATE_2=ENABLE

*.LOG_ARCHIVE_MAX_PROCESSES=30

*.FAL_SERVER=dg2

*.DB_FILE_NAME_CONVERT=’dg2′,’dg1′

*.LOG_FILE_NAME_CONVERT=’/data/oracle/arch_dis/’,'/data/oracle/arch’,'/data/oracle/arch_dis/’,'/data/oracle/arch’

*.STANDBY_FILE_MANAGEMENT=AUTO STANDBY_FILE_MANAGEMENT=AUTO
</pre>
<p>Log_archive_process’ si 30 olarak set ettim ben, oracle’ ın standby  için önermiş olduğu process sayısı 30’ dır. Daha azda yapabilirsiniz.</p>
<ul>
<li>Hem primary sunucuda hemde standby tarafındaki listener ve  tnsnames.ora dosyalarında aşağıdaki eklemeleri yapıp, listener servisini  stop – start ediyoruz.</li>
</ul>
<p>Tnsnames.ora doyasında her iki instance’ a ait bilgiler yer alacak şekilde düzenliyoruz.</p>
<pre class="brush: plain; title: ;">
DG2 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 10.1.3.145)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = dg2)
)
)

DG1 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 10.1.3.144)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = dg1)
)
)
</pre>
<p>Listener.ora dosyasınıda aşağıdaki satırları ekliyoruz.</p>
<pre class="brush: plain; title: ;">
SID_LIST_LISTENER =
(SID_LIST =
  (SID_DESC =
    (SID_NAME = dg1)
    (GLOBAL_DBNAME = dg1)
(ORACLE_HOME = /data/oracle/11.2.0/dbhome_1)
)

(SID_DESC =
  (SID_NAME = dg2)
  (GLOBAL_DBNAME = dg2)
(ORACLE_HOME = /data/oracle/11.2.0/dbhome_1)
)
)
</pre>
<ul>
<li>Standby tarafına profile dosyası üzerinde oracle_home, sid gibi  değişiklikleri yaptıkdan sonra, orapwd dosyasını primary db’ olduğu  sunucudan buraya kopyalıyoruz. Burada orapwdg1 ve orapwdg2 olacak  şekilde iki tane passord file oluşturuyoruz. (orapwdg1 dosyası,  switchover durumunda problem olmaması için)</li>
</ul>
<ul>
<li>Standby sunucuda $ORACLE_HOME/dbs klasörü altına manuel olarak (vi  editörü ile) initdg2.ora dosyası create edip içerisine sadece  DB_NAME=DG2 parametresini ekleyip kaydediyoruz.</li>
</ul>
<ul>
<li>Standby tarafında $ORACLE_BASE altına /admin/SID/admin klasörünü create ediyoruz.</li>
</ul>
<p>(rman komutunu çalıştırdığınızda eksik create edilmiş olan bir  lokasyon var ise hata verecektir, böyle bir durumda standbydaki oradata  lokasyonu silip primary tarafında rman’ e tekrar connect olup komutu  tekrar başlatabilirsiniz.)</p>
<ul>
<li>Yine standby tarafında $ORACLE_BASE altına /oradata/SID klasörünü create ediyoruz.</li>
</ul>
<ul>
<li>Standby database’ ini nomount moda alıyoruz.</li>
</ul>
<pre class="brush: sql; title: ;">
[oracle@betadataguard2 admin]$ sqlplus “/as sysdba”

SQL*Plus: Release 11.2.0.1.0 Production on Sun Apr 17 00:26:05 2011
Copyright (c) 1982, 2009, Oracle.  All rights reserved.

Connected to:

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 – 64bit Production

SQL&amp;gt; startup nomount pfile=$ORACLE_HOME/dbs/initdg2.ora;

ORACLE instance started.

Total System Global Area  217157632 bytes

Fixed Size                  2211928 bytes
Variable Size             159387560 bytes
Database Buffers           50331648 bytes
Redo Buffers                5226496 bytes

SQL&amp;gt;
</pre>
<ul>
<li>Primary sunucusu üzerinden Rman’ e connect olup komutumuzu çalıştırıyoruz.</li>
</ul>
<pre class="brush: plain; title: ;">
[oracle@betadataguard1 standby_kurulum]$ rman

Recovery Manager: Release 11.2.0.1.0 – Production on Sat Apr 16 19:45:51 2011
Copyright (c) 1982, 2009, Oracle and/or its affiliates.  All rights reserved.

RMAN&amp;gt; connect target sys

target database Password:

connected to target database: DG1 (DBID=1729884635)

RMAN&amp;gt; connect auxiliary sys@dg2

auxiliary database Password:

connected to auxiliary database: DG2 (not mounted)
</pre>
<p>Çalıştıracağımız komutumuz ;</p>
<pre class="brush: plain; title: ;">
run {
allocate channel prmy1 type disk;
allocate channel prmy2 type disk;
allocate channel prmy3 type disk;
allocate channel prmy4 type disk;
allocate auxiliary channel stby type disk;

duplicate target database for standby from active database

spfile

parameter_value_convert ‘dg1′,’dg2′

set db_unique_name=’dg2′
set db_file_name_convert=’/dg1/’,'/dg2/’
set log_file_name_convert=’/dg1/’,'/dg2/’
set control_files=’/data/oracle/oradata/dg2/dg2.ctl’
set log_archive_max_processes=’5′
set fal_client=’dg2′
set fal_server=’dg1′
set standby_file_management=’AUTO’
set log_archive_config=’dg_config=(dg1,dg2)’
set log_archive_dest_2=’service=dg1 ASYNC valid_for=(ONLINE_LOGFILE,PRIMARY_ROLE) db_unique_name=dg1′
;
}
</pre>
<p>Scriptin outputu ;</p>
<pre class="brush: plain; title: ;">
RMAN&amp;gt; run {

2&amp;gt;      allocate channel prmy1 type disk;

3&amp;gt;      allocate channel prmy2 type disk;

4&amp;gt;      allocate channel prmy3 type disk;

5&amp;gt;      allocate channel prmy4 type disk;

6&amp;gt;      allocate auxiliary channel stby type disk;

7&amp;gt;      duplicate target database for standby from active database

8&amp;gt;      spfile

9&amp;gt;              parameter_value_convert ‘dg1′,’dg2′

10&amp;gt;             set db_unique_name=’dg2′

11&amp;gt;             set db_file_name_convert=’/dg1/’,'/dg2/’

12&amp;gt;             set log_file_name_convert=’/dg1/’,'/dg2/’

13&amp;gt;             set control_files=’/data/oracle/oradata/dg2/dg2.ctl’

14&amp;gt;             set log_archive_max_processes=’5′

15&amp;gt;             set fal_client=’dg2′

16&amp;gt;             set fal_server=’dg1′

17&amp;gt;             set standby_file_management=’AUTO’

18&amp;gt;             set log_archive_config=’dg_config=(dg1,dg2)’

19&amp;gt;             set log_archive_dest_2=’service=dg1 ASYNC valid_for=(ONLINE_LOGFILE,PRIMARY_ROLE) db_unique_name=dg1′

20&amp;gt;      ;

21&amp;gt;      }

using target database control file instead of recovery catalog

allocated channel: prmy1

channel prmy1: SID=34 device type=DISK

allocated channel: prmy2

channel prmy2: SID=1169 device type=DISK

allocated channel: prmy3

channel prmy3: SID=33 device type=DISK

allocated channel: prmy4

channel prmy4: SID=1167 device type=DISK

allocated channel: stby

channel stby: SID=10 device type=DISK

Starting Duplicate Db at 16-APR-11

contents of Memory Script:

{

backup as copy reuse

targetfile  ‘/data/oracle/11.2.0/dbhome_1/dbs/orapwdg1′ auxiliary format

‘/data/oracle/11.2.0/dbhome_1/dbs/orapwdg2′   targetfile

‘/data/oracle/11.2.0/dbhome_1/dbs/spfiledg1.ora’ auxiliary format

‘/data/oracle/11.2.0/dbhome_1/dbs/spfiledg2.ora’   ;

sql clone “alter system set spfile= ”/data/oracle/11.2.0/dbhome_1/dbs/spfiledg2.ora””;

}

executing Memory Script

Starting backup at 16-APR-11

Finished backup at 16-APR-11

sql statement: alter system set spfile= ”/data/oracle/11.2.0/dbhome_1/dbs/spfiledg2.ora”

contents of Memory Script:

{

sql clone “alter system set  audit_file_dest =

”/data/oracle/admin/dg2/adump” comment=

”” scope=spfile”;

sql clone “alter system set  db_unique_name =

”dg2” comment=

”” scope=spfile”;

sql clone “alter system set  db_file_name_convert =

”/dg1/”, ”/dg2/” comment=

”” scope=spfile”;

sql clone “alter system set  log_file_name_convert =

”/dg1/”, ”/dg2/” comment=

”” scope=spfile”;

sql clone “alter system set  control_files =

”/data/oracle/oradata/dg2/dg2.ctl” comment=

”” scope=spfile”;

sql clone “alter system set  log_archive_max_processes =

5 comment=

”” scope=spfile”;

sql clone “alter system set  fal_client =

”dg2” comment=

”” scope=spfile”;

sql clone “alter system set  fal_server =

”dg1” comment=

”” scope=spfile”;

sql clone “alter system set  standby_file_management =

”AUTO” comment=

”” scope=spfile”;

sql clone “alter system set  log_archive_config =

”dg_config=(dg1,dg2)” comment=

”” scope=spfile”;

sql clone “alter system set  log_archive_dest_2 =

”service=dg1 ASYNC valid_for=(ONLINE_LOGFILE,PRIMARY_ROLE) db_unique_name=dg1” comment=

”” scope=spfile”;

shutdown clone immediate;

startup clone nomount;

}

executing Memory Script

sql statement: alter system set  audit_file_dest =  ”/data/oracle/admin/dg2/adump” comment= ”” scope=spfile

sql statement: alter system set  db_unique_name =  ”dg2” comment= ”” scope=spfile

sql statement: alter system set  db_file_name_convert =  ”/dg1/”, ”/dg2/” comment= ”” scope=spfile

sql statement: alter system set  log_file_name_convert =  ”/dg1/”, ”/dg2/” comment= ”” scope=spfile

sql statement: alter system set  control_files =  ”/data/oracle/oradata/dg2/dg2.ctl” comment= ”” scope=spfile

sql statement: alter system set  log_archive_max_processes =  5 comment= ”” scope=spfile

sql statement: alter system set  fal_client =  ”dg2” comment= ”” scope=spfile

sql statement: alter system set  fal_server =  ”dg1” comment= ”” scope=spfile

sql statement: alter system set  standby_file_management =  ”AUTO” comment= ”” scope=spfile

sql statement: alter system set  log_archive_config =  ”dg_config=(dg1,dg2)” comment= ”” scope=spfile

sql statement: alter system set  log_archive_dest_2 =  ”service=dg1  ASYNC valid_for=(ONLINE_LOGFILE,PRIMARY_ROLE) db_unique_name=dg1”  comment= ”” scope=spfile

Oracle instance shut down

connected to auxiliary database (not started)

Oracle instance started

Total System Global Area     471830528 bytes

Fixed Size                     2214456 bytes

Variable Size                268436936 bytes

Database Buffers             192937984 bytes

Redo Buffers                   8241152 bytes

allocated channel: stby

channel stby: SID=9 device type=DISK

contents of Memory Script:

{

backup as copy current controlfile for standby auxiliary format  ‘/data/oracle/oradata/dg2/dg2.ctl’;

}

executing Memory Script

Starting backup at 16-APR-11

channel prmy1: starting datafile copy

copying standby control file

output file name=/data/oracle/11.2.0/dbhome_1/dbs/snapcf_dg1.f tag=TAG20110416T194634 RECID=4 STAMP=748640795

channel prmy1: datafile copy complete, elapsed time: 00:00:01

Finished backup at 16-APR-11

contents of Memory Script:

{

sql clone ‘alter database mount standby database’;

}

executing Memory Script

sql statement: alter database mount standby database

contents of Memory Script:

{

set newname for tempfile  1 to

“/data/oracle/oradata/dg2/temp01.dbf”;

switch clone tempfile all;

set newname for datafile  1 to

“/data/oracle/oradata/dg2/system01.dbf”;

set newname for datafile  2 to

“/data/oracle/oradata/dg2/sysaux01.dbf”;

set newname for datafile  3 to

“/data/oracle/oradata/dg2/undotbs01.dbf”;

set newname for datafile  4 to

“/data/oracle/oradata/dg2/users01.dbf”;

backup as copy reuse

datafile  1 auxiliary format

“/data/oracle/oradata/dg2/system01.dbf”   datafile

2 auxiliary format

“/data/oracle/oradata/dg2/sysaux01.dbf”   datafile

3 auxiliary format

“/data/oracle/oradata/dg2/undotbs01.dbf”   datafile

4 auxiliary format

“/data/oracle/oradata/dg2/users01.dbf”   ;

sql ‘alter system archive log current’;

}

executing Memory Script

executing command: SET NEWNAME

renamed tempfile 1 to /data/oracle/oradata/dg2/temp01.dbf in control file

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME

executing command: SET NEWNAME

Starting backup at 16-APR-11

channel prmy1: starting datafile copy

input datafile file number=00001 name=/data/oracle/oradata/dg1/system01.dbf

channel prmy2: starting datafile copy

input datafile file number=00002 name=/data/oracle/oradata/dg1/sysaux01.dbf

channel prmy3: starting datafile copy

input datafile file number=00003 name=/data/oracle/oradata/dg1/undotbs01.dbf

channel prmy4: starting datafile copy

input datafile file number=00004 name=/data/oracle/oradata/dg1/users01.dbf

output file name=/data/oracle/oradata/dg2/users01.dbf tag=TAG20110416T194641

channel prmy4: datafile copy complete, elapsed time: 00:00:03

output file name=/data/oracle/oradata/dg2/undotbs01.dbf tag=TAG20110416T194641

channel prmy3: datafile copy complete, elapsed time: 00:00:36

output file name=/data/oracle/oradata/dg2/system01.dbf tag=TAG20110416T194641

channel prmy1: datafile copy complete, elapsed time: 00:00:56

output file name=/data/oracle/oradata/dg2/sysaux01.dbf tag=TAG20110416T194641

channel prmy2: datafile copy complete, elapsed time: 00:00:56

Finished backup at 16-APR-11

sql statement: alter system archive log current

contents of Memory Script:

{

switch clone datafile all;

}

executing Memory Script

datafile 1 switched to datafile copy

input datafile copy RECID=4 STAMP=748640857 file name=/data/oracle/oradata/dg2/system01.dbf

datafile 2 switched to datafile copy

input datafile copy RECID=5 STAMP=748640857 file name=/data/oracle/oradata/dg2/sysaux01.dbf

datafile 3 switched to datafile copy

input datafile copy RECID=6 STAMP=748640857 file name=/data/oracle/oradata/dg2/undotbs01.dbf

datafile 4 switched to datafile copy

input datafile copy RECID=7 STAMP=748640857 file name=/data/oracle/oradata/dg2/users01.dbf

Finished Duplicate Db at 16-APR-11

released channel: prmy1

released channel: prmy2

released channel: prmy3

released channel: prmy4

released channel: stby

RMAN&amp;gt;
</pre>
<p>Artık dataguardımız hazır sayılır. Bize kalan sadece apply başlatmak  için komutumuzu çalıştırmak. Standby sunucusu üzerine gidip komutumuzu  başlatalım;</p>
<pre class="brush: sql; title: ;">
SQL&amp;gt; ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;

Database altered.
</pre>
<p>Artık dataguardımız hazır sayılır. Şimdi primary ile karşılaştırıp kontrol edelim.</p>
<p>– Çıkan logları kontrol etmek için;</p>
<pre class="brush: sql; title: ;">
SQL&amp;gt; SELECT SEQUENCE#, FIRST_TIME, NEXT_TIME
2  FROM V$ARCHIVED_LOG
3  ORDER BY SEQUENCE# desc;

SEQUENCE# FIRST_TIM NEXT_TIME
———- ——— ———
98 16-APR-11 16-APR-11
98 16-APR-11 16-APR-11
97 16-APR-11 16-APR-11
97 16-APR-11 16-APR-11
96 16-APR-11 16-APR-11
96 16-APR-11 16-APR-11
95 16-APR-11 16-APR-11
95 16-APR-11 16-APR-11
94 16-APR-11 16-APR-11
94 16-APR-11 16-APR-11
93 16-APR-11 16-APR-11
</pre>
<p>– Standby tarafında çıkan logların durumunu kontrol etmek için;</p>
<pre class="brush: sql; title: ;">
SQL&amp;gt; SELECT SEQUENCE#, FIRST_TIME, NEXT_TIME
        FROM V$ARCHIVED_LOG
        ORDER BY SEQUENCE# desc ;

SEQUENCE# FIRST_TIM NEXT_TIME
———- ——— ———
98 16-APR-11 16-APR-11
97 16-APR-11 16-APR-11
96 16-APR-11 16-APR-11
95 16-APR-11 16-APR-11
94 16-APR-11 16-APR-11
93 16-APR-11 16-APR-11
92 16-APR-11 16-APR-11
91 16-APR-11 16-APR-11
90 16-APR-11 16-APR-11
89 16-APR-11 16-APR-11
88 16-APR-11 16-APR-11
</pre>
<p>– Standbyda hangilerinin apply olduğunu görebilmek içinse;</p>
<pre class="brush: sql; title: ;">
SQL&amp;gt; SELECT SEQUENCE#,APPLIED FROM V$ARCHIVED_LOG ORDER BY SEQUENCE# desc ;

SEQUENCE# APPLIED
———- ———
98 IN-MEMORY
97 YES
96 YES
95 YES
94 YES
93 YES
92 YES
91 YES
90 YES
89 YES
88 YES
</pre>
<p>Çıkan tüm archiveların apply olduğunu görebiliyoruz.  11gR2 için  dataguard kurulumunun adım adım  nasıl yapabileceğimizi ifade etmeye  çalıştım.Umarım  faydalı olmuştur.</p>
<p>﻿<span style="color: #0000ff;"><strong>Kamil Türkyılmaz </strong> tarafından yayınlandı</span></p>
]]></content:encoded>
			<wfw:commentRss>http://turkceoracle.com/2011/05/step-by-step-creating-a-physical-standby-database-on-11gr2.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

