|
*SQL güvenlik ve performans çıtasını yukarı taşıyan pratik bir yol haritası.
1. Temel Yapılar
1.1. Tablo Oluştur
CREATE TABLE urunler (
id SERIAL PRIMARY KEY,
ad TEXT NOT NULL,
kategori TEXT NOT NULL,
fiyat NUMERIC(10,2) CHECK (fiyat >= 0),
stok INT DEFAULT 0 CHECK (stok >= 0),
aktif BOOLEAN DEFAULT TRUE
);
İpucu: PostgreSQL 17’de SERIAL yerine identity sütun kullan:
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY
Sekans yönetimini otomatikleştirir.
1.2. CRUD Örnekleri
-- INSERT
INSERT INTO urunler (ad, kategori, fiyat, stok)
VALUES ('USB‑C Hub', 'Elektronik', 349.90, 25)
RETURNING id;
-- SELECT
SELECT id,
ad AS urun,
fiyat || ' ₺' AS fiyat_etiket,
stok,
CASE WHEN stok = 0 THEN 'Stok Yok' ELSE 'Var' END AS durum
FROM urunler
WHERE aktif IS TRUE
ORDER BY fiyat DESC
LIMIT 10;
-- UPDATE
UPDATE urunler
SET stok = stok - 1
WHERE id = 42;
-- DELETE (kampanya bitince)
DELETE FROM urunler
WHERE aktif IS FALSE AND stok = 0;
2. İlişkiler & JOIN’ler
-- Basit JOIN: sipariş detayındaki ürün bilgisi
SELECT u.ad, u.kategori, sd.miktar
FROM urunler u
JOIN siparis_detay sd ON sd.urun_id = u.id
WHERE sd.birim_fiyat > 100;
-- LEFT JOIN + agregasyon: hiç satmayan ürünleri bul
SELECT u.id,
COALESCE(SUM(sd.miktar), 0) AS toplam_satis
FROM urunler u
LEFT JOIN siparis_detay sd ON sd.urun_id = u.id
GROUP BY u.id
HAVING SUM(sd.miktar) IS NULL;
Performans Tüyosu: JOIN’lenen sütunlara (siparis_detay.urun_id) mutlaka indeks bas. Yabancı anahtarlar için ON DELETE CASCADE ya da DEFERRABLE senaryolarını değerlendir.
3. Güvenlik — “Veri kalesini” sağlamlaştır
| Tehdit |
Karşı Hamle |
| SQL Injection |
Parametreli sorgu ($1, pg_prepare, PDO::prepare`). |
| Aşırı yetki |
CREATE ROLE readonly LOGIN...; sonra sadece gerekli tablolara GRANT SELECT. |
| Şifreler |
Sunucu‑CLI SSL (hostssl), scram-sha-256 auth; uygulama katmanında Argon2/BCrypt hash. |
| Veri sızıntısı |
Sütun şifreleme (pgcrypto), satır düzeyi politikalar (Row‑Level Security). |
| Kaza‑silme |
WAL + pg_basebackup; v17’de artımlı yedek (delta) desteği. |
🔐 Ekstra: Trigger ile “soft delete” (örn. deleted_at) tut, yetkisi olmayan kullanıcılara WHERE deleted_at IS NULL filtreli view göster.
4. Performans — “Uçan” sorgular için reçete
-
İndeks Stratejisi
btree → eşitlik/sırala
hash → saf eşitlik (v17’de hızlandı)
GIN/GIST → JSONB, coğrafi, full‑text
-
EXPLAIN (ANALYZE, BUFFERS) ile plan oku:
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM urunler WHERE ad ILIKE 'usb%';
- Autovacuum Ayarı — büyük tablolarda
autovacuum_vacuum_scale_factor = 0.02 gibi agresif değer.
-
Konfig:
shared_buffers = 25% RAM
work_mem = (eşzamanlı sorgu × 1–2 MB)
maintenance_work_mem = rebuild/vacuum sırasında yüksek tut
-
PostgreSQL 17 Bonusları
- Streaming I/O → sekansiyel taramada %20 hız
- Adaptive Vacuum → yoğun trafikte daha az dur‑kalk
- JSON_TABLE() → JSON’u satırlara aç, sonra join
- Connection Pool → PgBouncer / PgCat.
- Partisyonlama → yıllık veya kategori bazlı tablolar; eski partisyonu
DETACH edip salt‑okunur sakla.
5. Mikroservis / Modüler Data Layer
- Schema‑per‑module:
CREATE SCHEMA stok;, siparis; vb. Çakışma riskini sıfırlar.
- Foreign Data Wrapper (
postgres_fdw) ile modüller arası sorgu, ya da
- Logical Replication — modül A’daki
urunler tablosunu modül B’ye yayınla; v17’de failover kontrolü geldi.
- Event Bus:
LISTEN/NOTIFY ile hafif publish–subscribe.
6. Öğrenme Rotaları & Alıştırmalar
-
Challenge — “Kritik stok” fonksiyonu yaz:
CREATE OR REPLACE FUNCTION urun_kritik_stokta_mi(p_id INT)
RETURNS BOOLEAN LANGUAGE plpgsql AS $$
DECLARE
s INT;
BEGIN
SELECT stok INTO s FROM urunler WHERE id = p_id;
RETURN s < 10; -- eşik değeri
END;
$$;
- Index Lab —
generate_series ile 1 M satırlık sahte veri doldur; btree vs gin arası hız farkını ölç.
- RLS Görevi — tedarikçi bazlı satır politikası:
tedarikci_id = current_user.
7. Son Tüyolar
- Versiyon Güncellemesi — 15→17 in‑place upgrade artık tek tık; downtime kısa.
- pg_stat_statements → yavaş sorguları sınıflandır; sonra gereken yerde
CREATE INDEX / REFRESH MATERIALIZED VIEW.
- Test ≠ Prod — staging’de farklı
work_mem/istatistik hedefi, hatalı plan doğurur.
- CLI Ninja Move —
\watch 1 ile psql çıktısını saniyelik güncelle; canlı monitoring gibi.
Şimdi terminali aç, birkaç EXPLAIN patlat: kaç satır diskten geldi, kaç buffer hit oldu bir bak. Sonra kahveni yudumla; bir sonraki optimizasyon turunda görüşürüz! 🚀 |