Gereksinimler ve Ön Hazırlık
Başarılı bir veri modelleme süreci için öncelikle doğru araçlara ve temel bilgilere sahip olmalısınız. 2026 yılı itibarıyla PostgreSQL, ilişkisel veritabanı yönetimi (RDBMS) konusunda endüstri standardı kabul edilmektedir. Çalışmalarınızda yerel ortamda Docker kullanarak bir veritabanı konteyneri ayağa kaldırmanız, geliştirme ve üretim ortamları arasındaki farkları minimize edecektir.
- PostgreSQL 17+ veya MySQL 9.0+: Güncel güvenlik yamalarına sahip veritabanı sunucusu.
- DBeaver veya pgAdmin 4: Veri şemalarını görselleştirmek ve sorguları test etmek için profesyonel araçlar.
- ORM (Object-Relational Mapping) Bilgisi: Laravel (Eloquent) veya Node.js (Prisma) gibi araçların veritabanı ile nasıl konuştuğuna dair temel fikir.
- Temel SQL Bilgisi: DDL (Data Definition Language) ve DML (Data Manipulation Language) komutlarına hakimiyet.
Adım 1: Gereksinim Analizi ve Varlık-İlişki Diyagramı (ERD)
Kod yazmaya başlamadan önce, uygulamanızdaki "varlıkları" (entities) tanımlamanız gerekir. Örneğin bir e-ticaret uygulaması yapıyorsanız; Kullanıcılar, Ürünler ve Siparişler temel varlıklarınızdır. Bu varlıkların birbirleriyle olan ilişkilerini (bire-bir, bire-çok, çok-tan-çoğa) kağıt üzerinde veya bir diyagram aracıyla çizmek, hataları en baştan engeller.
İlişkileri belirlerken normalizasyon kurallarını (1NF, 2NF, 3NF) göz önünde bulundurmalısınız. Normalizasyon, veritabanındaki veri tekrarını azaltır ve veri bütünlüğünü sağlar.
Adım 2: Tablo Yapılarını Oluşturma ve Veri Tipleri
Tabloları oluştururken doğru veri tiplerini seçmek, disk alanı ve sorgu performansı açısından hayati önem taşır. Örneğin, bir kullanıcının yaşını saklamak için INT yerine SMALLINT kullanmak, büyük ölçekli sistemlerde bellek tasarrufu sağlar.
Aşağıdaki örnekte, kullanıcılar tablosunun güvenli bir şekilde nasıl oluşturulacağını görebilirsiniz:
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
Bu kod bloğunda UUID kullanarak veritabanı anahtarlarının tahmin edilebilir olmasını engelledik. password_hash alanı, şifrelerin asla düz metin olarak saklanmaması gerektiğini vurgular.
Adım 3: İlişkisel Veritabanı Tasarımında Foreign Key Kullanımı
Veriler arasındaki bağı kurmak için FOREIGN KEY (yabancı anahtar) kısıtlamalarını kullanmalısınız. Bu, veritabanı seviyesinde veri tutarlılığını garanti eder. Örneğin, bir siparişin var olmayan bir kullanıcıya ait olmasını bu şekilde engelleyebilirsiniz.
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
total_amount DECIMAL(12, 2) NOT NULL,
status VARCHAR(20) DEFAULT 'pending'
);
Buradaki ON DELETE CASCADE komutu, bir kullanıcı silindiğinde ona ait tüm siparişlerin de otomatik olarak silinmesini sağlar. Bu, veritabanında "yetim veri" kalmasını önleyen bir yöntemdir.
Adım 4: Performans İçin İndeksleme Stratejileri
Veritabanı büyüdükçe, belirli sütunlarda arama yapmak yavaşlayabilir. İndeksler, veritabanının tüm tabloyu taramak yerine doğrudan ilgili satıra gitmesini sağlar. Ancak her sütuna indeks eklemek, veri ekleme (INSERT) işlemlerini yavaşlatır.
-- Kullanıcıların email ile giriş yapması için indeks
CREATE INDEX idx_users_email ON users(email);
-- Siparişlerin tarih aralığına göre sorgulanması için indeks
CREATE INDEX idx_orders_created_at ON orders(created_at);
İndeksleri, uygulamanızda en sık yaptığınız WHERE ve JOIN sorgularına göre optimize etmelisiniz.
Adım 5: Güvenli Veri Erişimi ve SQL Injection Koruması
Web uygulamalarında en büyük güvenlik riski SQL Injection'dır. Kullanıcıdan gelen veriyi doğrudan sorguya eklemek yerine, her zaman "Prepared Statements" (Hazırlanmış İfadeler) kullanmalısınız.
-- Güvensiz kullanım:
-- SELECT * FROM users WHERE username = ' + input + ';
-- Güvenli kullanım (PDO veya benzeri sürücülerle):
PREPARE get_user (text) AS SELECT * FROM users WHERE username = $1;
EXECUTE get_user('kullanici_adi');
Kritik Güvenlik Uyarısı: Veritabanı bağlantı bilgilerini (host, user, password) asla kaynak kodun içine yazmayın. Bunları her zaman .env dosyaları veya güvenli bir "Secret Manager" üzerinden yönetin.
Veritabanı Tasarım Yöntemleri Karşılaştırması
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| Normalizasyon (3NF) | Veri tekrarını önler, tutarlılık sağlar. | Karmaşık JOIN sorguları performansı düşürebilir. |
| Denormalizasyon | Okuma hızını artırır, basit sorgular sağlar. | Veri tutarsızlığı riski taşır, güncelleme zordur. |
Sıkça Sorulan Sorular
Veritabanı şemamı nasıl güncel tutabilirim?
Veritabanı "migration" (göç) araçlarını kullanın. Laravel, Django veya Prisma gibi modern çatılar, veritabanı değişikliklerini versiyon kontrol sistemine (Git) dahil etmenize olanak tanır.
UUID mi yoksa Auto-increment ID mi kullanmalıyım?
Dağıtık sistemlerde ve güvenlik odaklı projelerde UUID kullanımı daha avantajlıdır. Auto-increment ID'ler, veritabanı kayıt sayınızın rakipleriniz tarafından tahmin edilmesine neden olabilir.
Veritabanı yedeği alırken nelere dikkat etmeliyim?
Yedeklerinizi düzenli olarak test edin. Geri yüklenemeyen bir yedek, yedek değildir. Otomatik yedekleme senaryolarını pg_dump gibi araçlarla cron job olarak kurun.
İlişkisel veritabanı yerine NoSQL tercih etmeli miyim?
Verileriniz yapısal ve ilişkisel ise (e-ticaret, finans), SQL her zaman daha güvenli ve tutarlıdır. NoSQL, çok hızlı değişen ve ilişkisiz büyük veri setleri için uygundur.
Performans sorunlarını nasıl tespit ederim?
EXPLAIN ANALYZE komutunu kullanarak sorgularınızın nasıl çalıştığını inceleyin. Hangi adımın yavaş olduğunu görmek, indeksleme stratejinizi belirlemenize yardımcı olur.
Sorumluluk Reddi: Bu makaledeki kod örnekleri eğitim amaçlıdır. Üretim ortamında veritabanı şeması oluştururken, verilerinizi yedeklediğinizden ve yetkilendirme (RBAC) kurallarını uyguladığınızdan emin olun. SQL sorgularınızda her zaman kütüphanenizin sunduğu "parameterized query" yöntemlerini kullanın.
Veritabanı Tasarımında İleri Düzey İpuçları: Partitioning ve Sharding
Veritabanınız büyüdükçe, tek bir tablo üzerinde yapılan işlemler yavaşlamaya başlar. Özellikle milyonlarca satırlık verilerde "Partitioning" (Bölümleme) stratejisi, veriyi fiziksel olarak daha küçük parçalara ayırarak sorgu performansını ciddi oranda artırır. Örneğin, tarih bazlı bir bölümleme yaparak, sadece güncel verilere erişimi hızlandırabilirsiniz.
Aşağıdaki SQL örneği, PostgreSQL üzerinde bir tablonun tarih aralıklarına göre nasıl bölümlenebileceğini göstermektedir:
-- Ana tabloyu oluşturma
CREATE TABLE siparisler (
id SERIAL,
siparis_tarihi DATE NOT NULL,
toplam_tutar DECIMAL,
PRIMARY KEY (id, siparis_tarihi)
) PARTITION BY RANGE (siparis_tarihi);
-- 2023 yılı verileri için partition oluşturma
CREATE TABLE siparisler_2023 PARTITION OF siparisler
FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
-- 2024 yılı verileri için partition oluşturma
CREATE TABLE siparisler_2024 PARTITION OF siparisler
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
Sharding ise veritabanını farklı sunuculara dağıtma işlemidir. Bu yöntem genellikle "horizontal scaling" (yatay ölçekleme) gerektiren çok büyük ölçekli uygulamalarda tercih edilir. Sharding yaparken, veriyi hangi kritere göre böleceğiniz (Sharding Key) mimarinizin başarısını belirler.
Veritabanı Testleri ve Entegrasyon Süreçleri
Veritabanı şemanızı kod gibi yönetmek, hataları en aza indirir. "Migration" (Göç) araçlarını kullanarak veritabanı değişikliklerini versiyonlamalı ve her değişiklikten önce otomatik testler çalıştırmalısınız. Bir veritabanı testinde, verinin bütünlüğünü ve ilişkilerin doğruluğunu kontrol etmek için "Unit Test" yazmak en iyi pratiktir.
Örnek Test Senaryosu
Bir kullanıcı silindiğinde, ona bağlı tüm siparişlerin de silinip silinmediğini (Cascade Delete) kontrol eden bir test senaryosu şu şekilde kurgulanabilir:
-- Test verisi ekleme
INSERT INTO kullanicilar (id, isim) VALUES (1, 'Test Kullanıcı');
INSERT INTO siparisler (id, kullanici_id, tutar) VALUES (101, 1, 500);
-- Silme işlemi
DELETE FROM kullanicilar WHERE id = 1;
-- Doğrulama: Sipariş tablosunda kayıt kalmamalı
SELECT COUNT(*) FROM siparisler WHERE kullanici_id = 1;
-- Sonuç 0 dönmelidir.
Bu tür testleri CI/CD süreçlerinize dahil ederek, veritabanı şemasında yaptığınız bir değişikliğin mevcut iş mantığını bozmadığından emin olabilirsiniz. Özellikle "Foreign Key" kısıtlamalarınızın test ortamında aktif olduğundan ve veritabanı motorunun (örneğin InnoDB) bu kısıtlamaları desteklediğinden emin olun.
İpucu: Veritabanı testlerinde gerçek verileri asla kullanmayın. Bunun yerine "Factory" veya "Fixture" yöntemlerini kullanarak her test için izole edilmiş geçici veritabanı tabloları oluşturun.
Sonuç
Web uygulamaları için veri modelleme, uygulamanızın ömrünü belirleyen en önemli mimari karardır. Bu rehberde öğrendiğiniz normalizasyon, indeksleme, güvenlik ve ilişki yönetimi prensipleri, profesyonel bir veritabanı uzmanı olmanız için gereken temel taşlardır. Bir sonraki adım olarak, veritabanı işlemlerinizi hızlandıracak olan "Caching" (Önbellekleme) mekanizmalarını (Redis gibi) araştırmanızı öneririm. Sağlam bir veritabanı mimarisi, uygulamanızın her zaman ayakta kalmasını sağlar.

Yorumlar (0)
Yorum Yaz