Kapsamlı PostgreSQL Geliştirici Rehberi

3 Ağustos 2026 · netologist · 26 dakika, 5371 kelime ·

Backend geliştiricileri için PostgreSQL’in en çok kullanılan özellikleri, best practice’leri ve pattern’leri hakkında derinlemesine, uygulamaya dönük bir rehber — sadece sorguyu çalıştırmak değil, Postgres’i doğru ve verimli kullanmak isteyenler için.


İçindekiler

  1. Temel Mimari Kavramlar
  2. Veri Tipleri
  3. Şema Tasarımı ve Kısıtlamalar
  4. İndeksleme
  5. Sorgu Yazımı ve Optimizasyon
  6. EXPLAIN ve Sorgu Planlayıcısı
  7. Transaction’lar ve İzolasyon Seviyeleri
  8. Kilitlenme (Locking) ve Eşzamanlılık
  9. JSON / JSONB
  10. Tam Metin Arama (Full-Text Search)
  11. Window Fonksiyonları ve İleri SQL
  12. Common Table Expressions (CTE)
  13. Partitioning (Bölümleme)
  14. Vacuum, Autovacuum ve Bloat
  15. Bağlantı Yönetimi ve Pooling
  16. Replikasyon ve Yüksek Erişilebilirlik
  17. Yedekleme ve Kurtarma
  18. Güvenlik Best Practice’leri
  19. Bilinmesi Gereken Extension’lar
  20. Yaygın Pattern’ler
  21. Migration’lar
  22. İzleme (Monitoring) ve Gözlemlenebilirlik
  23. Kaçınılması Gereken Anti-Pattern’ler
  24. Hızlı Referans Kontrol Listeleri

1. Temel Mimari Kavramlar

Postgres’in neden böyle davrandığını anlamak, rehberin geri kalanının anlaşılmasını çok kolaylaştırır.


2. Veri Tipleri

Doğru tipleri baştan seçmek, ileride acı verici migration’lardan kurtarır.

Sayılar

Metin

Tarih/Zaman

Boolean

UUID

Diziler (Array)

JSON / JSONB

Enum’lar

Ağ tipleri

Range (Aralık) tipleri


3. Şema Tasarımı ve Kısıtlamalar

Primary key’ler

CREATE TABLE orders (
    id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    ...
);

Foreign key’ler

Belge ve güvenlik ağı olarak kısıtlamalar

CREATE TABLE bookings (
    room_id int,
    during tstzrange,
    EXCLUDE USING gist (room_id WITH =, during WITH &&)
);

Bu, aynı oda için hiçbir iki rezervasyonun çakışamayacağını veritabanı seviyesinde garanti eder — uygulama kodunda hiçbir race condition mümkün değildir.

Normalizasyon vs. denormalizasyon

İsimlendirme kuralları


4. İndeksleme

İndeksler, Postgres’teki en yüksek etkiye sahip tek performans aracıdır — ve en çok yanlış kullanılanıdır.

İndeks tipleri

Pratik kurallar

CREATE INDEX idx_orders_customer ON orders (customer_id) INCLUDE (order_date, total);
CREATE INDEX idx_orders_pending ON orders (created_at) WHERE status = 'pending';

Soft-delete pattern’leri (WHERE deleted_at IS NULL) veya duruma göre filtrelenen sorgular için mükemmeldir.

CREATE INDEX idx_users_lower_email ON users (lower(email));
-- destekler: WHERE lower(email) = '[email protected]'

5. Sorgu Yazımı ve Optimizasyon


6. EXPLAIN ve Sorgu Planlayıcısı

EXPLAIN olmadan sorgu optimizasyonu tahmin yürütmekten ibarettir.

EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) SELECT ...;

7. Transaction’lar ve İzolasyon Seviyeleri


8. Kilitlenme (Locking) ve Eşzamanlılık

SELECT * FROM jobs
WHERE status = 'pending'
ORDER BY created_at
LIMIT 1
FOR UPDATE SKIP LOCKED;

9. JSON / JSONB

CREATE INDEX idx_products_attrs ON products USING gin (attributes);
-- destekler: WHERE attributes @> '{"color": "red"}'
CREATE INDEX idx_products_sku ON products ((attributes->>'sku'));

Postgres, gerçekten yetenekli, yerleşik bir tam metin arama motoruna sahiptir — küçük-orta ölçekte Elasticsearch kurmaktan kaçınmak için genellikle yeterlidir.

ALTER TABLE articles ADD COLUMN search_vector tsvector
  GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || body)) STORED;

CREATE INDEX idx_articles_search ON articles USING gin (search_vector);

SELECT * FROM articles
WHERE search_vector @@ to_tsquery('english', 'postgres & performance');

11. Window Fonksiyonları ve İleri SQL

Window fonksiyonları, mevcut satırla ilişkili bir satır kümesi üzerinde hesaplama yapar, ancak (GROUP BY‘ın aksine) bunları gruplara çökertmez.

SELECT
    employee_id,
    department,
    salary,
    RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank,
    AVG(salary) OVER (PARTITION BY department) AS dept_avg,
    salary - LAG(salary) OVER (ORDER BY hire_date) AS diff_from_prev_hire
FROM employees;
SELECT * FROM (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) rn
  FROM employees
) t WHERE rn <= 3;

Diğer ileri seviye yapılar


12. Common Table Expressions (CTE)

WITH regional_sales AS (
    SELECT region, SUM(amount) AS total
    FROM orders
    GROUP BY region
)
SELECT * FROM regional_sales WHERE total > 100000;
WITH RECURSIVE subordinates AS (
    SELECT id, manager_id, name FROM employees WHERE id = 1
    UNION ALL
    SELECT e.id, e.manager_id, e.name
    FROM employees e
    JOIN subordinates s ON e.manager_id = s.id
)
SELECT * FROM subordinates;
WITH moved AS (
    DELETE FROM staging_orders WHERE processed = true RETURNING *
)
INSERT INTO orders SELECT * FROM moved;

13. Partitioning (Bölümleme)

Çok büyük tablolar için (on milyonlarca+ satır), yerleşik bildirimsel (declarative) partitioning, tek bir mantıksal tabloyu fiziksel alt tablolara böler.

CREATE TABLE events (
    id bigint,
    created_at timestamptz NOT NULL,
    payload jsonb
) PARTITION BY RANGE (created_at);

CREATE TABLE events_2026_01 PARTITION OF events
    FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');

14. Vacuum, Autovacuum ve Bloat

Bu, Postgres operasyonlarının en yanlış anlaşılan bölümlerinden biridir.

ALTER TABLE hot_table SET (autovacuum_vacuum_scale_factor = 0.01, autovacuum_analyze_scale_factor = 0.005);

15. Bağlantı Yönetimi ve Pooling


16. Replikasyon ve Yüksek Erişilebilirlik


17. Yedekleme ve Kurtarma


18. Güvenlik Best Practice’leri

ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON documents
    USING (tenant_id = current_setting('app.current_tenant')::uuid);

Bu gerçek bir savunma derinliği (defense-in-depth) katmanıdır: RLS doğru yapılandırıldığında, bir SQL injection hatası veya bir uygulama hatası bile kiracılar (tenant) arası veri sızdıramaz, çünkü sınırı veritabanının kendisi zorlar.


19. Bilinmesi Gereken Extension’lar

CREATE EXTENSION extension_adi; ile etkinleştirilir.

ExtensionNe yapar
pg_stat_statementsTüm sorgular genelinde sorgu performans istatistiklerini takip eder — üretimde varsayılan olarak açık olmalıdır
pgcryptoKriptografik fonksiyonlar, eski sürümlerde gen_random_uuid()
pg_trgmTrigram tabanlı bulanık metin eşleştirme/benzerlik arama
postgisTam coğrafi/mekânsal veri tipleri ve fonksiyonları — mekânsal veri için endüstri standardı
pg_partmanPartition oluşturma/bakımını otomatikleştirir
pg_repackUzun exclusive kilit olmadan çevrimiçi tablo/indeks bloat temizliği
pgauditDetaylı oturum/nesne denetim günlüğü
hstoreBasit anahtar-değer tipi (yeni projelerde büyük ölçüde jsonb tarafından geçilmiştir)
uuid-osspEski UUID üretim fonksiyonları (artık gen_random_uuid() yerleşik olduğundan çoğunlukla gereksiz)
citextBüyük/küçük harf duyarsız metin tipi — karşılaştırmaları her zaman lower() içine sarmaktan daha basittir
timescaledbZaman serisi optimizasyonları (varsayılan olarak paketlenmemiştir ama IoT/metrik iş yükleri için yaygın kullanılır)

20. Yaygın Pattern’ler

Upsert (INSERT … ON CONFLICT)

INSERT INTO users (email, name)
VALUES ('[email protected]', 'Alice')
ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name, updated_at = now();

Atomiktir, race-condition içermez — uygulama kodundan “var mı diye kontrol et, sonra insert veya update yap” yaklaşımından çok daha iyidir.

Keyset (cursor tabanlı) sayfalama

Bunun yerine:

SELECT * FROM posts ORDER BY created_at DESC OFFSET 10000 LIMIT 20; -- derinlerde yavaş

Şunu kullanın:

SELECT * FROM posts
WHERE created_at < :last_seen_created_at
ORDER BY created_at DESC
LIMIT 20;

created_at (veya onunla birlikte kullanılan benzersiz bir eşitleyici) indekslendiği sürece, sayfa derinliğinden bağımsız sabit performans sağlar.

Soft delete (yumuşak silme)

ALTER TABLE orders ADD COLUMN deleted_at timestamptz;
CREATE INDEX idx_orders_active ON orders (id) WHERE deleted_at IS NULL;

“Aktif satırlar” sorgu kalıbı için her soft-delete kolonunu bir kısmi indeksle eşleştirin, yoksa silinen satırlar birikçe sorgular yavaşlar.

Optimistic locking (DB seviyesi kilit olmadan kayıp güncellemeleri önleme)

UPDATE accounts SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = :beklenen_versiyon;
-- etkilenen satır sayısını kontrol edin == 1; 0 ise, başka biri önce güncellemiştir — yeniden deneyin veya yeniden yükleyin

SKIP LOCKED ile job queue

(bkz. Bölüm 8) — ayrı bir mesaj broker’ı olmadan basit bir job/task kuyruğu için standart, Postgres’e özgü pattern.

Primary key’ler için UUIDv7

Primary key olarak rastgele (v4) UUID’ler, yeni değerler B-tree üzerinde sona eklenmek yerine rastgele dağıldığı için, yoğun insert yapılan tablolarda indeks parçalanmasına (fragmentation) neden olur. UUIDv7 (zamana göre sıralı; native destek olmayan Postgres sürümlerinde extension’lar veya uygulama seviyesi üretim ile desteklenir), UUID’nin benzersizlik/tahmin edilemezlik avantajlarını, sıralı bir integer’ın davranışına çok daha yakın, çok daha iyi insert lokalitesiyle birlikte sunar.

Trigger’larla denetim izi (audit trail)

CREATE TABLE orders_audit (LIKE orders INCLUDING ALL, operation text, changed_at timestamptz DEFAULT now());

CREATE OR REPLACE FUNCTION audit_orders() RETURNS trigger AS $$
BEGIN
    INSERT INTO orders_audit SELECT OLD.*, TG_OP, now();
    RETURN OLD;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER orders_audit_trigger
AFTER UPDATE OR DELETE ON orders
FOR EACH ROW EXECUTE FUNCTION audit_orders();

Hafif pub-sub için LISTEN/NOTIFY

LISTEN new_order;
NOTIFY new_order, '{"order_id": 123}';

Polling yapmadan DB olaylarına uygulama katmanı tepkileri tetiklemek için kullanışlıdır — ancak dayanıklı (durable) bir mesaj kuyruğu değildir (kimse dinlemiyorsa bildirimler kaybolur; garantili teslimat için gerçek bir kuyruk/CDC sistemi kullanın).


21. Migration’lar

ALTER TABLE orders ADD CONSTRAINT chk_positive CHECK (total >= 0) NOT VALID;
ALTER TABLE orders VALIDATE CONSTRAINT chk_positive;

22. İzleme (Monitoring) ve Gözlemlenebilirlik

Üretimde takip edilmesi gereken temel şeyler:


23. Kaçınılması Gereken Anti-Pattern’ler


24. Hızlı Referans Kontrol Listeleri

Yeni tablo kontrol listesi

Üretime bir migration deploy etmeden önce

Sorgu performansı kontrol listesi

Üretime hazırlık kontrol listesi


Bu rehber, çalışan bir backend/uygulama geliştiricisinin günlük olarak ihtiyaç duyduğu şeylerin büyük çoğunluğunu kapsar. Derin iç yapı detayları (depolama format detayları, WAL iç yapısı, planlayıcı maliyet modeli iç yapısı) için, gerçekten mükemmel olan ve otoriter detay için doğrudan okumaya değer resmi PostgreSQL dokümantasyonuna başvurun.