11 Mart 2015 Çarşamba

PL/SQL

Oracle ile çalışırken aldığım notları burada paylaşıyorum

Shared Pool
Shared Pool Oracle sunucusu içindeki bir çok hafıza alanından birisi. Aşağıdaki şekilde bunu görebiliyoruz.


SGA içindeki en öenmli alanlarda birisi de "Shared Pool". Shared Pool içinde SQL sorgularını ve çalıştırma planlarını saklıyor. SQL sorgularının neden değişkenler bind ederek çalıştırılması gerektiğini anlatan Oracle SQL Processing, Shared Pool ve Bind Variables başlıklı güzel bir yazıyı burada buldum.Eğer sürekli dinamik SQL kullanılırsa Shared Pool içindeki önbellek etkili bir şekilde kullanılamıyor. Konuyu anlatan bir diğer bilgilendirici yazı ise burada. Her iki yazının özeti ise buradan aldığım şu cümlede bulunabilir.

Oracle is built on the premise that you are going to parse a SQL statement once, generally using bind variables, and then execute the statement many times with different values for the bind variables


Cursor
Cursor bir SQL select cümlesine isim vermek şeklinde düşünülebilir.
Cursor ile sorguların sonuçlarını başka metodlara geçmesi çok kolay. Cursor sorgu sonucunu nerede saklıyor sorusunu merak ediyordum. Cevabını buradan aldığım aşağıdaki şekilde buldum.

Open cursor for select statement

Bir cursor konusu şu başlıklardan oluşuyor. Başlıkları en iyi anlatan sayfa burada.

Cursor Tanımı
Cursor yazısına taşıdım.

Kod İçinde Arama Yapmak

Aşağıdaki SQL ile kod içinde arama yapmak mümkün.

SELECT owner, name, type, line, text FROM dba_source 
WHERE instr(UPPER(text), UPPER('create index')) > 0; 
 
Index
Bir kaç tane index çeşidi var.

B-Tree Index
Bunlardan en çok kullanılanı B-Tree Index'leri. B-Tree index içinde RowID tutulduğu için verilen tablodaki satıra direkt erişim olabiliyor. Aşağıdaki şekli buradan aldım ve direkt erişimi gösteriyor.
B-Tree index içindeki node'lar istenilen sayıda olabilir ancak genellikle disk block size'ın belli bir katı olacak şekilde kullanılırlar.

Index'i paralel olarak yaratmak için aşağıdakine benzer bir cümle lazım.
create index on mytable nologging parallel 16
INDEX FULL SCAN : Tüm index'in okunarak istenilen kaydın bulunması anlamına geliyor.
INDEX FULL SCAN (MIN/MAX) : Min, Max gibi koşulların olduğu sorguda , INDEX FULL SCAN'in tersine tüm indeksi okumak yerine koşulu sağlar sağlamaz indeksi okumayı bırakıyor.
FULL TABLE SCAN : Tüm tabloyu okuyor.

Bitmap Index
Bitmap Index indekslenecek değerler belli sınırlar içindeyse kullanışlı oluyorlar. Aşağıdaki cümle de bunu özetliyor.

One problem with a bitmap based solution is that even if the sets themselves are very small, but contain very large numbers (or even unbounded) checking bitmaps would be very wasteful.
   
Paralel İşlemler
select /*+ parallel(a,32,8) */ max(parameterinstanceid) from parameterinstance a; 
cümlesinde a tabloya verilen alias. 32 kaç tane thread ile çalışacağını, 8 ise cluster içindeki kaç node'un kullanılacağını belirtiyor.

EXISTS
PL/SQL ile exists kullanmak için alternatifleri buradan görebilirsiniz.

IS NULL
NULL bir sütunun değerinin bilinmediğini gösterir. SQL boolean data type işlemleri yerine, three valued logic kullanır.

Unique Kısıtı
Oracle üzerinde Unique kısıtı konulunca  otomatik olarak bir Index te yaratılıyor.

Sequence
Bir çok veritabanının aksine Oracle otomatik olarak artırılan sütun tipi tanımlatmıyor. Bu tür işler için sequence kullanmak gerekiyor.

Sequence içinde iki tane pseudo column bulunuyor. Bunlara aşağıdaki gibi erişilebilir.
sequence_name.CURRVAL
sequence_name.NEXTVAL
Sequence yaratırken cache veya nocache seçeneği kullanılabilir.

Sequence kullanarak bir başka tabloya satır ekleme örneği ise aşağıda

insert into mytable (myid) values(mySeq.nextVal);

Oracle/PLSQL: Sequences (Autonumber) başlıklı yazıda da  anlatıldığı gibi cache seçeneği kullanılırsa Oracle önceden hazırlanmış bir sayı dizisi oluşturuyor ve daha hızlı cevap veriyor. Ancak cache seçeneğinin dezavantajı Oracle kapatılırsa hazırlanmış olan sayı dizisi kaybediliyor ve dizide boşluklar oluşabiliyor. Eğer nocache seçeneği kullanılırsa dizide boşluklar oluşmaz ancak Oracle her seferinde yeni bir sayı çekmek zorunda kalacağı için biraz daha yavaş çalışır. Performans önemli ve sayı dizisinde boşluklar kabul edelebilir bir durumsa cache seçeneğinin kullanılması daha iyi olur.

sequence yerine max+1
Buradaki soruda sequence yerine max+1 veya coalesce kullanımı tartışılmış.

Inner Join
Konuyu Join Tipleri başlıklı yazıya taşıdım.

Group By
Group by select ile seçilen sütunlardan önce çalışır ve veriyi kümelere ayırır. Daha sonra kümede üzerinde select işlemi yapılır. Aşağıdaki şekili Logical Query Processing Poster'den aldım ve SQL cümlelerinin mantıksal sıralaması görülüyor. Burada Group by'ın Where'den hemen sonra gelen yüksek öncelikli bir işlem olduğu görülebilir.


Grup by ile avg,count, min, max, sum gibi sql fonksiyonları kullanılabilir.

count ile gruptaki elemanların sayısını öğrenmek
Gruplanan sütununa ait kaç tane veri olduğunu görmek için.

Eğer istenirse count(*) ile sayılan satırlar büyükten küçüğe sıralanabilir.

count ile gruptaki eleman sayısı sıfır olanları öğrenmek
Örneği buradan aldım.  

max ile gruptaki en büyük elemanı öğrenmek
Örneği buradan aldım. Bir isme ait en büyük değeri çekiyor.

sum
Örnekte sütun isimleri yerine sütun sıraları kullanılmış ancak sum dışındaki diğer sütunlar group by ifadesinde varlar.

Bir başka örnekte ise iki defa sum kullanılmış. Gruplanan konular, aralıklara bölünerek kaç tane oldukları sayılmış.

ORA-937 not a single-group group function
Eğer bir sütuna SUM yapmak istersek bu hatayı alabiliriz. SUM yapılan sütun dışındaki diğer tüm sütunları group by yaparak gruplamak gerekir. Eğer diğer tüm sütunların sayısı çok fazla ise aşağıdaki örnekte gibi inner join yaparak tüm sütunları yazmaktan da kurtulabiliriz. İçteki SQL içinde iki tane eşleştirme yapılabilecek sütun seçiliyor. Daha sonra bu sütünlar aynı tabloya erişen dışarıdaki SQL'e ile eşleştirme yapmada kullanılıyor.

ROW_NUMBER

Partition By ile Sıralama (Grubun ilk n sayıdaki elemanını çekmek için kullanılır)
Aşağıdaki örnekte veri seti gruplara ayırılıyor ve ayırma işleminde kullanılan her değerin yanına 1'den başlayarak numara veriliyor. Verilen numaralara arasında boşluk olmaz.


İçteki cümle ile veri şöyle gruplanıyor. RN sütununun her grup için birden başladığına dikkat etmek lazım.
ID     URL     RN
1     g     1
1     f     2
1     e     3
1     d     4
1     c     5
1     b     6
1     a     7

11     ga     1
11     fa     2
11     ea     3
11     da     4
11     ca     5
11     ba     6
11     aa     7
Daha sonra her grubun ilk 5 elemanı alınıyor ve aşağıdaki tablo ortaya çıkıyor.
ID     URL
1     g
1     f
1     e
1     d
1     c
11     ga
11     fa
11     ea
11     da
11     ca
ROWNUM
ROWNUM ile ROW_NUM farklı şeyler. ROWNUM sayfalama yapmak için kullanılır. Örneğin sayfada 5 kayıt göstermek istiyorsak aşağıdakine benzer bir cümle kullanırız.

Buradaki örnekte ise MAX fonksiyonu yerine WHERE ROWNUM  < 1 ORDER BY DESC gibi ilginç bir kullanım şekli var.
MySQL veya SQL Server'daki Limit ve Top fonksiyonları yerine ROWNUM kullanılıyor.
Benzer bir açıklama da burada var.

RANK
Rank fonksiyonu aynı tabloyu gruplamak için kullanılabilir.
Partition By ile Sıralama (Grubun ilk n sayıdaki elemanını çekmek için kullanılır)
Aşağıdaki örnekte veri seti gruplara ayırılıyor ve ayırma işleminde kullanılan her değerin yanına 1'den başlayarak numara veriliyor. Verilen numaralara arasında boşluk olabilir.


One-to-many şeklinde kullanımında ise bir kayıt başka bir tablo ile join'de birden çok geliyorsa aynı kayıtlar elemek için kullanılabilir. Örnek:

DENSE_RANK
DENSE_RANK yazısına taşıdım

For Döngüsü
Örnek :
FOR record IN  (SELECT id FROM t_sample where children is null)
LOOP
 INSERT INTO TEST_LOG VALUES (my_sequence.nextVal, record.id);
END LOOP;

Grant
Burada gösterildiği gibi kullanıcılara tablolar için erişim hakkı verilebilir.


Tarih ve Saat Sütun Tipleri
DATE
Yıl, ay, gün, saat,dakika bilgisini saklar. Saniye bilgisini saklamaz. Date nesnesini saate çevirmek için 24 ile çarpmak gerekir. Örnek : to_date metodu da verilen string'i date nesnesine çeviren yardım bir metoddur.


 TIMESTAMP
Yıl, ay, gün, saat,dakika, saniye bilgisini saklar. Saniye bilgisi küsüratlı olabilir ve kaç haneye kadar olduğu sütunu yaratırken seçilir. Örneğin TIMESTAMP(6) 6 haneye kadarlık küsüratta saniye bilgisini saklar. Bu sütun tipinde saat dilimi bilgisi bulunmamakta. Verilen değer aynen geri alınır. Türkiye gibi tek bir saat diliminin bulunduğu ülkelerde rahatlıkla kullanılabilir.

TIMESTAMP WITH TIME ZONE
Bu sütun tipinde saat dilimi bilgisi bulunmakta. Dünyanın bir çok yerindeki müşterilerin kendi saat bilgisini tutmakta kullanılabilir.

TIMESTAMP WITH LOCAL TIME ZONE
Bu sütun tipinde saat saat dilimi bilgisi bulunmamakta. Veritabanı verilen saati kaydederken gönderen session'daki saat dilimi bilgisini kullanarak kendi saat dilimine çevirir.   

TimeStamp tipleri arasındaki farkı gösteren en güzel şekli buradan aldım. Bu şekilde Oracle UTC saat diliminde çalışıyor.
İşlem tarihi Toronto saati ile 21:46. TimeStamp ve TimeStamp With Time Zone sütunları bu bilgiyi gösteriyor ancak İstanbul'dan bağlanan birisi yerel saat ile 04:46'yı görüyor çünkü Oracle session'dan bağlanan kişinin saat dilimi bilgisini alıp çevirerek veriyor.

Isolation Level
ACID yazısına taşıdım.

2 yorum: