whereDate('created_at', $date) kullanımının temiz görünmesine rağmen, büyük tablolarda indeksinizi devre dışı bırakır ve tam tarama yapar.
Sorun
Sorun
Belirli bir günde oluşturulan bildirimleri almak istediğinizi varsayın. Görünürdeki en basit çağrı:
UserNotification::query()
->whereDate('created_at', '2026-04-23')
->get();
Laravel bu SQL sorgusunu oluşturur:
SELECT * FROM user_notifications
WHERE DATE(created_at) =
+----+-------------+--------------------+------+---------+
| id | select_type | table | type | rows |
+----+-------------+--------------------+------+---------+
| 1 | SIMPLE | user_notifications | ALL | 5000000 |
+----+-------------+--------------------+------+---------+
5 bin satırda bunu fark etmeyeceksiniz, ancak 5 milyon satırda durum tamamen değişiyor.
Çözüm
Çözüm
Doğrudan bir aralık kullanarak karşılaştırma yapın:
use Illuminate\Support\Facades\Date;
$start = Date::parse()->startOfDay();
$end = $start->copy()->addDay();
UserNotification::query()
->where(, , $start)
->where(, , $end)
->get();
Şimdi SQL sorgusu şöyle görünür:
SELECT * FROM user_notifications
WHERE created_at >= AND created_at '2026-04-24 00:00:00'
Burada kolon bozulmamış durumda. MySQL, created_at indeksi üzerinde temiz bir aralık taraması yapabilir:
+----+-------------+--------------------+-------+------+
| id | select_type | table | type | rows |
+----+-------------+--------------------+-------+------+
| 1 | SIMPLE | user_notifications | range | 1200 |
+----+-------------+--------------------+-------+------+
Yarım açık aralık (>= başlangıç, < sonraki gün) daha güvenli bir yöntemdir – endOfDay() 23:59:59.999999 ile sona erer ve 23:59:59‘ya karşı karşılaştırma yapmak son saniyeyi kaçırmanıza neden olabilir.
Neden Çalışıyor
Neden Çalışıyor
Bu kavram sargability olarak adlandırılır – “Search ARGument ABLE”. Bir predikat sargable olduğunda, kolon kendisi olarak görünür, bir işlev sarmalanmadan. DATE(col), YEAR(col) veya LOWER(col) yazdığınız anda, optimizer standart bir B-tree indeksini col üzerinde kullanamaz hale gelir.
Aynı tuzak, whereDay(), whereMonth(), whereYear() ve whereTime() için de geçerlidir; bunların hepsi kolonu bir MySQL işlevi içinde sarmalar. Küçük lookup tablolarında kabul edilebilir. Ancak büyüyen log tarzı tablolarda sıkıntılar çıkarır.
Notlar: PostgreSQL, işlevsel bir indeks oluşturmanıza izin verir (CREATE INDEX ON t ((date(created_at)))), böylece whereDate() yine de bir indeksi vurabilir. MySQL’de bu durumda gerçek bir karşılık yoktur; şema yükü oluşturacak kadar karmaşık yapılar var ama bunlar bir aralık filtrelemesi tarafından zaten çözülebiliyor.
Eğitimler genellikle whereDate('created_at', today()) kullanımını teşvik eder. Ben hala aralık formunu tercih ediyorum. Her yerde aynı şekilde okunuyor ve bir indeksin kullanılıp kullanılmayacağını asla merak etmeyeceğim.
Özet
Özet
whereDate() kullanışlıdır ama büyük tablolarda non-sargable’dir, bu da tam tarama gerektirir. created_at‘yı yarı açık bir >= startOfDay() / < range ile karşılaştırın ve indeksi koruyun.
💡 Aynı hikaye whereMonth(), whereYear(), whereDay(), whereTime() için geçerlidir. Eğer kolon bir işlev içinde sarılmışsa, indeksten yararlanamayacağınızı düşünün.
Yazarın Notu
Yazarın Notu
Okuduğunuz için teşekkürler!
Beni dev.to, linkedin üzerinden takip edebilirsiniz, ya da çalışmalarımı github adresinden inceleyebilirsiniz.
Gerçek dünyadan Laravel notları.
Kaynak: Orijinal Makale


