Menu

17 Mart 2013 Pazar

Weblogic JMS uygulamasi

Merhaba, bu yazimda weblogic uzerinde bir Java Message Service (JMS) uygulamasini nasil yapabiliriz, ilk bastan en sona ekran goruntuleri ile birlikte paylasacagim. Bu uygulamayi yaparken 30`un uzerinde ekran goruntusu ortaya :) cikti. Faydali olmasi dilegiyle.

1. Weblogic Admin Console`u actikdan sonra
 Summary of Deployments >Summary of Services: JMS >Summary of JMS Servers altinda

2. DenemJMS adinda bir JMS Server olusturuyoruz.

3. Olusturdugumuz JMS Server`i bir managed server`a atiyoruz. (Clusterada atabilirsiniz)

4. asagidakileri uyguluyoruz.

5. JMS modules ekliyoruz.

6. New diyerek ekliyoruz



7. Managed Server`imizi seciyoruz

8. Finish diyerek bitirelim

9. Herseyin basarili oldugu goruluyor. ve herhangi bir restarta ihtiyac yoktur.

10. dosya ismini ne verdigi gorebiliyoruz.


11. SImdi bir Queue olusturuyoruz.


12. JNDI ismini verip next diyoruz.

13. Subdeployment secerek devam ediyoruz.

14. Ok

15. Finish

16.

17.

18. Simdi ise JMS server`a connection kurabilmek icin ConnectionFactory olusturuyoruz.

19. Asagidaki olusturarak devam ediyoruz.

20. Server`a secerek devam diyoruz.

21. ConnectionFactory ve Queue`muz gorunuyor.

22. Simdi ise Netbeans`de bir EJB module olusturup MDB bean`imiz olusturuyoruz.

23. Next

24. Next

25. Weblogic Server`a secerek devam ediyoruz.

26. Message-Driven Bean`imizi olusturuyoruz.

MDBExample.java
package tr.com.devinim.example;
import javax.ejb.ActivationConfigProperty;import javax.ejb.MessageDriven;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.TextMessage;
/** * * @author easlan */@MessageDriven(mappedName = "jms/myQueue", activationConfig = {    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")})public class MDBExample implements MessageListener {        public MDBExample() {    }        @Override    public void onMessage(Message message) {        try {            TextMessage tm = (TextMessage) message;            System.out.println("Geriye donen mesaj: " + tm.getText());        } catch (JMSException jex) {            System.out.println("Exception: " + jex);        }    }}



27. Simdi ise Olusturdugumuz MDB`mizi cagiracak JSF projemizi olusturuyoruz.

28. Next

29. Weblogic Server`imizi seciyoruz.

30. Java Server Faces Frameworkumuzu secip devam ediyoruz.
MessageYayinlayiciBean.java

package tr.com.devinim.jsf;
/** * * @author easlan */import javax.annotation.Resource;import javax.enterprise.context.RequestScoped;import javax.faces.application.FacesMessage;import javax.faces.context.FacesContext;import javax.inject.Named;import javax.jms.*;
@Named(value = "mesajBean")@RequestScopedpublic class MessageYayinlayiciBean {
    @Resource(mappedName = "jms/myQueue")    private Queue myQueue;    @Resource(mappedName = "jms/myQueueFactory")    private ConnectionFactory myQueueFactory;    private String mesaj;
    public MessageYayinlayiciBean() {    }
    public String getMesaj() {        return mesaj;    }
    public void setMesaj(String mesaj) {        this.mesaj = mesaj;    }
    public void mesajGonder() {        FacesContext facesContext = FacesContext.getCurrentInstance();        try {            sendJMSMessageToMyQueue(mesaj);            FacesMessage facesMessage = new FacesMessage("Mesaj gonder: " + mesaj);            facesMessage.setSeverity(FacesMessage.SEVERITY_INFO);            facesContext.addMessage(null, facesMessage);        } catch (JMSException jmse) {            FacesMessage facesMessage = new FacesMessage("Mesaj gonderilemedi: " + mesaj);            facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);            facesContext.addMessage(null, facesMessage);        }    }
    private Message createJMSMessageForjmsMyQueue(Session session, Object messageData) throws JMSException {        TextMessage tm = session.createTextMessage();        tm.setText(messageData.toString());        return tm;    }
    private void sendJMSMessageToMyQueue(Object messageData) throws JMSException {        Connection connection = null;        Session session = null;        try {            connection = myQueueFactory.createConnection();            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);            MessageProducer messageProducer = session.createProducer(myQueue);            messageProducer.send(createJMSMessageForjmsMyQueue(session, messageData));        } finally {            if (session != null) {                try {                    session.close();                } catch (JMSException e) {                    e.printStackTrace();                }            }            if (connection != null) {                connection.close();            }        }    }}

index.html




Ve son olarak. Once EJB`mizi (MDB) daha sonrada JSF uygulamamizi weblogic server`a deploy ederek bitirelim ve test edelim.



JSf uygulamamizda deniyoruz.

Asagida ise managed serverimizin logu

Umarim faydali bir makale olmustur.

11 Mart 2013 Pazartesi

Virtual Box Uzerinde OCFS2 kurulumu

Merhaba, Baslik biraz kisa oldu :) aslinda baslik Virtualbox Uzerinde calistirdigimiz iki linux makine arasinda OCFS2 ile paylasilan disk nasil olusturabiliriz onu gorecegiz.

Virtual RAC

Ilk once, virtualbox uzerinde paylasilan(sharedable) bir disk olusturmali ve her iki makineye baglamaliyiz.
1. Kendi makinemizde:
   sudo bash
  [sudo] password for easlan:
  root@ertugrul:~# mkdir -p /storage/disk1
  root@ertugrul:~# chmod -R 777 /storage/disk1
  root@ertugrul:~# chmod -R 777 /storage/disk1
  easlan@ertugrul:~$ cd /storage/disk1

 # Sonra disk olusturuyoruz
  easlan@ertugrul:/disk1$ VBoxManage createhd --filename sanaldisk.vdi --size 5120 --       format VDI --variant Fixed
  0%...10%...20%...30%...40%...50%...60%...70%...80%...90%...100%
  Disk image created. UUID: 5cd924a1-59ce-421c-b9c7-7a59769f4c3f
  # Virtual Makinemize bagliyoruz.
  easlan@ertugrul:/disk1$ VBoxManage storageattach wlserver1 --storagectl "SATA Controller" --port 1 --device 0 --type hdd --medium sanaldisk.vdi --mtype shareable
  # Paylasilan yapiyoruz.
  easlan@ertugrul:/disk1$ VBoxManage modifyhd sanaldisk.vdi --type shareable
  -- Ikinci Makine icin olusturdugumuz diski gosteriyoruz.
  easlan@ertugrul:/disk1$ VBoxManage storageattach wlserver2 --storagectl "SATA Controller" --port 1 --device 0 --type hdd --medium sanaldisk.vdi --mtype shareable  
  wlserver1 linux makinemiz icersinden :
  [oracle@linux1 dev]$ cd /dev
  [oracle@linux1 dev]$ ls sd*
  sda  sda1  sda2  sdb   
   ~ Sonra her iki makineyede OCFS2 kurariz.


OCFS2 kurmak icin, linux makinemizin kernel versiyonunu ogrenerek indirip yukluyoruz.


# rpm -Uvh ocfs2-2.6.18-194.el5-1.4.7-1.el5.x86_64.rpm \ ocfs2console-1.6.3-2.el5.x86_64.rpm \ ocfs2-tools-1.6.3-2.el5.x86_64.rpm \ ocfs2-tools-debuginfo-1.6.3-2.el5.x86_64.rpm
Sonra ocfs2console`u baslatiyoruz.
[root@wlserver1 /]# ocfs2console
OCFS2 Console

Sonra Cluster > Configure Nodes
OCFS2 Information

Burada kac tane node`umuz varsa onlarin hepsini ekliyoruz.
OCFS2 Node Configuration





Icinden "/etc/init.d/o2cb" asagidakileri siliyoruz.
### BEGIN INIT INFO## Provides: o2cb## Required-Start: $network## Should-Start:## Required-Stop:## Default-Start: 2 3 5## Default-Stop:## Description: Load O2CB cluster services at system boot.### END INIT INFO
Asagidaki komutlari calistiyoruz.
[root@wlserver1 /] chkconfig --del o2cb 
[root@wlserver1 /] chkconfig --add o2cb 
[root@wlserver1 /] chkconfig --list 
o2cbo2cb 0:off 1:off 2:on 3:on 4:on 5:on 6:off
    [root@wlserver1 /] /etc/init.d/o2cb offline ocfs2
Cleaning heartbeat on ocfs2: OK
Stopping cluster ocfs2: OK
#
[root@wlserver1 /] /etc/init.d/o2cb unload
Unmounting ocfs2_dlmfs filesystem: OK
Unloading module "ocfs2_dlmfs": OK
Unmounting configfs filesystem: OK
Unloading module "configfs": OK
#
[root@wlserver1 /] /etc/init.d/o2cb configure
Configuring the O2CB driver.
This will configure the on-boot properties of the O2CB driver.
The following questions will determine whether the driver is loaded on
boot. The current values will be shown in brackets ('[]'). Hitting
without typing an answer will keep that current value. Ctrl-C
will abort.
Load O2CB driver on boot (y/n) [y]:
Cluster to start on boot (Enter "none" to clear) [ocfs2]:
Writing O2CB configuration: OK
Loading module "configfs": OK
Mounting configfs filesystem at /config: OK
Loading module "ocfs2_nodemanager": OK
Loading module "ocfs2_dlm": OK
Loading module "ocfs2_dlmfs": OK
Mounting ocfs2_dlmfs filesystem at /dlm: OK
Starting cluster ocfs2: OK
[root@wlserver1 /] cd /dev 
[root@wlserver1 /] ls sd*
                     sda sda1 sda2 sdb 
[root@wlserver1 /] fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course, the previous
content won't be recoverable.
The number of cylinders for this disk is set to 1305.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
(e.g., DOS FDISK, OS/2 FDISK)
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1305, default 1):
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-1305, default 1305):
Using default value 1305
Command (m for help): p
Disk /dev/sdb: 10.7 GB, 10737418240 bytes
255 heads, 63 sectors/track, 1305 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Device Boot Start End Blocks Id System
/dev/sdb1 1 1305 10482381 83 Linux
Command (m for help): w
The partition table has been altered!
Calling ioctl() to re-read partition table.
Syncing disks.
Sonra ocfs2console yeninden aciyoruz ve diski mount edecez.

[root@wlserver1 /] ocfs2console 

Menuden Tasks > Format
OCFS2 Format

OCFS2 Console

Gelen pencereden mount etmek istediginiz yolu seciyoruz.
 Mountpoint : /paylasilan

ve son olarak diskimizi automount olabilmesi icin fstab altina ekliyoruz.
[root@wlserver1 /] vi /etc/fstab
/dev/sdb1 /paylasilan ocfs2 _netdev,datavolume 0 0
Bukadar suanda her iki node`da /paylasilan altini ortak olarak kullanabiliriz.

~~~~~~~~~~~~~~~~~~~~~~ Yaptiklarimizi test etmek icin~~~~~~~~~~~~~~~~~~~~~~~
Herhangi bir node uzerinde /paylasilan adinda olusturdugumuz klasor icinde bir dosya olusturalim ve diger tarafda gorunecekmi bakalim.
node1 uzerinden
[oracle@wlserver1 /]$ cd /paylasilan/
[oracle@wlserver1 paylasilan]$ vi deneme.txt
node2 uzerinden
cd /paylasilan/
[oracle@wlserver2 paylasilan]$ ls
deneme.txt  lost+found
[oracle@wlserver2 paylasilan]$ cat deneme.txt
Bu ocfs2 denemesidir.
[oracle@wlserver2 paylasilan]$ vi deneme.txt
[oracle@wlserver2 paylasilan]$ cat deneme.txt
Bu ocfs2 denemesidir.
Simdi ikinci nodedan actik
node1 uzerinden
[oracle@wlserver1 paylasilan]$ cat deneme.txt
Bu ocfs2 denemesidir.
Simdi ikinci nodedan actik
## Yukaridada goruldugu gibi suanda hangi makinede degisiklik yapsak aninda digeri goruyor.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Burada mesala node1 kapatip actiginizda node2 bu alanda degisiklik yapabilecek ve node1 tekrar basladiginda node2`nin yaptigi degisiklikleri gorecektir.

/bin/sh: o2cb_ctl: command not found Could not create cluster ocfs2


/bin/sh: o2cb_ctl: command not found

Could not create cluster ocfs2

Oracle Enterprise Linux 5.5 kullaniyor ve ocfs2console actikdan sonra yukaridaki hatayi aliyorsaniz yapmaniz gereken PATH degiskenini set etmeliyiz.

$ export PATH=$PATH:/sbin


Daha sonra yeniden denediginizde duzeldigini goreceksiniz.

25 Şubat 2013 Pazartesi

personel_sema


drop table personeller cascade constraint purge;

drop table bolumler cascade constraint purge;

drop table iller cascade constraint purge;

drop table bolgeler cascade constraint purge;

CREATE TABLE personeller (
  personel_id NUMBER,
  adi VARCHAR2(50),
  soyadi VARCHAR2(50),
  email VARCHAR2(50),
  maas NUMBER,
  bolum_id NUMBER,
  mudur_id NUMBER
);

CREATE TABLE bolumler(
  bolum_id NUMBER,
  bolum_adi VARCHAR2(50),
  il_id NUMBER,
  mudur_id NUMBER
);

CREATE TABLE iller(
  il_id NUMBER,
  il_adi VARCHAR2(50),
  bolge_id NUMBER
);

CREATE TABLE bolgeler(
  bolge_id NUMBER,
  bolge_adi VARCHAR2(50)
);

ALTER TABLE personeller ADD CONSTRAINT uq_email UNIQUE (email);

ALTER TABLE personeller ADD CONSTRAINT pk_personelid PRIMARY KEY (personel_id);

ALTER TABLE bolumler ADD CONSTRAINT pk_bolumid PRIMARY KEY (bolum_id);

ALTER TABLE iller ADD CONSTRAINT pk_ilid PRIMARY KEY (il_id);

ALTER TABLE bolgeler ADD CONSTRAINT pk_bolgeid PRIMARY KEY (bolge_id);

ALTER TABLE iller ADD CONSTRAINT fk_bolgeid FOREIGN KEY (bolge_id) REFERENCES bolgeler(bolge_id);


insert into bolgeler values(1,'Akdeniz Bolgesi');
insert into bolgeler values(2,'Karadeniz Bolgesi');
insert into bolgeler values(3,'Marmara Bolgesi');
insert into bolgeler values(4,'Ege Bolgesi');
insert into bolgeler values(5,'Dogu Anadolu Bolgesi');
insert into bolgeler values(6,'Ic Anadolu Bolgesi');
insert into bolgeler values(7,'Guney Dogu Anadolu Bolgesi');

-- iller tablosu
insert into iller values(1,'Antalya',1);
insert into iller values(2,'Mersin',1);
insert into iller values(3,'Adana',1);
insert into iller values(4,'Trabzon',2);
insert into iller values(5,'Rize',2);
insert into iller values(6,'Ordu',2);
insert into iller values(7,'Samsun',2);
insert into iller values(8,'Istanbul',3);
insert into iller values(9,'Kocaeli',3);
insert into iller values(10,'Bursa',3);
insert into iller values(11,'Tekirdag',3);
insert into iller values(12,'Izmir',4);
insert into iller values(13,'Mugla',4);
insert into iller values(14,'Denizli',4);
insert into iller values(15,'Afyon',4);
insert into iller values(16,'Malatya',5);
insert into iller values(17,'Erzurum',5);
insert into iller values(18,'Agri',5);
insert into iller values(19,'Kars',5);
insert into iller values(20,'Ankara',6);
insert into iller values(21,'Kirsehir',6);
insert into iller values(22,'Konya',6);
insert into iller values(23,'Corum',6);
insert into iller values(24,'Gaziantep',7);
insert into iller values(25,'Sanliurfa',7);
insert into iller values(26,'Adiyaman',7);
insert into iller values(27,'Diyarbakir',7);

-- bolumler
insert into bolumler values(1,'Bilgi Islem',8,1);
insert into bolumler values(2,'Pazarlama',8,2);
insert into bolumler values(3,'Satis',9,3);
insert into bolumler values(4,'Muhasebe',20,4);
insert into bolumler values(5,'Insan Kaynaklari',8,5);
insert into bolumler values(6,'Finans',20,6);

-- personeller
insert into personeller values(100,'Murat','Bilgin','mbilgin@gmail.com',20000,null,null);
insert into personeller values(1,'Bilge','Ozturk','bilge@msn.com',4000,1,100);
insert into personeller values(2,'Ahmet','Aslan','ahmeta@gmail.com',3000,2,100);
insert into personeller values(3,'Mustafa','Camci','mustafac@msn.com',5000,3,100);
insert into personeller values(4,'Canan','Duran','canand@hotmail.com',2000,4,100);
insert into personeller values(5,'Baki','Turkoglu','bakit@msn.com',4500,5,100);
insert into personeller values(6,'Serdar','Erdogan','serdare@msn.com',3500,6,100);
insert into personeller values(7,'Hakan','Dogan','hakand@gmail.com',4000,1,1);
insert into personeller values(8,'Deniz','Kaya','kayad@msn.com',3500,2,2);
insert into personeller values(9,'Yusuf','Ozcan','yusufo@msn.com',2800,3,3);
insert into personeller values(10,'Mehmet','Karadag','karadagh@gmail.com',3200,1,1);
insert into personeller values(11,'Mehmet','Bozkurt','mehmetb@msn.com',4000,5,5);
insert into personeller values(12,'Ayse','Suzen','ayses@msn.com',3000,3,3);
insert into personeller values(13,'Esra','Dogulu','esrad@gmail.com',2000,4,4);
insert into personeller values(14,'Kemal','Kilic','kemalk@hotmail.com',2600,6,6);
insert into personeller values(15,'Ozkan','Eraslan','ozkane@msn.com',2900,1,1);
insert into personeller values(16,'Mehmet','Kilic','kilicm@msn.com',2000,6,6);
insert into personeller values(17,'Mustafa','Erdogan','mustafae@hotmail.com',1900,3,3);
insert into personeller values(18,'Ensar','Selcukoglu','ensars@msn.com',2560,4,4);
insert into personeller values(19,'Kadir','Balci','kadirb@gmail.com',3000,5,5);
insert into personeller values(20,'Gulsah','Arslan','gulsaha@hotmail.com',2000,2,2);
insert into personeller values(21,'Hakan','Mertcan','hakanm@msn.com',2300,1,1);
insert into personeller values(22,'Suat','Taskesen','suatt@gmail.com',1980,4,4);
insert into personeller values(23,'Nurhan','Yilmaz','nurhany@hotmail.com',3000,3,3);
insert into personeller values(24,'Harun','Ipek','haruni@gmail.com',2000,3,3);
insert into personeller values(25,'Mahmut','Yildirim','mahmut@msn.com',2500,3,3);


ALTER TABLE personeller ADD CONSTRAINT fk_bolumid FOREIGN KEY (bolum_id) REFERENCES bolumler(bolum_id);

ALTER TABLE bolumler ADD CONSTRAINT fk_mudurid FOREIGN KEY (mudur_id) REFERENCES personeller(personel_id);

ALTER TABLE bolumler ADD CONSTRAINT fk_ilid FOREIGN KEY (il_id) REFERENCES iller(il_id);









30 Ocak 2013 Çarşamba

kupprdp: worker process DW01 started with worker

kupprdp: worker process DW01 started with worker, eger alertlog`da bu sekilde bir prosesin calistigini goruyorsaniz, veritabani uzerinde datapump (import-export) islemin yapildigi veya hala devam ettigidir.

 alterlog.log


ALTER SYSTEM SET service_names='SERVICESO','SERVICE1','ORCL','SYS$SYS.KUPC$C_1_20120530152424.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' SCOPE=MEMORY SID='ORCL';

kupprdp: master process DM00 started with pid=242, OS id=18774
         to execute - SYS.KUPM$MCP.MAIN('EXP_FULL_1', 'SYSTEM', 'KUPC$C_1_20120530152424', 'KUPC$S_1_20120530152424', 0);
kupprdp: worker process DW01 started with worker id=1, pid=568, OS id=8654

21 Ocak 2013 Pazartesi

Index Clustering Factor

   Soyle bir senaryo dusunelim, varolan bir tablonuzdaki herhangi bir kolon uzerinde index olusturnuz ve sorgunuz where sartinda bu kolon uzerinden bir kosul sagladik ve sorgumuzun execution planina baktigimizda “index range scan” yaziyor. Burada kadar her sey cok guzel, istedigimiz gibi index`imiz calisiyor. 

Ama bir sorun var.! Sorgum index range scan plani kullanmasina ragmen bana donen sonuc bekledigimden cok yavas. Acaba bunun sebebi ne olabilir. Bunun sebebi su ki, sorgum index kullanmasina ragmen tablodan cok fazla blok okumasidir. Buda bize Index Clustering Factor degerinin cok buyuk oldugunu gostermektedir.

Index Clustering Factor : Indeks üzerinden tabloya gidildiğinde, her gidişte okunan tablo bloklarının sayısıdır. ICF degeri bir tablodan arka arkaya ayni blogu okudugumuzda artmaz, yeni bloklara gecildigi zaman artar. 

Index Clustering Factor degerindende anlayacagimiz gibi, sorgumuzun execution planda index calistigini gorsek bile, sorgumuz sonuc getirirken malasef tablo uzerindeki cok fazla blogu ziyaret etmekte ve buda system uzerinde I/O degerini artirmaktadir. Ve ne kadar  cok blog okunursa sorgumuzun cost(maliyet)ini o derecede artiracaktir. 

Clustering factor'ü düşük olan bir indeks ile costu cok dusuk sorgulara sahip olabilirsiniz

Clustering factor'ü arttırabilecek faktörlerden birisi tablonun sürekli olarak taşınması(move) veya yeniden oluşturulmasıdır. Tabloya girilen her yeni kayıt ile indeks kendine ait olan mantıksal yapraklarını günceller ve daha fazla clustered olma eğilimine girer. Bu sekilde devam eden bir durumda, clustering factor degerinin nelere gelebilcegine inamamazsiniz.

Peki bu kadat bahsettigimiz clustering factor degerini nasıl düşürebiliriz?Akla gelen ilk yol tabloyu yeniden organize etmektir.Bunu da 10g ile gelen shrink opsiyonu ile gerçekleştirebiliriz. Ancak SHRINK yapildigi zaman, tablodaki indexler kullanilamaz hale gelir ve yeninde rebuild edilmesi gerekmektedir.

Oracle Optimizer Istatistikleri

Bu bolumde asagidaki konulari gorecez.
      Cost Based Optimizer (CBO), verilen SQL'i hangi yol ile çalıştıracağını tespit eden bir sistem. Bu sistem aslına bakarsanız oldukça faydalı ve en düşük maliyetli sorgu yolunu seçmekte başarılı.

CBO kimi zaman tablo üzerindeki istatistikler güncel olsa bile doğru sonucu vermiyor olabilir. Burada dikkat, CBO zaten doğru sonuca gidiyor ama "optimum" sonuca gitmiyor olabilir.  Bu da şu demek oluyor, CBO kendi hesapladığı maliyeti en düşük olan çalıştırma yoluna girer.  Bunu da tablo üzerindeki istatistikleri baz alarak yapar.

    Evet yukaridaki tanimlardada belirtildigi gibi, ozellikle tablo ve indexlerin istatistik bilgilerinin guncel olmasi performans acisindan bizim icin cok onemli. Cunku tablo veya indexlerin istatistik bilgileri eski ise optimizet eski olan bu istatistik bilgilerine gore bir execution plan(calisma plani) olusturacaktir.

  Peki bizim icin bu kadar onemli olan istatisktik bilgileri nasil toplayabiliriz veya istatistik bilgilerimizin guncel olabilmesi icin ne yapmaliyiz.

 Oracle ANALYZE ifadesini kullanarak istatistik bilgileri toplamanız mümkündür. Ancak Oracle 9i versiyonu ile birlikte aramiza katilan ve bir PL/SQL paketi olan DBMS_STATS paketini yapabiliriz ve bu bolume bu paket uzerinden devam edecegiz.

DBMS_STATS bu paketin amaci. Daha once bahsetmis oldugumuz Cost Based Optimizer icin gerekli tablo, index ve diger objeler uzerinde istatistik bilgilerini toplamaktir. Toplanan bur istatistik bilgilerini oracle data dictionaryde tutmaktadir.Oracle istenilirse istatistikleri data dictionary dışında da tutulabilmektedir ve optimizer'ı  hic bir sekilde etkilemeden yapabilmektedir. Toplanan istatistikleri başka bir veritabanına da taşıyabilirsiniz.

Simdide optimizer istatistik tiplerine bakalim.

Optimizer Istatistik tipleri


Bu tipleri 4 baslik altinda toplayabiliriz. Bunlara Table, Index, System ve Column


Table Istatistikleri
• Number of rows
• Number of blocks
• Average low length
Index Istatistikleri
• B*-tree level
• Distinct keys
• Number of leag blocks
• Clustering factor
System istatistikleri
• I/O performance and utilization
• CPU performance ve utilization
Column istatistikleri
• Basic : Number of distinct values, number of nulls, average length, min, max
• Historamgs (data distribution when the column data is skewed)
• Extended statistics

Yukarida en cok kullanilan ve bilinen istatistik tiplerini gordurk. Oracle 10g surumu ile birlikte indexlerin istatistik bilgileri, index olusturuldugunda ve yeniden rebuild edilginde otomatik olarak toplanmaktadir.(create or rebuild).

Daha once bahsettigimiz gibi, optimizer istatistik bilgileri data dictionaryde tutulur. Ve bunlari bazi view(goruntu)ler yardimiyla goruntuluyebiliriz. Bu goruntuler performans goruntuleri ile karsilastirilmamalidir.

Tablo istatistikleri icin : DBA_TAB_STATISTICS
Index Istatistikleri icin : DBA_IND_STATISTICS

Peki bu istatistikleri bir manuel olarak toplamak zorundamiyiz.? Oracle'ın GATHER_STATS_JOB isminde bir otomatik istatistik toplayan görevi bulunmaktadır ve hafta içi 22:00'den sonra hafta sonu ise sabah otomatik olarak devreye girerek, veritabanı istatistiklerini toplamaktadır.

Bu sorumuzu cevabini aldikdan sonar akilimiza su gelebilir. Demekki biz, hafta ici gun icersinde bir tablo olusturdugumuzda ve bu tabloya mesala milyonda fazla kayit ekledikden sonar tablonun istatistik bilgileri tabloda 0 rows oldugunu gosterecek ve optimizer execution plani bu istatistik dogrultusunda yapacaktir. O zaman yapmamiz gerek bu durumlar icin, tablonun istatik bilgilerini manuel olarak almaktadir. Daha sonra gece, bu job kendisi otomatik olarak toplayacaktir.

Not: Gun icerisinde bir tabloya cok fazla veri ekleniyorsa, bu job isini yapmasini beklemektense kendimiz bir job yazib bu tablonun istatistik bilgilerini gunde bir kac defa toplamamasina veya 4 saatte bir  istatistik toplamasini saglayabiliriz.

Adaptive Cursor Sharing

       Bir onceki baslikta gordugumuz bind variable ve cursor sharing yani benzer SQL statement`a sahip SQL`lerin ayni exectuion plani kullanmalarini gormustuk. Ancak bununda dezavantajlarinin oldugunu soylemek mumkun. Mesala benzer olan uc tane SQL ifademiz var, ve cursor sharing oluyorsa ilk calisan SQL icin olusturulan execution plan diger SQL`ler icinde calisacak ve eger ilk calisan SQL hard parse veya FTS(Full Table Scan) yapiyorsa ondan sonra gelen SQL`ler icinde ayni durum olacaktir. Ama diger SQL`ler FTS yapmiyor olabilir. Bu durumda cursor sharing avantajli durumdan cikacaktir.
Oracle 11g surumunden sonra bu durum icinde bir cozum olusturulmustur oracle bu sorunu Adaptive Cursor Sharing ile asabilmektedir.

Adaptive Cursor Sharing : Cost Based Optimizer (CBO)’ın execution planları oluştururken bir statement için daha fazla execution plan tutmasına olanak sağlayan yapı olarak ön plana çıkmaktadır. Bir statement için birden fazla execution planı tutuyor olmak daha önceki versiyonlardan farklı olarak ilk hard parse olan statement’ın planını daha sonra tekrar tekrar farklı parametrelerle çalışan aynı statementlarıda kullanmak zorunda bırakmamak anlamınada geliyor olacaktır. Bind variable kavramındaki execution planları ortak kullandırma mantığının aynı plana sahip olmaması gereken 2 cümle için ortak plan kullandırdığı zaman ne kadar maliyetli (costu yüksek) olduğunu görebiliriz. Mesala asagidaki SQL`i degerlendirelim.

                select * from emps where salary= :sal;

      Bu SQL icin, mesala :sal degeri once 10000 daha sonrada 2000 olarak set edilsin. 10000 olarak set edildiginde 1 tane sonuc geliyor(yani selectiviysi yuksek) ve execution plani optimizer uzerinde INDEX RANGE olarak calissin ve index uzerinden veriyi getiriyor olsun. Ama :sal degeri 2000 olarak set ettigimizde ise tablodaki verilerin % 40 `I geliyor. Bu durumda hatirlayalim optimizer bir sorguda istenen sonuc tum tablounun tahmini olarak % 10`undan daha fazla ise Full table scan yapilmasi cost(maliyet) acisinda daha avantajlidir.

Simdi ikinci calistiracagimiz SQL`in bu durumunu inceleyelim; Bilindigi gibi bu SQL ifadesi daha birçok kez çalışacaktır ve eğer Adaptive Cursor Sharing(ACS) olmasaydi ilk hard parse olan yani :sal = 10000’e göre oluşan execution plan :sal 2000 içinde uygulanacaktı ve daha avantajli olan Full Table Scan ile gelmesi gereken bir tablo index üzerinden getirilmeye çalışılacak ve response time’ı düşecekti ve sorgunun sonucu daha uzun sürede oluşacaktır.

Adaptive Cursor Sharing`den bilgileri alabilmemiz icin bize yardimci views(goruntuler) mevcuttur.

V$SQL :  tablosunda – IS_BIND_SENSITIVE,  IS_BIND_AWARE kolonlari
V$SQL_CS_HISTOGRAM : SQL ifadesinin bind sensitive olup olmadığını 3 adet frequency histogram ile yorumlamamızı sağlar. Ayrica Child cursorların kaçar kere çalıştığı bilgisinide içerir.
V$SQL_CS_SELECTIVITY : Bir SQL ifadesi ile beraber gelen where koşulundaki değerleri, bunların selectivitysini ve high value – low value aralığını tutar.
V$SQL_CS_STATISTICS : Adaptive Cursor’ın nekadar paylaşıldığını gösteren istatistik bilgilerini iceren bir view(goruntudur).

Oracle Cursor Sharing`e bakis

Cursor Sharing
       Oracle 9i versiyonundan sonra, benzer SQL ifadeleri icin ayni execution plani olusturmaya baslamistir. Sadece literal degeri degisen sorgular icin ilk calisan sorguda olusturulan execution plan diger sorgular icinde kullanilmaya baslanmis ve her sorgu icin yeni execution plan olusturulmamis oldu. Simdi asagidaki iki sorguya bakalim.
                SQL> SELECT * FROM emps WHERE dep_id = 100;
                SQL> SELECT * FROM emps WHERE dep_id = 20;
         Yukaridaki iki sorgumuzda, ikinci sorguyu birinci sorguya bagli olarak, nasil bir execution plan olusturulmus ise ikinci sorgudada ayni execution plan devam edecektir.(Bu Full table scan olabilcegi gibi INDEX RANGE SCAN da olabilir)

Sorgularınızı yazarken dikkat etmeniz gereken konu sorgunun genel yapı olarak sürekli değişmiyor olması. Yaptığınız her en ufak değişiklik Oracle tarafından farklı bir sorgu olarak algılanır ve eğer bir de içeride bind variable yerine literal (numara veya karakter) kullanıyorsanız ve cursor_sharing parametreniz SIMILAR’da kalmış ise arka tarafda cok iyi seyler olmuyor diyebiliriz.

- CURSOR_SHARING bir oracle initilization parametresidir ve Shared pool içerisinde tutulan sqllerin benzerleri geldiğinde aynı plan ile diğerlerininde çalışıp çalışmayacağının set edildiği parametredir (literal(numara veya karakter) kullanımını görüp bunun birer bind variable olarak plan’larının saklanmasını sağlar)
Cursor sharing parametresinin degerleri nelerdir ve nasil degistirebilirim.
• CURSOR_SHARING paremetresinin alabilecegi degerler
-  FORCE
-  EXACT(default (varsayilan degerdir))
-  SIMILAR
• CURSOR_SHARING parametresini nasil degistirebilirim.
- ALTER SYSTEM CURSOR_SHARING = ?
- ALTER SESSION CURSOR_SHARING = ?
- Initializtaion parameter dosyasi icinden degistirebiliriz

Simdi CURSOR_SHARING parametresinin alabilecegi, FORCE, EXACT, ve SIMILAR degerlerinin ne yaptiklarina bakalim.
EXACT : Çalışan sqlerin cache’ den çalışması için sorguların birebir aynısı olması gerekmektedir.
FORCE : Cache de Çalışan sql lerin benzeri varsa mevcut execeution plan kullanılmasını zorlar.(Yani yazilan, ve benzer butun sql`ler icin ilk olusutural execution planlarin ortak kullanilmasi)
SIMILAR : sql’ lerin birebir aynı olmasa da benzeyenler için (execution planlarına da bakar) cache den çalıştırmaya yönlendirir.

Simdi asagidaki uc SQL` e bakalim ve bu uc sql`in ayni execution plani kullandigini gorecegiz. Oncelikle CURSOR_SHARING parametresini FORCE olarak set edelim.
SQL> alter session set cursor_sharing = FORCE;
SQL> SELECT * FROM emps WHERE salary > 10000;
SQL> SELECT * FROM emps WHERE salary > 15000;
SQL> SELECT * FROM emps WHERE salary > 9000;

Birinci SQL`imiz calsitikdan sonra Oracle bu SQL`e shared pool`da asagidaki gibi bir bind-variable generate ediyor ve bu SQL icin execution plan olusturuyor.

SELECT * FROM emps WHERE salary > :"SYS_B_0";
Daha sonra diger iki SQL calsitiginda bind-variable generate ettigi ve exectuion plani olusuturdugu plani calistiriyor.

Yukaridaki ornekten sunu cikarabiliriz. CURSOR_SHARING parametresi “auto binder”, yani biz sql`imizde bind_variable kullanmiyorsak Oracle bu parametre sayesinde bizim yerimize  otomatik bind variable yapiyor.
Simdi bu degerleri veritabanizda degistirerek sonuclara bakalim.

Labs :
SQL> alter system set cursor_sharing='SIMILAR';
System altered.
SQL> select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner='SYS';
SQL> select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner='SYSTEM';
SQL> select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner='SCOTT';

SQL>  select sql_id,sql_text from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';
SQL_ID               SQL_TEXT
7qsnvbzwh79tj  select /*TEST_SIMILAR*/  count(*) from system.myobjects where owner=:"SYS_B_0"
SQL> select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';
SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
7qsnvbzwh79tj            0          3          1           3

Goruldugu gibi, bir tane SQL`imi var ve otomatik olarak bind variable atanmis :SYS_B_0 ve 3 defa cagirilmis.

Simdi “v$sqlarea”`da kactane sqlmiz var bakalim.
SQL> select version_count from v$sqlarea where sql_id='7qsnvbzwh79tj';
VERSION_COUNT
-------------
            1

Ayni durumu LIKE kullanarak yapalim ve durumun ne kadar degistigini ve ortaya ayni sqlidye  uc tane SQL ciktigini gorecegiz.

SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where owner like 'A%';
SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where owner like 'B%';
SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where owner like 'C%';

SQL> select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';
SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
6hkkxzpas5hyq            0          1          1           1
6hkkxzpas5hyq            1          1          1           1
6hkkxzpas5hyq            2          1          1           1
SQL> select version_count from v$sqlarea where sql_id='6hkkxzpas5hyq';
VERSION_COUNT
-------------
3

Simdi ayni ornegi CURSOR_SHARING parametresini FORCE olarak set edip test edelim.

SQL> alter system set cursor_sharing='FORCE';
            System altered.
SQL> select /*FORCE*/  distinct owner from myobjects where owner like 'A%';
SQL>  select /* FORCE */  distinct owner from myobjects where owner like 'B%';
SQL> select /* FORCE */  distinct owner from myobjects where owner like 'C%';
SQL> select version_count from v$sqlarea where sql_id='6c4f9xwp19pff';
VERSION_COUNT
     1
SQL>  select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*FORCE*/%';
SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
6c4f9xwp19pff            0          3          1           3
SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='A';
SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='B';
SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='C';
SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='D';
SQL> select /*TEST_SIMILAR*/  distinct owner from myobjects where object_type='E';
SQL> select sql_id,child_number,EXECUTIONS,LOADS,PARSE_CALLS from v$sql where sql_text like 'select /*TEST_SIMILAR*/%';
SQL_ID        CHILD_NUMBER EXECUTIONS      LOADS PARSE_CALLS
------------- ------------ ---------- ---------- -----------
2m80tr9fhhbwn            0          1          1           1
2m80tr9fhhbwn            1          1          1           1
2m80tr9fhhbwn            2          1          1           1
2m80tr9fhhbwn            3          1          1           1
2m80tr9fhhbwn            4          1          1           1
SQL>  select version_count from v$sqlarea where sql_id='2m80tr9fhhbwn';
VERSION_COUNT
             5
SQL> select hash_value,address from v$sqlarea where sql_text like 'select /*TEST_SIMILAR*/%';
HASH_VALUE ADDRESS
1560817556 0000000095B58FD8
SQL> select * from v$sql_shared_cursor where address='0000000095B58FD8';
SQL_ID        ADDRESS          CHILD_ADDRESS    CHILD_NUMBER U S O O S L F E B P I S T A B D L T B I I R L I O E M U T N F A I T D L D B P C S C P T M B M R O P M F L P L A F L R L H P B
2m80tr9fhhbwn 0000000095B58FD8 000000009160F6B8            0 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N
2m80tr9fhhbwn 0000000095B58FD8 0000000091633E68            1 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N Y N N
2m80tr9fhhbwn 0000000095B58FD8 0000000091741E10            2 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N Y N N
2m80tr9fhhbwn 0000000095B58FD8 000000008DA39108            3 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N Y N N
2m80tr9fhhbwn 0000000095B58FD8 00000000947D5B30            4 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N Y N N