Indeks var ama neden kullanılmıyor ?
Durum 1 : T tablomuzda “x” ve “y” kolonlarımız olsun ve “idx_t(x,y)” şeklinde de bir indeksimiz oldugunu düşünelim.( concatenated index).Bu index ‘i kullanabilmek için “where” koşulundan sonra bu kolonları :
“….where x = :X and y = :Y” şeklinde ya da “…where x = :X” şeklinde , indeksin kullanılmasını sağlamış oluruz.
”…where y=:Y” durumunda ise indeks kullanılmayacaktır.Indeksli kolonlar T(x, y, z) ise indekten faydalanmak için “where” koşulundan sonra aşağıdaki kolon sırası takip edilirse indeks kullanılır :
(x, y, z)
(x,y)
(x)
(x,z), (y,z) gibi kombinasyonlarda indeks kullanılmaz.(Cost Based Optimizer kullanıldıgını düşünüyoruz)Durum 2 : T tablomuzda “x” kolonu üzerinde indeks oldugu düşünelim.
select count(*) from T , işleminde indeks üzerinden gitmesini beklerken FTS yapmış oldugunu görebiliriz.Bunun muhtemel sebebi indeks oluşturulan “x” kolonu “NULL” içermesi olabilir.NULL içeren kolon değerleri için indeks oluşturulmayacağını görmüştük.Bu durumda Oracle mantıklı olan FTS yapmayı tercih edecektir.
Durum 3 : select * from T where func(indexed_col) = value , gibi bir durumda indeks kullanılamaz.Indeks oluşturulan kolonlar için fonksiyon kullanıldıgında indeks işe yaramaz.Çünkü fonksiyonun değerine değil , fonksiyona parametre olan kolon üzerinde indeks vardır.Eğer buna ihtiyaç var ise “function-based index” kullnılmasında fayda var.
Durum 4 : Bir karakter kolonu indekslediğimizi düşünelim.Aşağıdaki gibi bir sorguda :
select * from T where indexed_col = 5 , indeks kullanılmayacaktır.Çünkü bu sorgu select * from T where to_number(indexed_col) = 5, ile aynıdır.Bu durumuda (Durum 3)’ te açıklamıştık.Bunu genelleyecek olursa implicit olarak yapılan karakter dönüşümlerine engel olunmaz ise indekste kullanılamaz.Benzer bir durum tarih alanları üzerinde indeks oluşturulduğunda karşımıza çıkar.
select * from T where trunc(indexed_date_col) = trunc(sysdate);
indeks TRUNC fonksiyonu sebebi ile yine kullanılamaz.Bu sorgu yerine :
…. indexed_date_col between trunc(sysdate) and trunc(sysdate)plus one mınus one second;
ya da
select * from t where indexed_date_col between trunc(sysdate) and trunc(sysdate) +1 – 1(1*24*60*60)
kullanılmalıdır.Bununla birlikte yukarıdaki 2 yöntemde, değer bir kez hesaplanıp indeks üzerinden gidilirken
“…where trunc(indexed_date_col) = trunc(sysdate);” durumunda ,her satır için trunc(indexed_date_col) hesaplanacaktır.
DURUM 5 : Indeks var ama hala kullanmıyorsam, bunun bir başka sebebi de CBO için gerekli olan istatistikleri toplamamış olmamız olabilir.Bir tablo oluşturulduktan sonra belli zamanlarda ilgili istatistikleri (tablo, kolon, indeksler vs..) toplamamız gerekiyor.Ancak bu sayede CBO en iyi çözümü bulabilir.Indeks buluna bir tabloda indeksli kolon için, tablo küçük iken FTS tercih etmesi doğal olabilir.Ama tablo büyüdükçe indeks range scan ile daha performanlı sorgu yapılabilir.ancak CBO, buna ancak elinde dogru bilgi olursa karar verebilir.
DURUM 6 : “CBO için gerekli istatistikleri de topladım ama indeks yerine hala FTS yapılıyor “ , boyle bir durumda gercekten dogru olan FTS olabilir.Örneğin 1000 kayıtlı bir tablo da indeksli kolon üzerinden 250 kaydı sorgulamak istediğimde , indekse gidip oradan tabloya erişim yapılacağına dogrudan tabloya gidip FTS yapmak daha az maliyetli olacaktır.Bu tablodaki veri sayısı örneğin 100.000’e ulaştıgında aynı sorgu için FTS yapması gariptir, bakılması gerekir.
Hakkı Oktay
http://hakkioktay.wordpress.com
|