Veritabanı Query Profiling: 100K Dolarlık Optimizasyon Yolculuğu

Sistematik veritabanı profiling ve optimizasyonu ile yıllık altyapı maliyetlerini 100K dolar azalttığımız hikaye. PostgreSQL ve MongoDB performance deneyimleri.

Hiç üç aylık maliyet değerlendirmelerinden birinde AWS faturası odadaki herkesi sessizliğe gömecek cinsten mi? Ben yaşadım. Üç yıl önce, veritabanı altyapımız Series A fonlaması alan bir startup'tan bile daha hızlı para yakıyordu. Aylık maliyetler 5.400 dolara kadar çıkmıştı, query'ler yoğun trafik sırasında timeout alıyor, en hızlı "çözümümüz" her zaman "daha fazla sunucu ekle" oluyordu.

Bu durum, veritabanı problemlerine donanım fırlatmanın kahve fincanını yangın hortumu ile doldurmaya benzer bir şey olduğunu - pahalı, dağınık ve şaşırtıcı derecede etkisiz - anlamadan önceydi.

İşte 64.800 dolarlık yıllık altyapı kabusumuzu 28.800 dolarlık iyi çalışan bir makineye nasıl dönüştürdüğümüz ve PostgreSQL ile MongoDB ortamlarında sistematik veritabanı optimizasyonu hakkında öğrendiklerim.

Problem: Performance Gerçekle Karşılaştığında#

Size bir tablo çizeyim. PostgreSQL (işlemsel data için) ve MongoDB (analitik ve döküman depolaması için) içeren multi-tenant SaaS platformu işletiyorduk. Kağıt üzerinde mimarimiz sağlamdı. Pratikte? Black Friday trafiği sırasında ürün arama query'lerimiz 8 saniye sürmesi dışında elbette.

Kopma noktası Q3 board sunumumuz sırasında geldi. CEO'muz yeni dashboard özelliklerini sergilerken, müşteri analitiklerini gösteren masum bir query'nin yüklenmesi 45 saniye sürdü. Tüm board üyelerinin önünde. Sessizlik sağır ediciydi.

İşte o zaman yama çözümlerden fazlasına ihtiyacımız olduğunu anladım. Veritabanlarımızın içinde gerçekte neler olup bittiğini anlayacak sistematik bir yaklaşıma ihtiyacımız vardı.

Olmayan Büyük MongoDB Migration'ı#

İşe yarayan şeyleri paylaşmadan önce, işe yaramayanlardan bahsedeyim. Altı ay önce, MongoDB'nin tüm scaling sorunlarımızı çözeceğine ikna olmuş halde, ana ürün katalogumuzu PostgreSQL'den MongoDB'ye migrate ettik. "NoSQL büyümemizi daha iyi handle eder," diye düşünmüştük. "Döküman depolaması API response'larımıza mükemmel match eder."

Üç ay ve 2 kat daha yüksek AWS faturaları sonra, SQL düşünüşünü NoSQL dünyasına getirmiş olduğumuzu fark ettik. Uygulamamız MongoDB aggregation pipeline'ları olması gereken karmaşık join'leri memory'de yapıyordu. Query performansı aslında öncekinden 3 kat daha kötüydü.

Ders? Veritabanı teknolojisi migration'ları kötü tasarlanmış query'leri sihirli bir şekilde düzeltmez. Önce erişim pattern'larınızı anlamanız, sonra doğru aracı seçmeniz gerekir.

Sistematik Profiling Framework Kurma#

Board meeting felaketi sonrasında, sonraki ayı "veritabanı gerçek sistemi" diyeceğim şeyi kurmakla geçirdim – performansımızın ve paramızın nereye gittiğini tam olarak gösterecek PostgreSQL ve MongoDB'de kapsamlı profiling.

PostgreSQL Profiling Stack#

İlk olarak, 100ms'den fazla süren her şeyi yakalamak için detaylı query logging'i etkinleştirdim:

SQL
-- Kapsamlı query logging'i etkinleştir
ALTER SYSTEM SET log_min_duration_statement = 100;
ALTER SYSTEM SET log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h ';
ALTER SYSTEM SET log_checkpoints = on;
ALTER SYSTEM SET log_connections = on;
ALTER SYSTEM SET log_disconnections = on;
ALTER SYSTEM SET log_lock_waits = on;
SELECT pg_reload_conf();

Sonra gerçek tabloyu görmek için pg_stat_statements kullandım:

SQL
-- Kaynak yiyen query'leri bul
SELECT 
    substring(query, 1, 100) as query_start,
    calls,
    total_time,
    mean_time,
    rows,
    100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS cache_hit_percent
FROM pg_stat_statements 
ORDER BY total_time DESC 
LIMIT 20;

Sonuçlar göz açıcıydı. En üstteki query'imiz toplam veritabanı zamanının %30'unu tüketiyordu ve cache hit oranı sadece %12'ydi. Birisi ürünleri kategoriye göre filtrelediğinde 50 milyonluk tabloyu her seferinde scan ediyordu.

MongoDB Profiling Configuration#

MongoDB için, 100ms üzerindeki operasyonları yakalamak için profiler'ı etkinleştirdim:

JavaScript
// Yavaş operasyonlar için profiler'ı etkinleştir
db.setProfilingLevel(2, { slowms: 100 });

// Pattern'ları analiz et
db.system.profile.aggregate([
  { $match: { ns: "myapp.products" } },
  { $group: {
      _id: "$command.find",
      count: { $sum: 1 },
      avgDuration: { $avg: "$millis" },
      maxDuration: { $max: "$millis" },
      totalDuration: { $sum: "$millis" }
    }
  },
  { $sort: { totalDuration: -1 } },
  { $limit: 10 }
]);

Bu şok edici bir şey ortaya çıkardı: saniyeler içinde process edilmesi gereken veriyi 12 dakikada işleyen aggregation pipeline'larımız vardı. Suçlu? MongoDB'nin built-in aggregation framework'ünü kullanmak yerine uygulama seviyesinde join'ler yapıyorduk.

Black Friday'ı Kurtaran Index#

Hiç yaratmadığım en pahalı index'ten bahsedeyim. Black Friday 2023 sırasında ürün arama sistemimiz sürünüyordu. Kullanıcılar arama sonuçlarının yüklenmesi 8+ saniye sürdüğü için sepetlerini terk ediyorlardı.

PostgreSQL loglarına daldım ve duman çıkan silahı buldum:

SQL
-- Katil query (basitleştirilmiş)
SELECT p.*, c.name as category_name 
FROM products p 
JOIN categories c ON p.category_id = c.id 
WHERE p.active = true 
  AND p.category_id = $1 
  AND p.price BETWEEN $2 AND $3 
ORDER BY p.rating DESC, p.created_at DESC;

EXPLAIN planı her arama için 50 milyon ürün üzerinde sequential scan yaptığını gösteriyordu. category_id ve price üzerinde ayrı ayrı indexlerimiz vardı, ama bu query'yi hızlı yapacak composite index yoktu.

Black Friday'da öğleden sonra 2'de (neyse ki gece 3'te değil!), 15 dakikalık maintenance window sırasında index ekleme kararı aldım:

SQL
CREATE INDEX CONCURRENTLY idx_products_category_price_rating 
ON products (category_id, price, rating DESC, created_at DESC) 
WHERE active = true;

Query süresi 8 saniyeden 150ms'ye düştü. Bu tek index değişikliği en büyük alışveriş günümüzde tahminen 2 milyon dolarlık satış kaybını önledi.

Ama öğrendiğim şey: bu index ayrıca write sürelerini de yaklaşık %15 artırdı. Her ürün güncellenmesi artık ek bir index'i maintain etmek zorundaydı. Her zaman bir trade-off var.

MongoDB Aggregation Pipeline Uyanışı#

PostgreSQL'i düzeltirken MongoDB analitiğimiz hala felaketti. Yöneticilerin göstermeyi sevdiği kullanıcı dashboard'u yüklenmesi 30+ saniye sürüyordu. Kullanıcılar gerçekten "Yükleniyor..." yazısını o kadar uzun görüyorlardı ki browser tab'ını kapatıyorlardı.

Problem veriyi nasıl düşündüğümüzdeydi. Node.js uygulamamız bunu yapıyordu:

JavaScript
// Yanlış yol - uygulama seviyesinde join'ler
const users = await User.find({ active: true });
const orders = await Order.find({ userId: { $in: userIds } });
const analytics = users.map(user => {
  const userOrders = orders.filter(o => o.userId === user._id);
  return {
    userId: user._id,
    totalRevenue: userOrders.reduce((sum, o) => sum + o.total, 0),
    orderCount: userOrders.length,
    avgOrderValue: userOrders.length > 0 ? totalRevenue / userOrders.length : 0
  };
});

Bu potansiyel olarak milyonlarca dökümanı memory'ye yüklemeyi ve JavaScript'te işlemeyi gerektiriyordu. Yavaş olması şaşırtıcı değildi.

MongoDB'nin aggregation pipeline'ını anlayınca çözüm utanç verici derecede basitti:

JavaScript
// Doğru yol - veritabanı seviyesinde aggregation
const analytics = await User.aggregate([
  { $match: { active: true } },
  { $lookup: {
      from: "orders",
      localField: "_id",
      foreignField: "userId",
      as: "orders"
    }
  },
  { $project: {
      userId: "$_id",
      totalRevenue: { $sum: "$orders.total" },
      orderCount: { $size: "$orders" },
      avgOrderValue: { 
        $cond: [
          { $gt: [{ $size: "$orders" }, 0] },
          { $divide: [{ $sum: "$orders.total" }, { $size: "$orders" }] },
          0
        ]
      }
    }
  }
]);

İşleme süresi 12 dakikadan 3 saniyeye düştü. Kullanıcı dashboard'u artık real-time yükleniyor. Bazen en iyi optimizasyon sadece veritabanınızı tasarlandığı şekilde kullanmaktır.

Real-Time Performance Monitoring Kurma#

Çok fazla performance sürprizi yaşadıktan sonra, regresyonları kullanıcılara ulaşmadan yakalayacak kapsamlı bir monitoring sistemi kurdum:

TypeScript
interface DatabaseMetrics {
  postgresql: {
    activeConnections: number;
    queryDuration: PercentileMetrics;
    cacheHitRatio: number;
    indexUsage: IndexEfficiency[];
    lockWaitTimes: Duration[];
  };
  
  mongodb: {
    operationCounts: OperationType[];
    queryExecutionStats: ExecutionStats;
    indexEffectiveness: IndexMetrics[];
    shardingBalance: ShardDistribution;
  };
  
  infrastructure: {
    cpuUtilization: number;
    memoryUsage: MemoryMetrics;
    diskIOPS: IOMetrics;
    networkLatency: NetworkStats;
  };
}

// Özel query performance tracker
class QueryPerformanceTracker {
  private metrics = new Map<string, QueryMetrics>();
  
  async trackQuery(query: string, duration: number, database: 'postgres' | 'mongodb') {
    const querySignature = this.normalizeQuery(query);
    const existing = this.metrics.get(querySignature) || {
      count: 0,
      totalDuration: 0,
      maxDuration: 0,
      database
    };
    
    existing.count++;
    existing.totalDuration += duration;
    existing.maxDuration = Math.max(existing.maxDuration, duration);
    
    this.metrics.set(querySignature, existing);
    
    // Regresyonda alert
    if (duration > existing.maxDuration * 1.5) {
      await this.alertPerformanceRegression(querySignature, duration);
    }
  }
}

Bu sistem artık performance regresyonlarını otomatik yakalıyor. Developer bir pull request'te yanlışlıkla indexsiz query eklediğinde, production'a ulaşmadan önce bundan haberimiz oluyor.

Veritabanı Optimizasyonunun Ekonomisi#

Gerçek maliyetleri açıklayalım, çünkü optimizasyon sadece teknik egzersizden ziyade iş case'i haline burada dönüşüyor.

Optimizasyon Öncesi (Aylık AWS Maliyetleri):

  • RDS PostgreSQL (db.r5.4xlarge): $1,200/ay
  • Read replica'lar (3x db.r5.xlarge): $900/ay
  • MongoDB Atlas (M60): $2,500/ay
  • Uygulama sunucuları (yavaş query'ler için extra kapasite): $800/ay
  • Toplam: $5,400/ay ($64,800 yıllık)

Optimizasyon Sonrası (Aylık AWS Maliyetleri):

  • RDS PostgreSQL (db.r5.2xlarge): $600/ay
  • Read replica'lar (2x db.r5.large): $400/ay
  • MongoDB Atlas (M30): $1,000/ay
  • Uygulama sunucuları (azaltılmış kapasite): $400/ay
  • Toplam: $2,400/ay ($28,800 yıllık)

Yıllık Tasarruf: Altyapıda $36,000 + önlenmiş scaling maliyetlerinde $64,000 = $100K

Ama gerçek değer sadece maliyet tasarrufu değildi. Kullanıcı deneyimi dramatik şekilde gelişti:

  • Ürün arama: 8 saniye → 150ms (%98 iyileşme)
  • Analytics dashboard: 30+ saniye → real-time güncellemeler
  • Checkout flow: Yoğun trafik sırasında artık timeout yok
  • Müşteri memnuniyeti: Conversion rate'lerde %23 artış

PostgreSQL vs MongoDB: Doğru Aracı Seçme#

Her iki sistemi üç yıl boyunca optimize ettikten sonra, hangisini ne zaman kullanacağım konusunda öğrendiklerim:

PostgreSQL kullan:

  • ACID uyumluluğuna ihtiyacın varsa (finansal işlemler, envanter yönetimi)
  • Karmaşık JOIN operasyonları query'lerinde yaygınsa
  • Öngörülebilir performans karakteristiği istiyorsan
  • Takımın NoSQL konseptlerinden çok SQL'e aşinaysa
  • Data tutarlılığı eventual consistency'den daha önemliyse

MongoDB kullan:

  • Built-in horizontal scaling'e ihtiyacın varsa
  • Data modelin sık değişiyorsa (startup pivot'ları, hızlı iterasyon)
  • Büyük veri setlerinde karmaşık aggregation'lar yapıyorsan
  • Döküman tabanlı query'ler uygulama objelerinle match ediyorsa
  • Kabul edilebilir write latency ile mükemmel read performansına ihtiyacın varsa

Temel görüş: Veritabanını hype'a veya trend'e göre seçme. Spesifik erişim pattern'larına ve tutarlılık gereksinimlerine göre seç.

Gerçekten İşe Yarayan Advanced Profiling Araçları#

Yıllar boyunca onlarca veritabanı profiling aracı denedim. İşte gerçekten fark yaratan olanlar:

PostgreSQL Araçları#

Log Analysis için pgBadger:

Bash
# Kapsamlı performans raporları oluştur
pgbadger -j 4 -f stderr /var/log/postgresql/postgresql-*.log \
  --prefix '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h' \
  -o /var/www/html/pgbadger.html

pgBadger PostgreSQL loglarınızı güzel, aksiyon alınabilir raporlara dönüştürüyor. Manuel olarak asla bulamayacağım pattern'ları tespit etti, mesela individually hızlı ama frekans nedeniyle büyük miktarda total time tüketen query'ler gibi.

Percona Monitoring and Management (PMM): PMM historical trending ile real-time query analytics sağlıyor. Sadece index recommendation engine'i bile haftalarca manuel analizi bize kazandırdı.

MongoDB Araçları#

MongoDB Compass: Compass'taki görsel explain planları inefficient query'leri spot etmeyi kolaylaştırıyor. Aggregation pipeline'ının shard'lar arasında tam olarak nasıl execute edildiğini görebilmek paha biçilmez.

Özel Profiling Script'leri:

JavaScript
// Otomatik yavaş query detection
function analyzeSlowQueries() {
  return db.system.profile.aggregate([
    { $match: { millis: { $gt: 100 } } },
    { $group: {
        _id: {
          collection: "$ns",
          operation: "$op"
        },
        count: { $sum: 1 },
        avgDuration: { $avg: "$millis" },
        maxDuration: { $max: "$millis" }
      }
    },
    { $sort: { avgDuration: -1 } }
  ]);
}

Bu script günlük çalışıyor ve en yavaş operasyonların raporunu mail atıyor. Aksi halde fark edilmeyecek birkaç performance regresyonunu yakaladı.

Yaptığım Yaygın Hatalar (Ve Nasıl Kaçınılır)#

"Daha Fazla Index Ekle" Tuzağı#

Optimizasyon yolculuğumun başlarında index'lerin sihir olduğunu düşünürdüm. Query yavaş? Index ekle. Hala yavaş? Başka index ekle. Çok geçmeden 12+ index'li tablolarımız oldu ve write performansı %60 düştü.

Ders: Her index read'leri hızlandırır ama write'ları yavaşlatır. Indexing stratejini read/write oranına göre tasarla. High-write tablolar için index konusunda çok seçici ol.

Production Data Sürprizi#

Her optimizasyon development ortamımızda 10.000 test kaydıyla mükemmel çalışıyordu. Production'da 50 milyon kayıt vardı ve tamamen farklı data dağıtım pattern'ları vardı.

Development'te 10ms süren bir query production'da 30 saniye sürüyordu çünkü data'da index'lerimizi etkisiz kılan skewed distribution'lar vardı.

Optimizasyonları her zaman production ölçeğindeki data ile test et, ya da en azından benzer dağıtım karakteristiklerine sahip data ile.

Yanlış Metrikler Odağı#

Aylarca yanlış query'leri optimize ettik çünkü kullanıcı odaklı operasyonlar yerine veritabanı merkezli metrikleri ölçüyorduk. User-facing arama query'leri yavaş kalırken gecelik batch process'leri optimize etmekle haftalar harcadık.

Önce kullanıcı deneyimini doğrudan etkileyen operasyonlara odaklan. İç raporlama yavaş olabilir – kullanıcı odaklı operasyonlar olamaz.

Farklı Yapacaklarım#

Üç yıllık veritabanı optimizasyonuna bakınca, değiştireceklerim:

Business Impact Measurement ile Başla En yavaş query'leri optimize etmek yerine, önce en yüksek business impact'li query'leri optimize ederdim. Günde 10.000 kez hit alan query'de 1 saniyelik iyileşme, günde bir kez hit alan query'de 10 saniyelik iyileşmeden daha değerli.

Otomatik Performance Testing Implement Et CI/CD pipeline'ına otomatik performance regression testing kur. Performance sorunlarını müşteri şikayetlerinden sonra değil, code review sırasında yakala.

Takım Eğitimine Erken Yatırım Yap Optimizasyona başlamadan önce tüm geliştirme takımını veritabanı performans temellerinde eğit. Query yazan her developer EXPLAIN planları ve temel indexing stratejilerini anlamalı.

10x Data Growth için Plan Yap Optimizasyon stratejilerini mevcut data hacminin 10 katında çalışacak şekilde tasarla. Büyüme planlamazsan bugünün hızlı query'si yarının timeout'u olur.

Teknik Liderler için Ana Çıkarımlar#

Birçok şirkette veritabanı optimizasyonu liderlik ettikten sonra öğrendiklerim:

Veritabanı Yöneticileri için:

  • Sistematik monitoring ve profiling sezgi tabanlı optimizasyonu her zaman yener
  • Index stratejisi read performansı ile write overhead'i dengelemeli
  • Veritabanı teknoloji seçimi spesifik use case pattern'larına match etmeli
  • Otomatik alerting küçük sorunların major incident olmasını önler

Geliştirme Takımları için:

  • Query optimizasyonu sürekli öğrenme ve pratik gerektiren bir beceri
  • Uygulama tasarım pattern'larının veritabanı performansına büyük etkisi var
  • Production ölçeğindeki data ile test anlamlı optimizasyon için şart
  • Performance regression prevention performance incident response'dan ucuz

Engineering Leadership için:

  • Veritabanı performans optimizasyonu ölçülebilir business ROI sağlar
  • Takım eğitimi ve tooling yatırımı tüm projelerde dividendlar ödüyor
  • Optimizasyon ile altyapı maliyet azaltma kapasite eklmeden daha iyi scale ediyor
  • Performance sorunları zamanla compound ediyor – erken yatırım büyük sorunları önlüyor

İleriye Giden Yol#

Veritabanı optimizasyonu bir kerelik proje değil – devam eden bir disiplin. İlk yılda tasarruf ettiğimiz 100K dolar sadece başlangıçtı. Sistematik profiling, monitoring ve optimizasyon pratiklerini geliştirme workflow'umuza entegre ederek, sayısız performance sorununu önledik ve scale olurken öngörülebilir maliyetleri maintain ettik.

Burada paylaştığım araçlar ve teknikler sihirli mermi değil. Veritabanı performansını anlama ve iyileştirmenin sistematik yaklaşımının parçaları. Gerçek sihir, iyi tooling'i spesifik use case'lerinizin ve erişim pattern'larınızın derin anlaşılmasıyla birleştirdiğinde oluyor.

Benzer veritabanı performans challengeları yaşıyorsan, ölçümle başla. Ölçemediğin şeyi optimize edemezsin. Önce kapsamlı monitoring kur, sonra o veriyi optimizasyon çabalarını yönlendirmek için kullan.

Ve unutma: amaç dünyadaki en hızlı veritabanına sahip olmak değil. Amaç bütçeni patlatmadan business hedeflerini destekleyecek kadar iyi performans veren bir veritabanına sahip olmak.

Kullanıcıların sub-millisecond query süreleri için teşekkür etmeyecek, ama arama 8 saniye sürerse ürününü terk edecekler. Spesifik durumun için doğru dengeyi bul ve büyürken onu maintain edecek süreçleri kur.

Loading...

Yorumlar (0)

Sohbete katıl

Düşüncelerini paylaşmak ve toplulukla etkileşim kurmak için giriş yap

Henüz yorum yok

Bu yazı hakkında ilk düşüncelerini paylaşan sen ol!

Related Posts