Ana içeriğe geç
Kesit SQL
İleri · T-SQL (SQL Server)

Yürütme planı ve STATISTICS IO: sorgu neden yavaş?

Plan operatörleri, mantıksal okuma, SARGable koşullar ve parameter sniffing.

Uygulamada aç, 6 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

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örAnlamıİpucu
Table / Clustered Index ScanTüm tabloyu okurBüyük tabloda seçici bir filtre varsa şüphelen.
Index Seekİndeks ağacında doğrudan ilgili satırlara giderGenellikle 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 LoopsHer dış satır için iç tabloyu ararAz satırda hızlı.
Hash MatchBellekte karma tablo kurarBüyük ve sırasız girdilerde.
SortSıralarBelleğ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) = 2024WHERE order_date >= '2024-01-01' AND order_date < '2025-01-01'
WHERE LEFT(name, 3) = 'Kab'WHERE name LIKE 'Kab%'
WHERE price * 1.2 > 1200WHERE 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

Query StoreSQL Server 2016+'da sorguların plan geçmişini ve performansını saklar. “Dün hızlıydı, bugün yavaş” sorununda hangi planın değiştiğini gösterir ve eski planı zorlamana izin verir.
Alıştırmalara geç (6)