Veri katmanı ve SQL
LINQ’ten SQL’e: EF Core sorguyu nasıl çevirir?
Hangi kısım veritabanında, hangi kısım bellekte çalışır ve üretilen SQL nasıl okunur?
Kavramı anlayalım
EF Core’da yazdığın LINQ sorgusu hemen çalışmaz; bir ifade ağacı olarak birikir. ToListAsync, SingleAsync, CountAsync gibi bir sonlandırıcı çağrıldığında EF Core bu ağacı SQL’e çevirir, parametreleri ekler ve veritabanına gönderir. Where, OrderBy, Select, Take gibi işlemler SQL’e dönüşür ve veritabanında çalışır.
Select ile projeksiyon yapmak, yalnız ihtiyaç duyulan kolonları getirir. Bütün entity’yi çekip bellekte birkaç alan kullanmak, ağ üzerinden gereksiz veri taşır ve büyük metin kolonlarında ciddi fark yaratır. Projeksiyonla oluşturulan DTO’lar izlenmez; okuma uç noktaları için en verimli yoldur.
Çevrilemeyen bir ifade (örneğin kendi yazdığın bir C# metodu) Where içinde kullanılırsa EF Core hata verir; sorgunun sessizce belleğe çekilip orada filtrelenmesine izin vermez. Üretilen SQL’i görmek için ToQueryString() veya geliştirme ortamında EF Core günlük kaydı kullanılır. SQL’i okumayı alışkanlık haline getirmek, performans sorunlarını üretime çıkmadan yakalatır.
Aynı sonucu veren iki LINQ sorgusu, çok farklı SQL ve maliyet üretebilir.
ToList()’i sorgunun başında çağırıp filtreleme ve sayfalamayı bellekte yapmak.
Bir mektubun şehirdeki yolculuğu
İsteği bir mektup, sunucuyu bir şehir gibi düşün. Senaryo seç, oynat ve mektubun hangi kapıdan geçip nerede durdurulduğunu izle.
Bir yazıya tıkladın. Tarayıcı ‘Bana bu yazıyı gönder’ diyen bir mektup yazıyor.
Aynı konu. Üç farklı derinlik.
var titles = await db.Posts
.Where(p => p.IsPublished)
.OrderByDescending(p => p.PublishedAtUtc)
.Select(p => p.Title)
.Take(5)
.ToListAsync(ct);
// SELECT TOP(@p) [p].[Title] FROM [Posts] AS [p]
// WHERE [p].[IsPublished] = 1 ORDER BY [p].[PublishedAtUtc] DESCBütün zincir tek bir SQL sorgusuna dönüşür ve veritabanında çalışır.
Bu sayfa gerçek bir sunucuya veya veritabanına bağlanmaz. Kod örnekleri .NET 8, Next.js ve SQL Server için temsilîdir; süreler simülasyondaki örnek değerlerdir, ölçüm değildir. Örnekleri yalnız kendi geliştirme ortamında dene; gerçek bağlantı dizesi, token veya parola paylaşma.
Önce kendin dene.
Liste sayfası yalnız başlık ve tarih gösteriyor, ama sorgu Content kolonunu (ortalama 40 KB) da getiriyor. 20 yazılık bir sayfada ne kadar gereksiz veri taşınıyor ve nasıl düzeltirsin?
Çözümü ve açıklamasını göster
≈ 20 × 40 KB = 800 KB gereksiz veri (her sayfa açılışında).
Düzeltme: .Select(p => new PostListItem(p.Title, p.PublishedAtUtc))Projeksiyon, SQL’in SELECT listesini daraltır; veritabanı, ağ ve bellek yükü birlikte düşer.