Entity Framework - Performance Optimization¶
Giriş¶
Entity Framework'te performans optimizasyonu, uygulamanın veritabanı işlemlerini daha hızlı ve verimli bir şekilde gerçekleştirmesini sağlar. Mid-level geliştiriciler için performans optimizasyonu kritik bir konudur.
Performance Optimization'un Önemi¶
- Uygulama Performansı
- Daha hızlı sorgu yanıt süreleri
- Daha az kaynak kullanımı
- Daha iyi kullanıcı deneyimi
-
Daha yüksek ölçeklenebilirlik
-
Veritabanı Yükü
- Daha az veritabanı yükü
- Daha verimli sorgu planları
- Daha az network trafiği
-
Daha iyi kaynak yönetimi
-
Maliyet Optimizasyonu
- Daha az donanım gereksinimi
- Daha düşük işlem maliyetleri
- Daha verimli kaynak kullanımı
- Daha iyi ROI
Performance Optimization Stratejileri¶
-
Query Optimizasyonu
// Kötü örnek: N+1 problemi var blogs = await _context.Blogs.ToListAsync(); foreach (var blog in blogs) { var posts = await _context.Posts.Where(p => p.BlogId == blog.Id).ToListAsync(); } // İyi örnek: Eager loading var blogs = await _context.Blogs .Include(b => b.Posts) .ToListAsync(); // İyi örnek: Projection var blogTitles = await _context.Blogs .Select(b => new { b.Id, b.Title }) .ToListAsync(); // İyi örnek: Compiled query private static readonly Func<ApplicationDbContext, int, Task<Blog>> GetBlogById = EF.CompileAsyncQuery((ApplicationDbContext context, int id) => context.Blogs.FirstOrDefault(b => b.Id == id));
-
Change Tracking Optimizasyonu
// Kötü örnek: Gereksiz change tracking var blogs = await _context.Blogs.AsTracking().ToListAsync(); // İyi örnek: No tracking var blogs = await _context.Blogs.AsNoTracking().ToListAsync(); // İyi örnek: Selective tracking var blog = await _context.Blogs .AsNoTracking() .FirstOrDefaultAsync(b => b.Id == id); _context.Entry(blog).State = EntityState.Modified;
-
Bulk Operasyonlar
// Kötü örnek: Tek tek ekleme foreach (var entity in entities) { await _context.AddAsync(entity); await _context.SaveChangesAsync(); } // İyi örnek: Bulk insert await _context.BulkInsertAsync(entities); // İyi örnek: Batch processing var batchSize = 100; for (var i = 0; i < entities.Count; i += batchSize) { var batch = entities.Skip(i).Take(batchSize); await _context.BulkInsertAsync(batch); }
-
Caching Stratejileri
// Memory cache kullanımı public class CachedRepository<T> where T : class { private readonly IMemoryCache _cache; private readonly ApplicationDbContext _context; private readonly string _cacheKey; public CachedRepository(IMemoryCache cache, ApplicationDbContext context) { _cache = cache; _context = context; _cacheKey = typeof(T).Name; } public async Task<T> GetByIdAsync(int id) { var cacheKey = $"{_cacheKey}-{id}"; return await _cache.GetOrCreateAsync(cacheKey, async entry => { entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(5)); return await _context.Set<T>().FindAsync(id); }); } } // Distributed cache kullanımı public class DistributedCachedRepository<T> where T : class { private readonly IDistributedCache _cache; private readonly ApplicationDbContext _context; private readonly string _cacheKey; public DistributedCachedRepository(IDistributedCache cache, ApplicationDbContext context) { _cache = cache; _context = context; _cacheKey = typeof(T).Name; } public async Task<T> GetByIdAsync(int id) { var cacheKey = $"{_cacheKey}-{id}"; var cachedData = await _cache.GetStringAsync(cacheKey); if (cachedData != null) { return JsonSerializer.Deserialize<T>(cachedData); } var data = await _context.Set<T>().FindAsync(id); await _cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(data), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5) }); return data; } }
-
Index Yönetimi
// Index tanımlama protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => b.Title) .IsUnique(); modelBuilder.Entity<Post>() .HasIndex(p => new { p.BlogId, p.PublishedDate }) .IncludeProperties(p => new { p.Title, p.Content }); } // Index kullanımı var blogs = await _context.Blogs .Where(b => b.Title.StartsWith("A")) .OrderBy(b => b.Title) .ToListAsync();
Performance Monitoring¶
-
Query Logging
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer(connectionString) .EnableSensitiveDataLogging() .LogTo(Console.WriteLine, LogLevel.Information); }
-
Performance Metrics
public class PerformanceMonitor { private readonly Stopwatch _stopwatch = new Stopwatch(); public async Task<T> MeasureQuery<T>(Func<Task<T>> query) { _stopwatch.Start(); var result = await query(); _stopwatch.Stop(); Console.WriteLine($"Query executed in {_stopwatch.ElapsedMilliseconds}ms"); _stopwatch.Reset(); return result; } }
Best Practices¶
- Query Tasarımı
- Eager loading kullanımı
- Projection kullanımı
- Compiled query kullanımı
- Batch processing
-
Pagination
-
Change Tracking
- No tracking kullanımı
- Selective tracking
- Bulk operasyonlar
- Batch updates
-
Optimistic concurrency
-
Caching
- Memory cache
- Distributed cache
- Cache invalidation
- Cache duration
-
Cache size
-
Indexing
- Index tasarımı
- Index maintenance
- Index fragmentation
- Index statistics
- Query plan analysis
Mülakat Soruları¶
Temel Sorular¶
- Entity Framework'te N+1 problemi nedir ve nasıl çözülür?
-
Cevap: N+1 problemi, bir ana sorgu ve her bir kayıt için ayrı bir sorgu yapılması durumudur. Eager loading, projection veya compiled query kullanılarak çözülebilir.
-
Entity Framework'te change tracking nedir ve nasıl optimize edilir?
-
Cevap: Change tracking, entity'lerdeki değişikliklerin takip edilmesi sürecidir. AsNoTracking() kullanarak veya selective tracking ile optimize edilebilir.
-
Entity Framework'te bulk operasyonlar nasıl yapılır?
-
Cevap: Bulk operasyonlar, toplu veri işlemleri için kullanılır. BulkInsert, BulkUpdate, BulkDelete gibi metodlar veya batch processing ile yapılabilir.
-
Entity Framework'te caching stratejileri nelerdir?
-
Cevap: Memory cache, distributed cache, query result caching gibi stratejiler kullanılabilir.
-
Entity Framework'te index yönetimi nasıl yapılır?
- Cevap: OnModelCreating metodunda HasIndex kullanılarak veya migration'lar ile yapılabilir.
Teknik Sorular¶
- Query optimizasyonu için hangi stratejileri kullanırsınız?
-
Cevap:
// Eager loading var blogs = await _context.Blogs .Include(b => b.Posts) .ToListAsync(); // Projection var blogTitles = await _context.Blogs .Select(b => new { b.Id, b.Title }) .ToListAsync(); // Compiled query private static readonly Func<ApplicationDbContext, int, Task<Blog>> GetBlogById = EF.CompileAsyncQuery((ApplicationDbContext context, int id) => context.Blogs.FirstOrDefault(b => b.Id == id));
-
Change tracking optimizasyonu nasıl yapılır?
-
Cevap:
// No tracking var blogs = await _context.Blogs.AsNoTracking().ToListAsync(); // Selective tracking var blog = await _context.Blogs .AsNoTracking() .FirstOrDefaultAsync(b => b.Id == id); _context.Entry(blog).State = EntityState.Modified;
-
Bulk operasyonlar nasıl yapılır?
-
Cevap:
// Bulk insert await _context.BulkInsertAsync(entities); // Batch processing var batchSize = 100; for (var i = 0; i < entities.Count; i += batchSize) { var batch = entities.Skip(i).Take(batchSize); await _context.BulkInsertAsync(batch); }
-
Caching nasıl implemente edilir?
-
Cevap:
public class CachedRepository<T> where T : class { private readonly IMemoryCache _cache; private readonly ApplicationDbContext _context; public async Task<T> GetByIdAsync(int id) { var cacheKey = $"{typeof(T).Name}-{id}"; return await _cache.GetOrCreateAsync(cacheKey, async entry => { entry.SetAbsoluteExpiration(TimeSpan.FromMinutes(5)); return await _context.Set<T>().FindAsync(id); }); } }
-
Index yönetimi nasıl yapılır?
- Cevap:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Blog>() .HasIndex(b => b.Title) .IsUnique(); modelBuilder.Entity<Post>() .HasIndex(p => new { p.BlogId, p.PublishedDate }) .IncludeProperties(p => new { p.Title, p.Content }); }
İleri Seviye Sorular¶
- Entity Framework'te query plan cache nasıl yönetilir?
-
Cevap:
- Query plan cache stratejileri
- Plan cache invalidation
- Plan cache monitoring
- Plan cache optimization
- Plan cache troubleshooting
-
Entity Framework'te memory leak nasıl önlenir?
-
Cevap:
- Change tracking yönetimi
- Connection pooling
- Resource cleanup
- Memory profiling
- Garbage collection
-
Entity Framework'te distributed sistemlerde performans nasıl optimize edilir?
-
Cevap:
- Caching stratejileri
- Query routing
- Load balancing
- Data partitioning
- Replication
-
Entity Framework'te high concurrency senaryolarında performans nasıl optimize edilir?
-
Cevap:
- Optimistic concurrency
- Pessimistic concurrency
- Retry mekanizmaları
- Queue yönetimi
- Batch processing
-
Entity Framework'te monitoring ve profiling nasıl yapılır?
- Cevap:
- Query logging
- Performance metrics
- Resource monitoring
- Profiling tools
- Health checks