Plan: motorun yol haritası
SQL Server bir sorguyu çalıştırmadan önce sorgu iyileştirici (optimizer) birçok olası yol arasından en ucuz görüneni seçer. Bu seçim yürütme planıdır. SSMS'te Ctrl+L tahmini planı, Ctrl+M ile açılan “gerçek plan” ise sorguyla birlikte gerçekleşen planı gösterir.
| Operatör | Anlamı | İpucu |
|---|---|---|
| Table / Clustered Index Scan | Tüm tabloyu okur | Büyük tabloda seçici bir filtre varsa şüphelen. |
| Index Seek | İndeks ağacında doğrudan ilgili satırlara gider | Genellikle istediğimiz. |
| Key Lookup | İndekste olmayan sütunlar için ana tabloya geri döner | Çok satırda pahalı; INCLUDE ile kapsayan indeks çözer. |
| Nested Loops | Her dış satır için iç tabloyu arar | Az satırda hızlı. |
| Hash Match | Bellekte karma tablo kurar | Büyük ve sırasız girdilerde. |
| Sort | Sıralar | Belleğe sığmazsa tempdb'ye taşar (spill). |
STATISTICS IO ve TIME
SET STATISTICS IO ON; SET STATISTICS TIME ON; SELECT COUNT(*) FROM orders WHERE YEAR(order_date) = 2024; -- Mesajlar sekmesinde: -- Her tablo için okuma sayıları: Scan count, logical reads, physical reads ... -- Sürenin altında: CPU time, elapsed time
Mantıksal okuma (logical reads), bellekten okunan 8 KB'lık sayfa sayısıdır ve sorgunun ne kadar iş yaptığının en güvenilir ölçüsüdür. Süre, sunucunun o anki yüküne göre değişir; mantıksal okuma değişmez. İyileştirme yaptıktan sonra bu sayının düştüğünü görmelisin.
SARGable koşullar
Bir koşulun indeksi kullanabilmesi için sütun çıplak olmalıdır. Sütunu bir fonksiyona sokarsan motor her satırı hesaplamak zorunda kalır:
| İndeksi kullanamaz | İndeksi kullanır |
|---|---|
WHERE YEAR(order_date) = 2024 | WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01' |
WHERE LEFT(name, 3) = 'Kab' | WHERE name LIKE 'Kab%' |
WHERE price * 1.2 > 1200 | WHERE price > 1000 |
WHERE ISNULL(city, '') = 'Ankara' | WHERE city = 'Ankara' |
-- İki sorgu aynı sonucu verir; yalnızca ikincisi order_date indeksini kullanabilir SELECT COUNT(*) AS adet FROM orders WHERE YEAR(order_date) = 2024; SELECT COUNT(*) AS adet FROM orders WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01';
Gizli tuzaklar
- Örtük dönüşüm: VARCHAR bir sütunu NVARCHAR bir parametreyle (
N'...') karşılaştırmak, sütunun her satırda dönüştürülmesine ve Seek yerine Scan'e yol açabilir. Planda sarı ünlem ile uyarılır. - Parameter sniffing (parametreye göre plan seçimi): Prosedür ilk çağrıldığındaki parametreye göre plan seçilir ve önbellekte kalır. Veri çok dengesizse diğer değerler için kötü bir plan kullanılır. Çözümler:
OPTION (RECOMPILE),OPTIMIZE FOR, sorguyu ayırmak. - Güncel olmayan istatistikler: Optimizer satır sayısını yanlış tahmin eder. Planda “tahmini” ile “gerçek” satır sayısı arasındaki büyük fark bunun işaretidir.