Oracle için kullandığım ve geliştirmekte olduğum PHP ORM kütüphanemde kompleks sorgulara girdikçe yeteneklerini arttırmam gerektiğini farkettim, veritabanını düşünmeden ORDER BY parametresine bir SUBQUERY yazdım düz mantıkla bu kesinlikle performans kaybıdır diye düşünerek Plan analizi yaptırdım veritabanına ama sonuç beni şaşırttı ve  yeni birşey öğrendim (: ORDER BY için bir subquery kullanmak JOIN den daha hızlıymış (: hemen bir örnek vermek istiyorum

Futbolcuları Takımları ile eşleştirip takım adına göre dizmek istedim.

0
1
SQL > SELECT P.NAME,P.ID  FROM PLAYERS P JOIN CLUBS C ON P.CLUB_ID = C.ID
ORDER BY C.NAME;

bunu kütüphanem yazamazdı ben de ORDER BY kısmına query yazdım ve sorgum bu hale geldi.

0
1
SQL > SELECTNAME,ID FROM PLAYERS P
ORDER BY (SELECT NAME FROM CLUBSC WHERE C.ID = P.CLUB_ID);

ve Plan analizinin sonucu (:
JOIN

0
1
2
3
4
5
6
7
8
Operation
------------------------------
SELECT STATEMENT
 SORT ORDER BY
  MERGE JOIN
   TABLE ACCESS BY INDEX ROWID
    INDEX FULL SCAN
   SORT JOIN
    TABLE ACCESS FULL

SUBQUERY

0
1
2
3
4
5
6
Operation
----------------------------
SELECT STATEMENT
 TABLE ACCESS BY INDEX ROWID
  INDEX UNIQUE SCAN
 SORT ORDER BY
  TABLE ACCESS FULL

Tuning fantazilerine girerseniz aklınızda bulunsun (: iyi çalışmalar,

OCI-Lob  sınıfını tanımıştık. bu sınıfın insert ve update  sorguları için kullanılan metodu olan OCI-Lob::save()  metodunu inceliyor olacağız.  Update sorgularımız için şartımıza uyan bir satır  yoksa php OCI_INVALID_HANDLE gibi bir hata fırlatıyor. update işlemlerini bir sonraki yazıda işleyeceğimiz için şimdilik sadece bahsedip geçiyoruz.

OCI-Lob
bool save ( string $data [, int $offset ] )

save metodu LOB alanlara veri yazmak için kullanılır. OCI lob objelerinin indikasyon özelliği olduğundan  opsiyonel olarak  offset değeri de verebiliyoruz . yani istersek veriyi  lobun istediğimiz alanına yazabiliyoruz.

işte örnek insert işlemi.

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
$conn=oci_connect(); // bağlantı ayarlarınız
 
$sql = "INSERT INTO loblar
          (
            id,
            lobalan
          )
       VALUES
          (
            loblar_seq.NEXTVAL,
            -- Boş bir CLOB oluşturuyoruz
            EMPTY_CLOB()
          )
       RETURNING
          -- Lob locator dönderiyoruz
          lobalan INTO :mylob_loc";
 
$stmt = oci_parse($conn, $sql);
 
// Boş bir OCI-Lob objesi oluşturuyoruz
$myLOB = oci_new_descriptor($conn, OCI_D_LOB);
 
// LOB loactor a bağlıyoruz.
oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_CLOB);
 
// Sorguyu çalıştıyoruz (Default Transaction modunda)
oci_execute($stmt, OCI_DEFAULT)
    or die ("Unable to execute query\n");
 
//  Lob alana şimdi istediğimizi yazdırıyoruz
if ( !$myLOB->save('Tarih : '.date('H:i:s',time())) ) {
 
    // Hata olmuşsa geri sarıyoruz
    oci_rollback($conn);
 
} else {
 
    // başarıyla yazabildiysek commit ediyoruz.
    oci_commit($conn);
 
}
 
// kaynakları boşaltıp  veritabanı bağlantısını kesiyoruz.
oci_free_statement($stmt);
$myLOB->free();
oci_close($conn)

Blob Compression konusunda bilgi almak için de şu konuyu okuyabilirsiniz

Oracle Blob Compression

4000 byte’tan daha büyük verilerle çalışıyorsak LOB  alanlara ihtiyacımız olacaktır.   

Standart (basit) veritabanı tipleriyle çalışmak diğer datalarda olduğu gibi Oracle’da da oldukça kolay. Fakat dosya saklama – ya da stringe dönüşümünde veri bozulmaları yaşayabileceğimiz 4000 byte tan büyük datalarla çalışacaksak Oralce LOB (Long Objects) lara ihtiyacımız olacaktır. PHP ile Oracle LOB alanlarda  yapabileceğimiz işlemleri incelemden once kısaca LOB tipleri tanımlayalım  

Oracle LOB Objects     

 

  • BLOB, Binary verileri saklamak için kullanırır (Binary Long Object)
  • CLOB, Veritabanı karakter setinde normal karakterler saklamak için kullanılır (Characters Long Object)
  • NCLOB,Unicode datalar saklamak için kullanılır . PHP nin Oci8 eklentisinde bu yoktur.
  • BFILE, Veritabanı sunucusnda dosya adresini referans alarak sunucuda saklanacak dosyalar için kullanılır.
  •   

    Üzerinde işlem yapılan LOB alanlar biz boşaltana kadar geçici tablo alanında (Temporary Tablespace) saklanır .  Oracle 9i ve öncesinde bu tipler için table spacede ayrı ayrı saklama yeri oluşturuluyormuş bu yuzden eski sürümlerde bu tipler üzerinde işlem yaparken daha dikkatli olmamız söyleniyor.   

     LOB Saklama 
    Oracle 10g  her LOB hücresi için 128 TB kadar veri saklama kapasitesine sahipmiş. Bu Veri tabanı block boyutu ve yığınlama ayarlarında isteğe bağlı değiştirilebiliniyormuş.  LOB verilerinin saklanması 2 elemanla olur. LOB Content  ve LOB Locator. LOB Content   sadece LOB Locator’un adresini içerir. 
          Dahili LOB tipleri (BFILE dışında kalanlar) 4KB nin altında  olduğu sürece diğer tablo verileriyle aynı (stored in line in the table ) yerde saklanır.   lob alanlarınız 4 kb den küçükse isteklerinizin işlenip size gelmesi gayet hızlı olacaktır. fakat büyükse bu  tablo için yapılan SELECT sorgularında LOB sütunlarının dahil edilmesi sorgu sonucu almanızı yavaşlatacaktır.  

    LOB Kısıtlamaları  
     Lob alalar için en önemli kısıtlamalar. Sorgu dahilinde sıralama ve gruplama işlemleridir.  

    • Coğul Elemelerde  kullanılmaz
    • Sıralamalarda kullanılamaz
    • Gruplamalarda kullanulamaz
    • Birleştirmelede kullanılamaz
    • Primary Key olarak atanamaz
    • Unique index oluşturulamaz

    SELECT DISTINCT <lob_type>
    ORDER BY <lob_type>
    GROUP BY <lob_col>   

    dahil edemeyeceğimiz bu işlemler ile yine bu işlemleri kullanan  UNION -MINUS -INTERSECTION gibi tablo birleştirme işlemlerinide kısıtlamış olur.  

    PHP ve ORACLE LOB işlemleri (OCI-Lob Sınıfı):
       Bu sınıfla ilgili php manual de  maalesef cok sınıflı bilgi var.  php ile OCI LOB işlemleri yapmamız için kullanabileceğimiz bu sınıf dikkatimi çektiği üzere bir cok PHP IDE tarafından da complatorlara dahil edilmemiş.! 

    Yerel Sunucumda PHP 5.3 versiyonunda OCI-Lob sınıfının metodlarını incelemek istedim.
      

    OCI-Lob::load()          
    OCI-Lob::tell()          
    OCI-Lob::truncate()      
    OCI-Lob::erase()         
    OCI-Lob::flush()         
    OCI-Lob::setbuffering()  
    OCI-Lob::getbuffering()  
    OCI-Lob::rewind()        
    OCI-Lob::read()          
    OCI-Lob::eof()           
    OCI-Lob::seek()          
    OCI-Lob::write()         
    OCI-Lob::append()        
    OCI-Lob::size()          
    OCI-Lob::writetofile()   
    OCI-Lob::export()        
    OCI-Lob::import()        
    OCI-Lob::writetemporary()
    OCI-Lob::close()         
    OCI-Lob::save()          
    OCI-Lob::savefile()      
    OCI-Lob::free()           

    metodların hepsini maalesef işleyemeyeceğim fakat kullandıkça örnekleri de buraya yazmaya çalışacağım. 

    Çoğu zaman ilişkili tablolarımızda tablo sayısı  bir kaç taneyi geçebiliyor  ve genelde bunların sonuna ya da başına _ALT koyuyoruz (:  ama soyun sınırsız olduğunu düşündüğümüzde  bunu tek tabloda tutup  ATA_ID ya da PARENT_ID gibi kendisinin atasıyla ilişkilendirmek daha mantıklı oluyor. bu gibi durumlarda Recursive işlemlere ihtiyac duyuyoruz . ama bunu recursive olarak dataya sormak yerine  recursive işlemini dataya yapmak daha da mantıklıdır. bu işlemi yapan cümleciğimizin yapısı da  CONNECT BY PRIOR – START WITH anahtar  cumleciklerinden oluşuyor ilk once bir soyağacı tablosu örneği vermek istiyorum . ailem diye bir tablo oluşturalım

    0
    1
    2
    3
    4
    
    CREATE TABLE ailem(
     tckimlik int PRIMARY KEY,
     adi VARCHAR(30),
     baba_tc int
    );

    ailenin her ferdini bu tabloda ilişkili olarka tutabiliriz  baba_tc kendisinin babası olan kaydın tckimlik alanına eşit olacaktır.

    şimdi kayıtlarımızı ekleyelim

    0
    1
    2
    3
    4
    5
    6
    7
    
    INSERT INTO ailem (tckimlik,adi) VALUES (1,'Ömer');
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (2,'Yahya',1);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (3,'Tufan',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (4,'Savaş',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (5,'Diyar',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (6,'Barbaros',2);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (7,'Yeğenim',6);
    INSERT INTO ailem (tckimlik,adi,baba_tc) VALUES (8,'Çocuğum (:',3);

    yandaki tablodan da gördüğümüz gibi  baba_tc alanı ile  kaydın babasını belirledik. bu iki sütun yardımı ile ağaç yapısnı oluşturabileceğimiz bir tablo yapımız oldu.

    şimdi ornek sorguyu yazalım

    0
    1
    2
    
    SELECT  adi,tckimlik,baba_tc
    FROM  ailem
    CONNECT BY PRIOR tckimlik=baba_tc

    bu sorgu sonucunda bize tüm kayıtlar ve varsa alt alt kayıtları da dönecektir. örnek resim :

    kayıtlar baba_tc ile geldi ama bu ne kadar işimize yarar (: her kayıt baba olarak ve her kaydın da varsa cocuğu geldi baba_tc ile zaten bu tabloda bir ilişki kurabiliyorduk bu bizim için bi anlam ifade etmedi conenct by sorgularında kullanabileceğimiz bir anahtar daha LEVEL  bu da bize kaydın derinliğini ya da nesil katını verir diyelim.

    örnek sorgu

    0
    1
    2
    
    SELECT  adi,tckimlik,baba_tc,LEVEL
    FROM  ailem
    CONNECT BY PRIOR tckimlik=baba_tc

    level bize derinlik verdi. resimdeki orneğe bakalım

    leveli 1 olan  ilk atalar 2- 3 diye arttıkça torun oluyor.

    buna bir de leveli kullanarak anlaşılabilir bir görüntü verebiliriz. lpad fonksiyonunu kullanarak  isimlerin başına “level”  kadar ” – ” attıralım..

    0
    1
    2
    3
    
    SELECT  LPAD('-',LEVEL,'-')|| adi sahis,tckimlik,baba_tc,LEVEL
    FROM  ailem
    START WITH baba_tc IS NULL
    CONNECT BY PRIOR tckimlik=baba_tc

    boylelikle kayıtlar daha anlaşılır oldu  kim kimin atası net olarak görülebiliyor.

    şimdi bu kayıtları üst kaydı göstererek tek satırda göstermeye çalışalım. bunun için de  SYS_CNNECT_BY_PATH() fonksiyonunu kullanacağız.

    örnek sorgu :

    0
    1
    2
    3
    
    SELECT tckimlik,adi, SYS_CONNECT_BY_PATH(adi, '->') AS konum
    FROM ailem
    CONNECT BY PRIOR tckimlik=baba_tc
    START WITH baba_tc IS NULL

    tablo :

    şimdi ise   her kaydı dosya yolu gibi PATH ‘i ile beraber  dededen ->toruna ikişkisiyle göstermeyi başardık  (:
    iyi çalışmalar…

    © 2012 Tufan Suffusion theme by Sayontan Sinha