İÇİNDEKİLER
- •Raporlarınız neden tüm tabloyu tarıyor?
- •Neden Index Kullanılamıyor?
- •Sık Görülen Kalıplar ve SARGable Karşılıkları
- •Dinamik Aralıklar: Bu Ay, Geçen Ay, Bugün
- •Aralık Sınırlarında Sık Yapılan Hata: BETWEEN
- •Tarih Sabitlerini Yazmak
- •Bir İstisna: CAST(kolon AS date)
- •Kontrol Listesi
- •Sorgularınızı index’i kullanır hale getirin
“Bu ayın siparişleri”, “dünkü hareketler”, “son 30 günün faturaları”… Tarih filtresi, iş uygulamalarındaki sorguların belki de en yaygın parçasıdır. Ve en sık yapılan performans hatalarından biri de burada saklıdır: tarih kolonunu bir fonksiyonun içine almak. YEAR(SiparisTarihi) = 2026 ya da CONVERT(varchar(10), Tarih, 104) = '16.10.2026' gibi koşullar doğru sonucu verir; ama SQL Server’ın o kolondaki index’i kullanmasını engeller ve tablonun tamamını taramasına yol açar.
Bu yazıda tarih koşullarının neden index’i kullanamadığını, nasıl SARGable (index’le aranabilir) yazılacağını ve tarih aralıklarında sık yapılan sınır hatalarını anlatıyoruz.
Raporlarınız neden tüm tabloyu tarıyor?
Aryasoft, yavaş sorguları execution plan'larıyla birlikte inceler; SARGable olmayan koşulları ve eksik index'leri bularak düzeltir.
Neden Index Kullanılamıyor?
Bir index, kolonun ham değerlerine göre sıralıdır. SiparisTarihi üzerindeki index, tarihleri sırayla tutar; ama YEAR(SiparisTarihi) değerlerini tutmaz. Koşulda kolon bir fonksiyonun içinde olduğunda SQL Server, her satır için fonksiyonu hesaplayıp sonucu karşılaştırmak zorundadır; bu da index seek yerine index ya da tablo taraması demektir.
Kural basittir: kolonu yalnız bırakın, hesaplamayı karşı tarafa taşıyın.
Sık Görülen Kalıplar ve SARGable Karşılıkları
-- KÖTÜ: yıl
WHERE YEAR(SiparisTarihi) = 2026
-- İYİ
WHERE SiparisTarihi >= '20260101' AND SiparisTarihi < '20270101'
-- KÖTÜ: ay
WHERE YEAR(SiparisTarihi) = 2026 AND MONTH(SiparisTarihi) = 10
-- İYİ
WHERE SiparisTarihi >= '20261001' AND SiparisTarihi < '20261101'
-- KÖTÜ: son 30 gün (hesaplama kolon tarafında)
WHERE DATEADD(DAY, 30, SiparisTarihi) >= GETDATE()
-- İYİ: hesaplama sabit tarafta
WHERE SiparisTarihi >= DATEADD(DAY, -30, GETDATE())
-- KÖTÜ: metne çevirerek karşılaştırma
WHERE CONVERT(varchar(8), SiparisTarihi, 112) = '20261016'
-- İYİ
WHERE SiparisTarihi >= '20261016' AND SiparisTarihi < '20261017'
Dinamik Aralıklar: Bu Ay, Geçen Ay, Bugün
Aralık sınırlarını değişkenlerde bir kez hesaplayın, sonra kolonu bu değişkenlerle karşılaştırın:
DECLARE @bugun date = CAST(GETDATE() AS date);
DECLARE @ayBasi date = DATEFROMPARTS(YEAR(@bugun), MONTH(@bugun), 1);
DECLARE @gecenAyBasi date = DATEADD(MONTH, -1, @ayBasi);
-- Bu ayın siparişleri
SELECT SiparisNo, Tutar FROM dbo.Siparis
WHERE SiparisTarihi >= @ayBasi AND SiparisTarihi < DATEADD(MONTH, 1, @ayBasi);
-- Geçen ayın siparişleri
SELECT SiparisNo, Tutar FROM dbo.Siparis
WHERE SiparisTarihi >= @gecenAyBasi AND SiparisTarihi < @ayBasi;
-- Bugünkü siparişler
SELECT SiparisNo, Tutar FROM dbo.Siparis
WHERE SiparisTarihi >= @bugun AND SiparisTarihi < DATEADD(DAY, 1, @bugun);
Aralık Sınırlarında Sık Yapılan Hata: BETWEEN
BETWEEN her iki ucu da dahil eder. Saat bilgisi içeren bir kolonda BETWEEN '20261001' AND '20261031', 31 Ekim’in yalnızca gece yarısındaki kayıtları alır ve günün geri kalanını kaçırır. Bunu düzeltmek için '20261031 23:59:59' yazmak da güvenli değildir: datetime’ın hassasiyeti nedeniyle 23:59:59.997 değeri yuvarlanabilir, datetime2’de ise 23:59:59 ile 24:00 arasındaki kayıtlar kaçar.
Uyarı
Tarih aralıklarında her zaman “başlangıç dahil, bitiş hariç” kalıbını kullanın: Tarih >= başlangıç AND Tarih < bitişten sonraki gün. Bu kalıp kolonun tipi (date, datetime, datetime2) ve hassasiyeti ne olursa olsun doğru çalışır ve index'i kullanır.
Tarih Sabitlerini Yazmak
'16.10.2026' ya da '10/16/2026' gibi biçimler, oturumun dil ve DATEFORMAT ayarına göre farklı yorumlanabilir; bir sunucuda çalışan sorgu başka bir sunucuda hata verebilir ya da yanlış ayı alabilir. Dilden bağımsız biçimleri kullanın: '20261016' (yalnızca tarih) ya da '2026-10-16T14:30:00' (tarih ve saat).
Bir İstisna: CAST(kolon AS date)
datetime ya da datetime2 bir kolonu date tipine çevirmek, SQL Server’ın özel olarak tanıdığı bir durumdur ve index seek yapılabilir. Yine de tahmin edilen satır sayısı daha az isabetli olabilir; aralık kalıbı hem okunabilirlik hem de plan kalitesi açısından daha güvenli bir alışkanlıktır.
İpucu
Fonksiyonu sorgudan kaldıramıyorsanız (örneğin bir raporlama aracı sürekli YEAR(Tarih) ile filtreliyorsa), persisted bir hesaplanmış kolon oluşturup onu index’leyebilirsiniz: ALTER TABLE dbo.Siparis ADD SiparisYili AS YEAR(SiparisTarihi) PERSISTED; ardından bu kolon üzerinde bir index. Hesaplanmış kolon index’leri için oturumun SET seçeneklerinin doğru olması gerektiğini unutmayın.
Kontrol Listesi
- WHERE koşullarında tarih kolonu fonksiyon içinde değil.
- Aralıklar “başlangıç dahil, bitiş hariç” kalıbıyla yazılmış; BETWEEN tarih-saat kolonlarında kullanılmıyor.
- Dinamik sınırlar değişkenlerde bir kez hesaplanıyor.
- Tarih sabitleri dilden bağımsız biçimde (YYYYMMDD) yazılmış.
- Execution plan’da tarih filtresinde index seek görülüyor.
Kolon bir fonksiyonun içinde olduğu için SQL Server index’i kullanamaz ve her satırda fonksiyonu hesaplar. Bunun yerine tarih >= ‘20260101’ AND tarih < '20270101' yazın.[/arya_faq_item]
[arya_faq_item q="SARGable ne demek?"]Search ARGument-able; koşulun index seek ile değerlendirilebilmesi demektir. Kolonun fonksiyon ya da hesaplama içine alınmaması gerekir.[/arya_faq_item]
[arya_faq_item q="Tarih aralığında BETWEEN kullanmalı mıyım?"]Saat bilgisi içeren kolonlarda hayır. tarih >= başlangıç AND tarih < bitişten sonraki gün kalıbı her tip ve hassasiyette doğru sonuç verir.[/arya_faq_item]
[arya_faq_item q="SQL Server'da tarih sabiti nasıl yazılmalı?"]Dilden bağımsız YYYYMMDD biçiminde ('20261016') ya da ISO 8601 biçiminde ('2026-10-16T14:30:00').[/arya_faq_item]
[/arya_faq]
İlgili Yazılar
SQL Server Performans Danışmanlığı
Sorgularınızı index’i kullanır hale getirin
Aryasoft’un kıdemli DBA ekibi yavaş sorguları execution plan’larıyla inceler; SARGable olmayan koşulları, örtük dönüşümleri ve eksik index’leri bularak sorgularınızı ölçülebilir şekilde hızlandırır.