SQL Query Tunning Hakkında

6 Ekim 2019 Pazar

Genellikle Oracle ve Microsoft SQL’de “tuning” den yani “performans artırma / akort yapma” donanım kaynaklı olarak düşünülür. Sunucu üzerinde daha fazla CPU, RAM vb. bileşenlere bakılır. Bir noktaya kadar doğru bir yaklaşımdır. Fakat kullanıcıların özellikle DML sorguları (Örn: Select) çalıştırdığında, bir miktar sunucu performansını etkileyecektir. Peki aynı anda 50 kullanıcı sorgu çalıştırırsa, arka planda raporlar çalışırsa? Durum kötüye gider…

Herhangi bir SQL sorgusu çalıştırıldığında, istenilen bilgiye nasıl ulaşılacağına “Optimizer” adı verilen veri tabanı optimizasyon birleşeni karar veriyor. Oracle, kullanıcılarına tahminler üzerine çalışan “Rule-Based Optimizer” ve daha çok akıl yürütme yöntemi ile çalışan “Cost-Based Optimizer” olmak üzere iki adet optimizasyon seçeneği sunmaktadır.

MS SQL’de de execution plan vb. kontroller ile sorgu anını kontrol edebiliriz. Sorgularda en çok can sıkan kısım, yanlış yazımlarla index’lerin kullanılamaması ve sorgu süresinin giderek artmasıdır.

Aşağıda sık kullanılan query örnekleri var. Bu örneklerde, yanlış kullanımı ve doğru kullanımı beraber yazdım.

HAVING yerine WHERE kullanımı:   
Önerilmez
SELECT product_type_id,
AVG(price)
FROM products
GROUP BY product_type_id
HAVING product_type_id IN ( 1, 2 );

Önerilir
SELECT product_type_id,
AVG(price)
FROM products
WHERE product_type_id IN ( 1, 2 )
GROUP BY product_type_id;

İkincisi işlemin başlangıcında kayıtları sınırlarken, ilkinde tüm kayıtlar için AVG çalıştırılıyor.

UNION yerine UNION ALL kullanımı
Önerilmez
SELECT product_id,
product_type_id,
name
FROM products
UNION
SELECT product_id,
product_type_id,
name
FROM more_products;

Önerilir
SELECT product_id,
product_type_id,
name
FROM products
UNION ALL
SELECT product_id,
product_type_id,
name
FROM more_products;

UNION ALL her iki sorgu sonucunda tüm kayıtları getirirken, UNION tekrarlanan kayıtları elemine ediyor. Bu nedenle, gerçekleşen eleme işleminden dolayı UNION ALL daha hızlıdır ve sistemi yormaz.

IN yerine EXISTS kullanımı:   
Önerilmez
SELECT product_id,
name
FROM products
WHERE product_id IN (
SELECT product_id
FROM purchases );

Önerilir
SELECT product_id,
name
FROM products pr
WHERE EXISTS (
SELECT 1
FROM purchases pu
WHERE pu.product_id = pr.product_id );

IN bir listede aranan verinin olup olmadığını kontrol eder. EXISTS sadece kayıtların varlığını kontrol ederken, IN ise gerçek verileri kontrol eder. Alt sorgularda EXISTS daha iyi sonuçlar verdiğinden tercih edilmelidir.

OR yerine UNION kullanımı:   
Önerilmez
SELECT ...
FROM ps_jrnl_header a
WHERE jrnl_hdr_status = ‘E’
OR EXISTS
( SELECT ‘x’
FROM ps_jrnl_header
WHERE business_unit_js = a.business.unit_js
AND journal_id = a.journal_id
AND unpost_seq = a.unpost_seq
AND jrnl_hdr_status = ‘E’ );

Önerilir
SELECT ...
FROM ps_jrnl_header a
WHERE jrnl_hdr_status = ‘E’
UNION
SELECT ...
FROM ps_jrnl_header a,
ps_jrnl_header b
WHERE a.business_unit_js = b.business.unit_js
AND a.journal_id = b.journal_id
AND a.unpost_seq = b.unpost_seq
AND a.jrnl_hdr_status = ‘E’
AND b.jrnl_hdr_status != ‘E’;

UNION kullanıldığında, optimizer kayıtları getirmek için iki benzer işlem gerçekleştirir. OR yapısında ise optimizer karar verirken daha karmaşık işlemler yapar ve daha az verimli sonuçlara ulaşır.

İndeks kullanımını engelleyen örnek bir sorgu:
Önerilmez
...
WHERE SUBSTR(account_name,1,7) = ‘CAPITAL’

Önerilir
...
WHERE account_name LIKE ‘CAPITAL%’

SUBSTR indeks kullanımını iptal eder.


Share/Bookmark

0 comments :