TB
← Tüm yazılar

Iliskisel modelleme ilkeleri

Veritabanı tasarımında normalizasyon, denormalizasyon ve iliskisel modelleme prensiplerini doğru uygulamak, sistemin uzun vadeli basarisini belirler.

Iliskisel veritabanı tasarımı, yazılım mimarisinin en uzun omurlu kararlarindan biridir. Uygulama katmaninda refactor yapmak haftalar surerken, yanlış modellenmis bir tablo yapisi yillardir her sorguya, her rapora ve her migration'a maliyet olarak yansir. Iliskisel modelleme; varliklari, iliskileri, butunluk kisitlarini ve is kurallarini tablo ve kolon duzeyinde ifade etme sanatidir. Bu yazida normalizasyonun pratik sınırları, denormalizasyonun ne zaman mantıklı olduğu, birincil ve yabanci anahtar tasarımı, surrogate key seçimi ve domain-driven tasarım ile veritabanı semasinin nasil hizalanacagini derinlemesine inceliyoruz.

Iliskisel modelin temel kavramlari

Iliskisel model, veriyi relation adi verilen iki boyutlu tablolarda tutar. Her satir bir tuple, her kolon bir attribute temsil eder. Tablolar arasi bağlantı yabanci anahtar ile kurulur. Codd'un iliskisel cebir kurallari sayesinde SQL uzerinden birlestirme, filtreleme, projeksiyon ve kumeleme islemleri tanimlanabilir. Tasarım sürecinde oncelikle kavramsal model cikarilir, ardindan mantiksal model ve son olarak fiziksel model oluşturulur.

Pratikte en sik yapılan hata, fiziksel optimizasyonu mantiksal model tamamlanmadan baslatmaktir. Bir tabloya erken eklenen JSON kolonu veya gereksiz denormalizasyon, sonradan normalizasyon maliyetini katlar. Ilk adim her zaman is domain'ini anlamak ve varlık sinirlarini netlestirmektir.

Normalizasyon: 1NF'den 3NF'ye

Birinci normal form (1NF): Her hucre atomik bir deger tasir. Tek kolonda virgülle ayrilmis etiket listesi veya tekrarlayan grup kolonlari 1NF ihlalidir. Çözüm ayri satirlar veya ilişkili tablodur.

Ikinci normal form (2NF): Bilesik birincil anahtara bağlı olmayan kolonlar ayri tabloya tasinir. Siparis kaleminde product_name ayni tabloda duruyorsa Products tablosuna ait olmalidir.

Üçüncü normal form (3NF): Birincil anahtara transitif bağımlılık olmamalidir. Müşteri tablosunda şehir ve bolge birlikte duruyorsa bolge sehre transitif bağımlıdır.

CREATE TABLE customers (
    id          BIGINT PRIMARY KEY,
    name        VARCHAR(200) NOT NULL,
    city_id     INT NOT NULL REFERENCES cities(id)
);

CREATE TABLE orders (
    id           BIGINT PRIMARY KEY,
    customer_id  BIGINT NOT NULL REFERENCES customers(id),
    ordered_at   TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE order_lines (
    order_id     BIGINT NOT NULL REFERENCES orders(id),
    product_id   BIGINT NOT NULL REFERENCES products(id),
    quantity     INT NOT NULL CHECK (quantity > 0),
    unit_price   NUMERIC(18,4) NOT NULL,
    PRIMARY KEY (order_id, product_id)
);

BCNF ve ileri normal formlar

Boyce-Codd Normal Form'da her determinans ad aday anahtar olmalidir. 4NF ve 5NF cok degerli bağımlılıkları ele alir; pratik OLTP'de nadiren zorunlu hale gelir. Normalizasyon her zaman performans dusmani degildir; asil risk denormalize verinin guncellenmesi sirasinda tutarsizlik olusmasidir.

Denormalizasyon ne zaman mantiklidir

  • Hesaplanmis kolon: order_total snapshot; trigger veya domain event ile senkron.
  • Materialized view: Raporlama icin ayri tablo; OLTP normal kalir.
  • Embedded snapshot: Fatura satirinda ürün adi anlik kopya; fiyat gecmisi korunur.

Denormalizasyon karari dokumante edilmeli ve tutarlılık mekanizmasi tanimlanmalidir.

Anahtar tasarımı

Surrogate key (BIGINT, UUID) degismez ve join dostudur. Natural key is kurallarini yansitir ancak degisebilir. UUID v7 zaman sirali uretimle indeks fragmentasyonunu azaltir. FK kisiti veri butunlugunun son savunma hattidir; CASCADE dikkatli kullanılmalıdır.

Varlık iliskileri

Bir-e-bir iliskide ayri tablolar performans ve güvenlik ayirimi sağlar. Bir-e-cok iliskide FK cok tarafinda olur. Cok-e-cok icin junction tablosu kullanılır. Polymorphic association FK butunlugunu zayiflatir.

DDD ve aggregate sınırları

Her bounded context kendi semasina sahip olabilir. Aggregate sınırları transaction birimini belirler. Order ve OrderLines birlikte kaydedilir; stok ve odeme ayri aggregate ise saga veya outbox ile senkronize edilir.

Veri tipi ve kisitlar

Para icin NUMERIC; tarih icin TIMESTAMPTZ UTC. CHECK kisiti domain kurallarini zorlar. ENUM yerine lookup tablosu migration esnekligi sağlar.

Soft delete ve temporal veri

deleted_at ile mantiksal silme audit sağlar. Partial index deleted_at IS NULL kosuluyla performansi korur. Temporal table gecmis durumu otomatik tutar.

Anti-pattern'ler

  1. EAV modeli: sorgu ve butunluk felaketi
  2. God table: yuzlerce nullable kolon
  3. FK'siz ilişki: erken veri bozulmasi
  4. Her sey JSON: indekslenemeyen bataklik
  5. Asiri normalizasyon: olcumsuz join maliyeti

Tasarım süreci

Varlık listesi, ER review, normal form analizi, kritik sorgu prototipi, migration taslagi ve peer review. ADR ile kararlar kaydedilir. Veritabanı tasarımı cok disiplinli ekip calismasi gerektirir.

Özet

Mantiksal modeli doğru kur, denormalizasyonu olcumle gerekcelendir, anahtar stratejisini erken sec, aggregate sinirlarini transaction ile hizala ve semayi duzenli gozden gecir.

Pratik modelleme ornegi: e-ticaret

E-ticaret domain'inde Customer, Address, Cart, Order, Payment, Shipment ve Inventory aggregate'leri ayri dusunulmelidir. Cart geçici bir durumdur; siparis olusturuldugunda Order aggregate'ine donusur ve fiyat anlik snapshot alinir. Stok rezervasyonu ayri transaction veya saga adimi ile yönetilir; tek dev transaction anti-pattern'dir. Category hiyerarsisi closure table veya ltree (PostgreSQL) ile modellenebilir; adjacency list basit ama derin sorgularda yavas kalir.

Promosyon kurallari (yüzde indirim, N al M ode) ayri PromotionRules tablosunda tutulur; OrderLine uzerinde applied_discount snapshot saklanir. Bu sayede gecmis siparisler güncel kural degisikliginden etkilenmez. Vergi hesaplamasi bolgeye gore TaxRate tablosundan okunur; hard-coded oranlar vergi degisikliginde migration felaketi yaratir.

Semantik tutarlılık ve naming

Tablo ve kolon isimlendirme tutarlılığı ekip verimliligini artirir. Tekil isim (order, customer) veya cogul (orders, customers) seçimi önemli degil; tutarlılık önemlidir. created_at, updated_at, created_by audit kolonlari standartlastirilmalidir. Boolean kolonlar is_* veya has_* prefix ile okunabilir kalir. Status kolonlari icin lookup tablosu veya CHECK kisiti zorunlu deger kumesi tanimlar.

Cok kiracili (multi-tenant) modelleme

Tenant basina ayri şema en güçlü izolasyonu sağlar ancak operasyon maliyeti yüksektir. Shared schema + tenant_id kolonu yaygın yaklasimdir; her sorguya tenant filtresi zorunludur. Row Level Security (PostgreSQL) veya security policy (SQL Server) yanlislikla cross-tenant erisimi engeller. tenant_id composite PK veya unique index'in parcasi olmalidir.

Veri kalitesi ve referans butunlugu

NOT NULL, UNIQUE, FK ve CHECK kisitlari uygulama hatalarini erken yakalar. Nullable FK bilincli tercih olmalidir. Default degerler migration ile geriye uyumlu eklenmelidir. Orphan kayıt tespiti icin periyodik reconciliation job planlanir. Veri kalitesi metrikleri (null orani, FK ihlali sayisi) dashboard'da izlenir.