Özet: Doğru ve performanslı sorgu(SQL) yazmanın ipuçları ve dikkat edilmesi gereken noktalar anlatılıyor.
Yazılan sql’lerin sadece istediğimiz sonucu veriyor olması yetmez, aynı zamanda iyi performans gösteriyor olması lazım. Yani sorunlu sql’ler veritabanımızda çok fazla kaynak tüketebileceği gibi çok uzun sürelerde çalışır, hatta bir türlü bitmez.
Eğer bu tarz birkaç sorunlu sql çok maliyetli olup aynı zaman diliminde çalışıyorsa, veritabanı kaynak sıkıntısından dolayı yeni gelecek session’lara cevap veremez duruma gelebilir.
Veritabanının sağlığı, stabil çalışabilmesi açısından sürekli olarak sql’ler izlenmeli, sorunlu olan sql’ler tespit edilip müdahale edilmelidir. Bu anlamda ilk olarak sql’i yazan yazılımcının(developer) performanslı sql yazma konusunda dikkat etmesi önemlidir!
Sql’in çalışma performansı, Dev/Test/Prelive ortamlarda test edilmeden Prod (Üretim-Canlı) ortama alınmamalıdır!
“SQL Performanslarında Dikkat Edilmesi Gerekenler” başlığı ile seri olarak blog yazılarımızı paylaşıyor olacağız.
Bu ilk seride aşağıdaki doğru/yanlış sql örneklerini inceleyelim:
1- a) daki kullanımda tablodaki tüm kayıtların ortalaması alınıp daha sonra koşul kullanılıyor ancak b) deki
kullanımda belli bir koşuldaki kayıtların sadece ortalaması alınıyor. Dolayısıyla b) deki doğrudur.
a) -> YANLIŞ KULLANIM
SELECT product_type_id, AVG(price) FROM products GROUP BY product_type_id HAVING product_type_id IN ( 1, 2 );
b) -> DOĞRU KULLANIM
SELECT product_type_id, AVG(price) FROM products WHERE product_type_id IN ( 1, 2 ) GROUP BY product_type_id;
2- Sorgu sonucu tekrarlı olanları görüntülememek için “DISTINCT” kullanılır.
“EXISTS” ise bir alt sorguda gelen kayıtlar içinde istenilenlerin olup olmadığını kontrol eder.
DISTINCT, gelen sonuçlarda tekrarlı olanları belirlemeden önce sıralama yaptığıdan verimsizdir ve bu yüzden de EXISTS tercih edilmelidir.
a) -> YANLIŞ KULLANIM
SELECT DISTINCT product_id, name FROM products a, purchase b WHERE a.product_id = b.product_id;
b) -> DOĞRU KULLANIM
SELECT product_id, name FROM products a WHERE EXISTS (SELECT 1 FROM purchase b WHERE a.product_id = b.product_id);
3- a) daki kullanımda tablonun “kart_no” kolonundaki tüm kayıtlarını şifreleyip daha sonra değerimizle eşitleniyor, b) deki kullanımda ise olması gerektiği gibi değerimizi şifreledikten sonra tabloda aratıyoruz
a) -> YANLIŞ KULLANIM
select * from onemli_tablo where enc_dec_pkg.get_enc_val(kart_no)='10000000000000002';
b) -> DOĞRU KULLANIM
select * from onemli_tablo where kart_no=enc_dec_pkg.get_enc_val('10000000000000002');
4- Aşağıdaki “NOT”, “!=”, “<>”, “TRUNC”, “SUBSTR”, “||(concatenate)” kullanım örnekleri index kullanımını iptal edeceği için dikkat edilmeli!
a) -> Önerilmez
WHERE account != '0'
b) -> Önerilir
WHERE account > '0'
———————————————–
a) -> Önerilmez
WHERE TRUNC(tarih) = TRUNC(sysdate)
b) -> Önerilir
WHERE tarih BETWEEN TRUNC(sysdate) AND TRUNC(sysdate) + 1
———————————————–
a) -> Önerilmez
WHERE SUBSTR(name,1,5) = 'ahmet'
b) -> Önerilir
WHERE name LIKE 'ahmet%'
———————————————–
a) -> Önerilmez
WHERE name || surname = 'ahmet'
b) -> Önerilir
WHERE name = 'ahmet' AND surname = 'bulut'
———————————————–
* Kolon eşitliğin her iki tarafında da kullanılırsa index kullanımı iptal olur
a) -> Önerilmez
WHERE name = NVL (a_name, name)
b) -> Önerilir
WHERE name LIKE NVL (a_name, '%')