Database Engineering

PostgreSQL JSONB: Şemasız Olay Kaynağı

Mikroservis mimarilerinde denetim günlüğü tutma, uyumluluk, hata ayıklama ve adli analiz için kritik öneme sahiptir. Geliştiriciler geleneksel olarak bu günlükler için katı ilişkisel şemalara güvenirdi. Ancak sistem davranışı değiştikçe, üretim ortamındaki denetim tablosuna yeni sütunlar eklemek maliyetli bir işlem haline gelir. İşte burada PostgreSQL JSONB devreye girer; SQL'in performansıyla NoSQL'in esnekliği arasında güçlü bir denge sunarak öne çıkar.

Bu yazı, denetim günlüklerinde şemasız olay kaynağı (event sourcing) için JSONB'nin nasıl kullanılacağını, çeşitli olay verilerini yakalama esnekliğinden ödün vermeden sorgu performansını nasıl koruyacağınızı incelemektedir.

Katı Denetim Şemalarının Zorluğu

Geleneksel bir denetim tablosu tasarımını ele alalım:

CREATE TABLE audit_logs (
    id SERIAL PRIMARY KEY,
    user_id UUID,
    action VARCHAR(50),
    target_id VARCHAR(100),
    old_value JSONB,
    new_value JSONB,
    created_at TIMESTAMP DEFAULT NOW()
);

Bu tasarım standart CRUD işlemleri için işe yarsa da, üç farklı hizmetten gelen meta verileri içeren karmaşık bir iş akışını günlüğe kaydetmeniz gerektiğinde ne olur? Sonuçta, çoğunluğu NULL değerlerden oluşan seyrek bir tabloya veya daha kötüsü, üretim ortamında kilitlenme sorunlarına yol açan sık sık değişen tablo şemalarına sahip olursunuz. JSONB, depolama verimsizliğini ve şema katılığını çözer ancak yeni bir zorluk getirir: yapılandırılmamış verileri sorgulama.

Performans İçin İndeksleme: GIN Avantajı

JSONB'yi etkili bir şekilde kullanmanın anahtarı uygun indekslemedir. Standart B-tree indeksleri, derin JSON yapıları için iyi çalışmaz. Bunun yerine PostgreSQL, bileşik türler ve JSONB için optimize edilmiş Genelleştirilmiş Tersine İndeksler (GIN) sunar.

Denetim günlüğü sisteminizde, genellikle JSON nesnesi içindeki belirli yolları sorgulamanız gerekir; örneğin, bir işlemi gerçekleştiren kullanıcı. İç içe bir alan için nasıl indeks oluşturulacağına bir göz atalım:

CREATE INDEX idx_audit_logs_user_id 
ON audit_logs USING gin ((data ->> 'user_id'));

(data ->> 'user_id') sözdizimine dikkat edin. ->> operatörü alanı metin olarak çıkarır ve bu, GIN indeksinin doğru çalışmasını sağlar. Bu indeks olmadan, user_id ile filtreleme yapan sorgular sıralı taramalara (sequential scans) neden olur ve büyük tablolar için performansı ciddi şekilde düşürür.

Pratik Örnek: Filtreleme ve Aggregasyon

JSONB sütununuzun data olaylarını şu şekilde sakladığını varsayalım:

{
  "user_id": "550e8400-e29b-41d4-a716-446655440000",
  "action": "UPDATE_PROFILE",
  "metadata": {
    "ip_address": "192.168.1.1",
    "device": "iOS"
  },
  "changes": [
    {"field": "email", "old": "a@b.com", "new": "c@d.com"}
  ]
}

Belirli bir kullanıcı için tüm işlemleri bulmak için indekslenmiş alanı sorgularız:

SELECT id, data 
FROM audit_logs 
WHERE data ->> 'user_id' = '550e8400-e29b-41d4-a716-446655440000'
ORDER BY created_at DESC 
LIMIT 100;

PostgreSQL planlayıcısı, ifade indeksini tanıyacak ve Bitmap İndeks Taraması kullanacaktır; bu da milyonlarca kayıt olsa bile sorgunun milisaniyeler içinde çalışmasını sağlar.

Veri Bütünlüğü İçin Şema Doğrulaması

JSONB şemasız olsa da, yalnızca esnekliğe güvenmek kirli verilere yol açabilir. Bütünlüğü korumak için PostgreSQL'in CHECK kısıtlamalarını JSON Şema doğrulamasıyla birlikte kullanın. Bu, denetim günlüğüne eklenen her JSON nesnesinin temel bir yapıya uygun olmasını sağlar.

ALTER TABLE audit_logs 
ADD CONSTRAINT json_schema_valid 
CHECK (jsonb_schema_valid(data, '{
  "type": "object",
  "required": ["user_id", "action"],
  "properties": {
    "user_id": {"type": "string"},
    "action": {"type": "string"}
  }
}'));

Bu yaklaşım, NoSQL'in geliştirici deneyimini ilişkisel veritabanlarının sıkı veri bütünlüğü garantileriyle birleştirir.

Sonuç

PostgreSQL JSONB'yi şemasız olay kaynağı için kullanmak, ekiplerin uyumluluğu veya performansı bozmadan hızlı hareket etmesine olanak tanır. Sorgu hızı için GIN indekslerini ve veri bütünlüğü için JSON şema doğrulamasını birleştirerek, uygulamanızla birlikte gelişebilen sağlam bir denetim izi oluşturursunuz. Sonuç olarak, hem karmaşık, yapılandırılmamış verileri işlemek için yeterince esnek hem de yüksek trafikli sorgu taleplerini karşılamak için yeterince hızlı bir sistem elde etmiş olursunuz.

Share: