
PostgreSQL Kurulum ve Temel Yönetim Rehberi 2026: VDS Üzerinde Production
PostgreSQL 17 kurulumu, pg_hba.conf, postgresql.conf tuning, role/database/schema, MVCC ve autovacuum, EXPLAIN ANALYZE, WAL + PITR ve streaming replication — Buyukweb VDS perspektifinden DBA pratik rehberi.
PostgreSQL Kurulum ve Temel Yönetim Rehberi 2026: VDS Üzerinde Sıfırdan Production'a
PostgreSQL — özellikle 16 ve 17 sürümleriyle birlikte — JSONB indeksleme, generated column, hot standby replication ve gelişmiş extension ekosistemi gibi özelliklerle 2026'da ciddi web uygulamaları için ilk tercih olmaya devam ediyor. Türkiye'de barındırılan bir VDS üzerinde PostgreSQL'i apt install adımından point-in-time recovery'ye kadar production'a hazır hale getirmek için pratik bir DBA rehberine ihtiyacınız varsa bu yazı tam size göre.
Bu rehberde Buyukweb VDS perspektifinden Ubuntu 22.04 üzerinde PostgreSQL 16/17 kurulumu, pg_hba.conf ile auth katmanı, postgresql.conf tuning değerleri, role/database/schema kavram farklılıkları, MVCC ve autovacuum, EXPLAIN ANALYZE okuma, WAL + PITR, streaming replication ve bağlantı havuzlamayı tek seferde ele alıyoruz. Komutlar gerçek bir DBA'nın günlük yaşadığı pratik akışla anlatılıyor — kopyala-yapıştır değil, neden şu değer şu rakam, bunu açıklıyoruz.
Buyukweb perspektifi — dürüst notlar: cPanel paylaşımlı hosting paketlerimizde standart veritabanı motoru MariaDB 10.6 LTS'dir; PostgreSQL paylaşımlı paketlerde standart olarak gelmez ve kullanıcı yönetim arayüzü kısıtlıdır. PostgreSQL 16/17'yi tam kontrolle (sürüm seçimi, extension yükleme,
postgresql.confözelleştirme, replication kurulumu) çalıştırmak için VDS root erişimi gereklidir. Bu rehberin tüm adımları Buyukweb VDS (Bursa Tier 3 veri merkezi, ₺250/ay başlangıç) üzerinde doğrulanmıştır.
Neden PostgreSQL? Open Source DB Tercihinde 2026 Tablosu
PostgreSQL'i seçmek için somut gerekçeler — pazarlama dilinden uzak:
- Tam ACID + serileştirilebilir izolasyon:
SERIALIZABLEizolasyon seviyesi gerçek anlamda çalışır; mali işlemler ve stok yönetimi için kritik. - JSONB veri tipi: İndekslenebilir binary JSON; document-store ihtiyaçlarınızın çoğunu tek motorda karşılar.
- Extension ekosistemi: PostGIS (coğrafi sorgular), pg_trgm (fuzzy text search), pg_stat_statements (sorgu profilleme), TimescaleDB (zaman serisi), Citus (sharding), uuid-ossp, hstore, vector (pgvector — embedding araması).
- Generated column ve constraint exclusion: Schema seviyesinde hesaplanmış sütunlar; partition pruning ile büyük tablolarda performans.
- BSD-style PostgreSQL lisansı: Ticari kullanım için kısıt yok; vendor lock-in riski sıfır.
- Akademik miras: Berkeley POSTGRES projesinin doğrudan devamı; standartlara (SQL:2016, SQL/JSON 2023) titiz uyum.
- PostgreSQL Global Development Group her yıl bir ana sürüm yayınlar; her ana sürüm 5 yıl boyunca güvenlik güncellemesi alır. PostgreSQL 16 (Eylül 2023) için EOL Kasım 2028.
PostgreSQL vs MySQL: Temel Mimari Farklar
MySQL/MariaDB'den PostgreSQL'e geçenlerin sıklıkla şaşırdığı kavramsal farklar:
| Konu | PostgreSQL | MySQL/MariaDB |
|---|---|---|
| Concurrency model | MVCC (snapshot per transaction) | InnoDB row-level lock + MVCC |
| Schema namespace | Database > Schema > Table (3 seviye) | Database > Table (2 seviye) |
| Kullanıcı kavramı | ROLE (LOGIN ile user, NOLOGIN ile group) | USER + ayrı GRANT tabanlı role |
| DDL transaction | Tam (CREATE TABLE bile ROLLBACK olur) | Çoğu DDL otomatik commit |
| JSON | JSON (text) + JSONB (binary, indekslenebilir) | JSON (binary, MySQL 8 sonrası) |
| Generated column | STORED ve VIRTUAL (PG 12+) | STORED ve VIRTUAL |
| Tablo kalıtım | INHERITS (partitioning öncesi yaygındı) | Yok |
| Regex | POSIX + PCRE benzeri (~, ~*) |
POSIX, sınırlı |
| Replication | Streaming (physical) + logical | Statement / Row / Mixed binlog |
| Default encoding | UTF8 (initdb anında belirlenir) | utf8mb4 (önerilen) |
| Default port | 5432 | 3306 |
Kritik fark: PostgreSQL'de bir "database" içine girip ayrı veritabanlarına USE ile geçemezsiniz; bağlantı kurulurken DB seçilir. Aynı bağlantı içinde "tüm database'lere" sorgu atılmaz. Schema farklı: aynı DB içinde mantıksal namespace; search_path ile sıralı aranır.
PostgreSQL 16 mı 17 mi? Sürüm Seçimi
2026 başı itibarıyla:
- PostgreSQL 16 (Eylül 2023) — Production'da en yaygın; logical replication parallel apply, libpq sslnegotiation,
pg_stat_io. EOL: Kasım 2028. - PostgreSQL 17 (Eylül 2024) — Vacuum bellek verimliliği,
MERGE ... RETURNING, JSON_TABLE, incremental backup desteği. EOL: Kasım 2029.
Yeni kurulum için PostgreSQL 17 önerilir. Mevcut bir 14/15 kurulumu varsa pg_upgrade ile 17'ye geçiş test ortamında doğrulanmadan production'a alınmaz.
Ubuntu 22.04 VDS Üzerinde Kurulum (PGDG Reposu)
Buyukweb VDS'iniz Ubuntu 22.04 ile geldiyse Ubuntu'nun universe deposundaki sürüm güncel olmayabilir. PostgreSQL Global Development Group'un PGDG deposunu kullanın — her ana sürümü ayrı paket olarak sunar.
# Sistem paketlerini güncelle
sudo apt update && sudo apt upgrade -y
# PGDG repo anahtarı ve liste
sudo apt install -y curl ca-certificates gnupg lsb-release
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \
--fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | \
sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt update
sudo apt install -y postgresql-17 postgresql-contrib-17
# Servis durumu
sudo systemctl status postgresql
sudo systemctl enable postgresql
# Sürüm kontrolü
sudo -u postgres psql -c "SELECT version();"
PGDG paketi kurulduktan sonra:
- Veri dizini:
/var/lib/postgresql/17/main - Yapılandırma:
/etc/postgresql/17/main/postgresql.conf - Auth:
/etc/postgresql/17/main/pg_hba.conf - Log:
/var/log/postgresql/postgresql-17-main.log
postgres adlı sistem kullanıcısı otomatik oluşur ve PostgreSQL süper kullanıcısı olarak peer auth ile yerelden bağlanır.
AlmaLinux 9 / Rocky Linux 9 Üzerinde Kurulum
# PGDG repo
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# Built-in modülü devre dışı bırak
sudo dnf -qy module disable postgresql
# PostgreSQL 17 kur
sudo dnf install -y postgresql17-server postgresql17-contrib
# Cluster initdb (encoding ve locale UTF8 + tr_TR önerilir)
sudo PGSETUP_INITDB_OPTIONS="--locale=tr_TR.UTF-8 --encoding=UTF8" \
/usr/pgsql-17/bin/postgresql-17-setup initdb
# Servis aktif
sudo systemctl enable --now postgresql-17
RHEL ailesinde dosya yolları farklıdır: /var/lib/pgsql/17/data/ veri dizini, yapılandırma ve pg_hba.conf aynı dizin içindedir.
pg_hba.conf: Host-Based Authentication
pg_hba.conf (PostgreSQL'in kalbi denilebilecek dosya) hangi istemcinin, hangi DB'ye, hangi kullanıcıyla, hangi auth metoduyla bağlanabileceğini sırayla tanımlar. Satırlar yukarıdan aşağı okunur, ilk eşleşen kural uygulanır — sıralama kritik.
# TYPE DATABASE USER ADDRESS METHOD
# 1) Yerel postgres süper kullanıcısı (Linux peer)
local all postgres peer
# 2) Diğer yerel uygulamalar — SCRAM-SHA-256 ile parolayla
local all all scram-sha-256
# 3) Loopback IPv4 — uygulama 127.0.0.1'den bağlanırsa
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
# 4) Sadece belirli iç ağdan, sadece uygulama_db'ye, sadece uygulama_user
hostssl uygulama_db uygulama_user 10.0.0.0/24 scram-sha-256
# 5) Replication için ayrı kural (streaming replication)
hostssl replication replicator 10.0.0.50/32 scram-sha-256
# Genel internet erişimi açmayın — VDS'in pg portu (5432) firewall ile dışa kapalı tutulmalı
Auth Metodları Özeti
| Metod | Açıklama |
|---|---|
trust |
Parola sormadan kabul — sadece izole test ortamı |
peer |
Linux UID = PG kullanıcı adı eşleşmesi (sadece local) |
md5 |
MD5 parola hash — eski; yeni kurulumlarda kullanmayın |
scram-sha-256 |
PG 10+ önerilen parola yöntemi (default 14+) |
cert |
TLS istemci sertifikası |
ident |
OS-level kimlik eşlemesi (RFC 1413) |
reject |
Açıkça reddet |
pg_hba.conf değişikliği SELECT pg_reload_conf(); veya sudo systemctl reload postgresql ile aktif olur — restart gerekmez.
postgresql.conf Temel Tuning Değerleri
Buyukweb VDS'inde 8 GB RAM 4 vCPU bir cluster için pratik başlangıç değerleri:
# /etc/postgresql/17/main/postgresql.conf
# --- Bağlantı ---
listen_addresses = 'localhost' # Sadece yerel; uygulama aynı VDS'de
# Farklı sunucudan erişim için: '10.0.0.5,localhost'
port = 5432
max_connections = 100 # 100-200 üzeri için pgBouncer önerilir
# --- Bellek ---
shared_buffers = 2GB # ~25% RAM (8GB RAM için 2GB)
effective_cache_size = 6GB # ~75% RAM (planner için ipucu)
work_mem = 16MB # Her sort/hash op başına; (RAM-shared_buffers)/max_conn/2
maintenance_work_mem = 512MB # VACUUM, CREATE INDEX için
huge_pages = try # Linux huge pages varsa kullan
# --- WAL ve checkpoint ---
wal_level = replica # replica (default) / logical
max_wal_size = 2GB
min_wal_size = 80MB
checkpoint_timeout = 15min
checkpoint_completion_target = 0.9
wal_compression = on # PG 15+ pglz veya zstd
# --- Disk planner (NVMe SSD için) ---
random_page_cost = 1.1 # NVMe için ~1.1; HDD için 4.0
effective_io_concurrency = 200 # SSD/NVMe yüksek; HDD = 2
# --- Paralel sorgu (4 vCPU) ---
max_worker_processes = 4
max_parallel_workers_per_gather = 2
max_parallel_workers = 4
# --- Autovacuum (aşağıda detay) ---
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 30s
# --- Loglama ---
log_destination = 'stderr'
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_min_duration_statement = 500 # 500ms üstü sorguları logla
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 0 # Tüm temp dosyaları logla (work_mem küçükse uyarı)
log_line_prefix = '%m [%p] %q%u@%d '
# --- Statistics ---
shared_preload_libraries = 'pg_stat_statements'
pg_stat_statements.track = all
Tuning Hızlı Kuralları
| Parametre | Hesap |
|---|---|
shared_buffers |
RAM × 0.25 (max 8GB üstü genelde fayda azalır) |
effective_cache_size |
RAM × 0.75 (gerçek bellek tahsisi değil; planner ipucu) |
work_mem |
(RAM − shared_buffers) / (max_connections × 2) |
maintenance_work_mem |
256MB-1GB (VACUUM ve REINDEX hızını etkiler) |
max_wal_size |
Yazma yoğunluğuna göre 2-16 GB; checkpoint sıklığını dengeler |
random_page_cost |
NVMe: 1.1, SAS SSD: 1.5, HDD: 4.0 |
# Değişiklik sonrası
sudo systemctl restart postgresql # listen_addresses, max_connections, shared_buffers için
# Diğer çoğu için
sudo -u postgres psql -c "SELECT pg_reload_conf();"
Role, Database ve Schema Kavramı
PostgreSQL'de "kullanıcı" yoktur — yalnızca role vardır. LOGIN özelliği olan role bir kullanıcıdır; NOLOGIN bir gruptur.
-- Süper kullanıcı olarak (sudo -u postgres psql)
-- Uygulama login role
CREATE ROLE uygulama_user WITH LOGIN PASSWORD 'GucluP@rola2026' NOSUPERUSER NOCREATEDB NOCREATEROLE;
-- Salt-okuma rolü (group)
CREATE ROLE readonly_group NOLOGIN;
-- Bir okuyucu kullanıcı, gruba üye
CREATE ROLE rapor_user WITH LOGIN PASSWORD 'OkumaP@rola';
GRANT readonly_group TO rapor_user;
-- Veritabanı oluştur, sahibi uygulama_user
CREATE DATABASE uygulama_db OWNER uygulama_user
ENCODING 'UTF8'
LC_COLLATE 'tr_TR.UTF-8'
LC_CTYPE 'tr_TR.UTF-8'
TEMPLATE template0;
-- Schema yapısı (uygulama_db içine bağlanıp çalıştırılır: \c uygulama_db)
CREATE SCHEMA app AUTHORIZATION uygulama_user;
CREATE SCHEMA logs AUTHORIZATION uygulama_user;
-- Schema yetkileri
GRANT USAGE ON SCHEMA app TO readonly_group;
GRANT SELECT ON ALL TABLES IN SCHEMA app TO readonly_group;
ALTER DEFAULT PRIVILEGES IN SCHEMA app
GRANT SELECT ON TABLES TO readonly_group;
-- search_path: schema arama sırası
ALTER ROLE uygulama_user SET search_path = app, public;
search_path aktif sırayı belirler. SELECT * FROM kullanicilar; sorgusunda PostgreSQL önce app.kullanicilar, sonra public.kullanicilar arar. Yanlış schema'ya yazmak istemiyorsanız search_path netleştirmek üretimde kritiktir.
psql: Günlük DBA Komutları
psql bir terminal istemcisi değil — adeta bir editör; meta-komutlar (\-prefixed) inanılmaz hız kazandırır.
$ sudo -u postgres psql
psql (17.0)
Type "help" for help.
postgres=# \l -- Tüm DB'leri listele (size, encoding, owner)
postgres=# \c uygulama_db -- DB'ye bağlan
You are now connected to database "uygulama_db".
uygulama_db=# \dt -- public schema tabloları
uygulama_db=# \dt app.* -- app schema tabloları
uygulama_db=# \d app.kullanicilar -- Tablo yapısı + indeksler + constraint
uygulama_db=# \du -- Tüm role'ler
uygulama_db=# \dn -- Schema'ları listele
uygulama_db=# \dx -- Yüklü extension'lar
uygulama_db=# \df app.* -- app schema fonksiyonları
uygulama_db=# \timing on -- Sorgu süresi ölçümünü aç
uygulama_db=# \x -- Genişletilmiş çıktı (uzun satır için)
uygulama_db=# \e -- Sorguyu $EDITOR ile düzenle
uygulama_db=# \i /tmp/script.sql -- Dosyadan SQL çalıştır
uygulama_db=# \copy urunler FROM 'urunler.csv' CSV HEADER
uygulama_db=# \? -- Tüm meta-komut yardım
uygulama_db=# \q -- Çıkış
COPY ... FROM PostgreSQL'in en hızlı toplu yükleme aracıdır — INSERT'lerden 10-100x daha hızlı. CSV import için \copy istemci tarafı dosyayı okur, COPY sunucu tarafını.
CRUD ve Transaction Yönetimi
-- Tablo (zengin tip kullanımı)
CREATE TABLE app.urunler (
id BIGSERIAL PRIMARY KEY,
sku VARCHAR(32) NOT NULL UNIQUE,
isim TEXT NOT NULL,
fiyat NUMERIC(12,2) NOT NULL CHECK (fiyat >= 0),
stok INTEGER NOT NULL DEFAULT 0,
ozellikler JSONB,
etiketler TEXT[],
aktif BOOLEAN NOT NULL DEFAULT TRUE,
olusturulma TIMESTAMPTZ NOT NULL DEFAULT NOW(),
guncelleme TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- INSERT ... RETURNING — eklenen satırı geri döner (auto-increment ID için pratik)
INSERT INTO app.urunler (sku, isim, fiyat, stok, ozellikler, etiketler)
VALUES ('NB-001', 'İş Laptopu 14"', 24999.90, 25,
'{"marka":"Generic","ram":"16GB","ssd":"512GB"}',
ARRAY['laptop','i5','ofis'])
RETURNING id, isim;
-- JSONB sorguları
SELECT id, isim FROM app.urunler WHERE ozellikler->>'marka' = 'Generic';
SELECT id FROM app.urunler WHERE ozellikler @> '{"ram":"16GB"}';
-- Array sorgu
SELECT id FROM app.urunler WHERE 'laptop' = ANY(etiketler);
-- Transaction ve savepoint
BEGIN;
UPDATE app.urunler SET stok = stok - 1 WHERE sku = 'NB-001';
SAVEPOINT after_decrement;
UPDATE app.urunler SET aktif = FALSE WHERE stok = 0;
-- Hata olursa savepoint'e dön
-- ROLLBACK TO SAVEPOINT after_decrement;
COMMIT;
-- İzolasyon seviyesi (mali işlem için)
BEGIN ISOLATION LEVEL SERIALIZABLE;
-- iş mantığı
COMMIT;
SERIALIZABLE izolasyonda phantom read engellenir; PostgreSQL gerekirse could not serialize access hatasıyla işlemi durdurur — uygulama bunu yakalayıp retry mantığı kurmalı.
MVCC, Dead Tuple, VACUUM ve Autovacuum
PostgreSQL Multi-Version Concurrency Control (MVCC) kullanır. Bir UPDATE eski satırı silmez; yeni bir versiyon yazar, eskisini "dead tuple" olarak işaretler. Aktif okuyucular kendi snapshot'larındaki eski versiyonu görebilsin diye eski versiyonlar tutulur.
Sonuç: yoğun yazma altında tablolar bloat eder. Dead tuple'ları temizleyen mekanizma VACUUM'dur, otomatik versiyonu autovacuum.
-- Dead tuple ölçümü
SELECT schemaname, relname,
n_live_tup,
n_dead_tup,
round(100.0 * n_dead_tup / NULLIF(n_live_tup + n_dead_tup, 0), 2) AS dead_pct,
last_vacuum,
last_autovacuum
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;
-- Manuel vacuum (tabloyu kilitlemez; autovacuum'un sıkışık olduğu durumlar için)
VACUUM (VERBOSE, ANALYZE) app.urunler;
-- VACUUM FULL — disk alanı geri kazanır AMA tabloyu ACCESS EXCLUSIVE lock ile kilitler
-- Üretimde nadiren; ekonomik değildir. pg_repack extension'ı online alternatif sunar.
VACUUM FULL app.eski_loglar;
Autovacuum Tuning İpuçları
# postgresql.conf — yoğun yazılan tablo varsa daha agresif
autovacuum_vacuum_scale_factor = 0.1 # %10 dead tuple → vacuum (default 0.2)
autovacuum_analyze_scale_factor = 0.05 # %5 değişiklik → analyze (default 0.1)
autovacuum_vacuum_cost_limit = 2000 # Daha az throttle (default 200)
Tek tablo bazında:
ALTER TABLE app.aktif_oturumlar SET (
autovacuum_vacuum_scale_factor = 0.05,
autovacuum_analyze_scale_factor = 0.02
);
pg_stat_user_tables ekran çıktısında dead_pct > 20 olan tablo varsa autovacuum yetişmiyordur — ya autovacuum_max_workers artırın ya da tablo özelinde scale_factor düşürün.
Index Türleri ve Ne Zaman Hangisi
PostgreSQL'in index çeşitliliği MySQL'den belirgin biçimde geniş:
| Türü | Kullanım | Örnek |
|---|---|---|
| B-Tree (default) | Eşitlik + aralık (=, <, BETWEEN, ORDER BY) |
CREATE INDEX ON urunler(fiyat); |
| Hash | Sadece eşitlik; nadiren faydalı, B-Tree çoğu zaman yeter | CREATE INDEX ... USING HASH(sku); |
| GIN | JSONB, full-text search, array, hstore | CREATE INDEX ON urunler USING GIN(ozellikler); |
| GiST | Geometric, PostGIS, range type, fuzzy text (pg_trgm) | CREATE INDEX ON poligonlar USING GIST(geom); |
| SP-GiST | Non-balanced tree; quad-tree, k-d tree | Nadiren özel kullanım |
| BRIN | Çok büyük zaman serisi tablolarda fiziksel sırayla korelasyon | CREATE INDEX ON loglar USING BRIN(zaman); |
-- Composite index (sıra önemli — en sık WHERE'de kullanılan başta)
CREATE INDEX idx_urunler_aktif_fiyat ON app.urunler(aktif, fiyat) WHERE aktif = TRUE;
-- Partial index — sadece aktif ürünleri indeksle (boyut küçük, hızlı)
CREATE INDEX idx_urunler_aktif ON app.urunler(olusturulma) WHERE aktif = TRUE;
-- Expression index
CREATE INDEX idx_urunler_lower_isim ON app.urunler(LOWER(isim));
-- JSONB GIN
CREATE INDEX idx_urunler_ozellik_gin ON app.urunler USING GIN(ozellikler);
-- BRIN: 100M satırlı log tablosunda
CREATE INDEX idx_loglar_brin ON loglar USING BRIN(zaman) WITH (pages_per_range = 32);
pg_stat_user_indexes üzerinden kullanılmayan indeksler tespit edilebilir — idx_scan = 0 olanlar muhtemelen drop edilmeli (yazma performansını yavaşlatırlar).
EXPLAIN ANALYZE: Sorgu Planını Okumak
Her DBA'nın günlük aracı. EXPLAIN planı tahmin eder, EXPLAIN ANALYZE gerçekten çalıştırır ve süreyi raporlar.
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT u.id, u.isim, k.email
FROM app.urunler u
JOIN app.kullanicilar k ON k.id = u.olusturan_id
WHERE u.aktif = TRUE AND u.fiyat > 1000
ORDER BY u.olusturulma DESC
LIMIT 50;
Çıktı parçası:
QUERY PLAN
-----------------------------------------------------------------------
Limit (cost=0.85..123.45 rows=50 width=72) (actual time=0.124..2.456 rows=50 loops=1)
-> Nested Loop (cost=0.85..2456.78 rows=1000 width=72) (actual time=0.121..2.401 rows=50 loops=1)
Buffers: shared hit=145 read=8
-> Index Scan Backward using idx_urunler_olusturulma on urunler u
Index Cond: (aktif = true)
Filter: (fiyat > 1000)
Rows Removed by Filter: 12
-> Index Scan using kullanicilar_pkey on kullanicilar k
Index Cond: (id = u.olusturan_id)
Planning Time: 0.234 ms
Execution Time: 2.512 ms
Plan Okuma Hızlı Rehberi
| Operatör | Anlam |
|---|---|
| Seq Scan | Tablo baştan sona okunuyor — küçük tablo iyi, büyük tabloda kötü işaret |
| Index Scan | Index üzerinden okuma — genelde iyi |
| Index Only Scan | Sadece indeks yeterli (covering index) — en hızlı |
| Bitmap Heap Scan | Index ile önce tabloda yer bul, sonra topla — orta yoğun WHERE'de yaygın |
| Nested Loop | Küçük outer × index lookup — küçük sonuç setinde iyi |
| Hash Join | Büyük tablolar arası eşitlik join — tipik orta-büyük veri |
| Merge Join | İki sıralı set birleştirme |
actual time ile cost arasında büyük fark varsa istatistikler güncel değildir → ANALYZE tablo;. Rows Removed by Filter çok yüksek ise indekste WHERE koşulu yer almıyordur — partial veya composite index düşünün.
WAL ve Point-in-Time Recovery (PITR)
Write-Ahead Log her yazma işleminin değişikliğini önce log dosyasına yazar; çökmede bütünlük garantisi WAL'dir. PITR, baz alınmış (base backup) bir snapshot + ardından gelen WAL dosyalarını ileri oynatarak istenen ana geri yükleme yapar.
# postgresql.conf — WAL arşivleme aç
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /var/backups/pg_wal_archive/%f && cp %p /var/backups/pg_wal_archive/%f'
archive_timeout = 60 # En geç 60sn'de bir WAL dosyasını döndür
Manuel base backup:
# Replication kullanıcısı
sudo -u postgres psql -c "CREATE ROLE repuser WITH REPLICATION LOGIN PASSWORD 'RepP@rola';"
# Base backup (online — uygulamayı durdurmaz)
sudo -u postgres pg_basebackup -D /var/backups/pg_base/2026-05-10 \
-F tar -z -P -U postgres
pg_basebackup PostgreSQL ile gelen yerleşik araçtır. Daha gelişmiş senaryolarda (incremental backup, paralel restore, WAL archive yönetimi) pgBackRest veya Barman topluluk araçları tercih edilir.
# pgBackRest tipik kurulum (apt veya dnf)
sudo apt install pgbackrest
# /etc/pgbackrest/pgbackrest.conf örnek
# [global]
# repo1-path=/var/lib/pgbackrest
# repo1-retention-full=2
# [main]
# pg1-path=/var/lib/postgresql/17/main
PITR senaryosu — "yanlışlıkla DROP TABLE çalıştı, 14:30'a dön":
# 1) PostgreSQL'i durdur
sudo systemctl stop postgresql
# 2) Mevcut data dizinini taşı (silmek yerine)
sudo mv /var/lib/postgresql/17/main /var/lib/postgresql/17/main.broken
# 3) Base backup'ı geri yükle
sudo -u postgres tar -xzf /var/backups/pg_base/2026-05-10/base.tar.gz \
-C /var/lib/postgresql/17/main
# 4) recovery.signal dosyası oluştur (PG 12+ için)
sudo -u postgres touch /var/lib/postgresql/17/main/recovery.signal
# 5) postgresql.conf'a recovery hedefi ekle
# restore_command = 'cp /var/backups/pg_wal_archive/%f %p'
# recovery_target_time = '2026-05-10 14:30:00 +03'
# 6) Servisi başlat — recovery otomatik
sudo systemctl start postgresql
PostgreSQL hedef zamana kadar WAL'ları oynatır, sonra recovery moduna geçer. Promotion için pg_promote() çağrılır.
Streaming Replication: Primary + Hot Standby
Yüksek erişilebilirlik veya okuma replikası için streaming replication. Primary WAL'ı ağ üzerinden standby'a stream eder.
# Primary: postgresql.conf
wal_level = replica
max_wal_senders = 5
wal_keep_size = 1GB
synchronous_commit = on # senkron mod (gecikmeli ama veri kaybı yok)
synchronous_standby_names = 'standby1'
# Primary: pg_hba.conf
hostssl replication repuser 10.0.0.50/32 scram-sha-256
Standby kurulumu:
# Standby sunucuda — boş data dizini
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/17/main/*
# Primary'den base backup çek
sudo -u postgres pg_basebackup -h primary.dahili -U repuser \
-D /var/lib/postgresql/17/main -P -R
# -R standby.signal ve primary_conninfo'yu otomatik yazar
sudo systemctl start postgresql
hot_standby = on (default) ile standby okuma sorguları kabul eder. Replikasyon gecikmesi:
-- Primary üzerinde
SELECT client_addr, state, sent_lsn, write_lsn, flush_lsn, replay_lsn,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS replay_lag_bytes
FROM pg_stat_replication;
-- Standby üzerinde
SELECT now() - pg_last_xact_replay_timestamp() AS replication_delay;
Otomatik failover için Patroni + etcd/Consul topluluk çözümü standarttır; Patroni cluster lider seçimi, otomatik standby promotion ve split-brain önleme yönetir.
Bağlantı Havuzu: pgBouncer Notu
PostgreSQL her bağlantı için ayrı bir backend process açar (~5-10 MB RAM/bağlantı). 200+ eşzamanlı bağlantı için bağlantı havuzu kritik. Bu konuda Buyukweb blog'unda ayrıntılı yazımız var; özetle:
- pgBouncer 6432 portunda dinler
- Üç pool modu: session / transaction / statement (transaction en yaygın)
max_client_conn(uygulama tarafı) >>default_pool_size(gerçek PG bağlantısı)- Transaction mode'da prepared statement ile dikkat — uygulama tarafında
prepareThreshold=0veya benzer ayar
cPanel paylaşımlı paketlerimizde: PostgreSQL standart olarak gelmediğinden pgBouncer da paylaşımlı paketler kapsamında değildir. Self-host PostgreSQL + pgBouncer kombinasyonu VDS üzerinde uygulanır.
Yedekleme Stratejisi: Logical + Physical
Üretimde her ikisi de gerekli:
# Logical (pg_dump) — schema/veri SQL veya custom format
sudo -u postgres pg_dump -Fc -d uygulama_db -f /var/backups/uygulama_db.dump
# Belirli schema
sudo -u postgres pg_dump -Fc -n app -d uygulama_db -f /var/backups/app_schema.dump
# Tüm cluster (role'ler + DB'ler)
sudo -u postgres pg_dumpall > /var/backups/all_$(date +%F).sql
# Restore (custom format için)
sudo -u postgres pg_restore -d uygulama_db -j 4 /var/backups/uygulama_db.dump
# Physical (pg_basebackup) — yukarıda PITR bölümünde
Buyukweb VDS'lerinde JetBackup ile haftalık otomatik snapshot ve manual recurring seçenekleri kullanılabilir; veritabanı tutarlılığı için pg_dump çalıştıran cron + JetBackup ikisinin birlikte çalıştırılması önerilir (cron pg_dump, JetBackup file system snapshot).
# /etc/cron.daily/pgbackup — günlük logical dump (7 gün retention)
#!/bin/bash
DUMP_DIR=/var/backups/postgresql
mkdir -p \$DUMP_DIR
sudo -u postgres pg_dump -Fc uygulama_db > \$DUMP_DIR/uygulama_db_$(date +%F).dump
find \$DUMP_DIR -name "*.dump" -mtime +7 -delete
Buyukweb VDS'de Production Checklist
Bursa Tier 3 veri merkezimizdeki VDS'lerde PostgreSQL'i internete açmak yerine güvenli mimari:
- Firewall (
ufwveyafirewalld) ile 5432 portu sadece uygulama sunucularına açık (varsayılan: dış kapalı) - Uygulama aynı VDS'de değilse SSH tunnel veya WireGuard üzerinden iç ağda
-
hostsslzorunlu, sertifika/etc/postgresql/17/main/server.crt - Role'ler least-privilege: uygulama_user
NOSUPERUSER NOCREATEDB NOCREATEROLE -
scram-sha-256zorunlu,md5vetrustkaldırıldı -
log_min_duration_statement = 500; yavaş sorgu izleme -
pg_stat_statementsile sorgu profilleme - Autovacuum izleniyor (
pg_stat_user_tableshaftalık denetim) -
fail2banPostgreSQL log filter eklendi (parola brute force engelleme) - WAL arşivleme + günlük
pg_dump+ JetBackup kombinasyonu - Disk doluluğu
pg_database_sizevepg_total_relation_sizeile izleniyor - Yıllık major sürüm yükseltme planı (pg_upgrade test ortamında doğrulandı)
cPanel Paylaşımlı Paketlerde PostgreSQL Durumu — Dürüst Açıklama
Bunu net belirtelim: Buyukweb cPanel paylaşımlı hosting paketlerinde standart veritabanı motoru MariaDB 10.6 LTS'dir. cPanel arayüzünde phpPgAdmin/PostgreSQL menüsü kısıtlıdır; küçük WordPress/PHP siteler için MariaDB tamamen yeterlidir ve bizim önerimizdir.
PostgreSQL kullanan bir uygulama (Django, Rails, Node.js + Sequelize/Prisma, Java + Spring) çalıştıracaksanız:
- Küçük ölçek: VDS ile root erişim, kendi PostgreSQL'i yönetirsiniz
- Orta ölçek: E5 v4 VDS ile NVMe IOPS avantajı
- Büyük ölçek: Fiziksel Dedicated ile tam donanım kontrol
Hangisi sizin senaryonuza uygun, paket karşılaştırma sayfamıza bakabilir veya 0850 302 60 70 numaramızdan teknik ekibe sorabilirsiniz.
Sıkça Sorulan Sorular
PostgreSQL 16 mı 17 mi seçmeliyim?
Yeni kurulum için PostgreSQL 17. Vacuum bellek verimliliği, MERGE ... RETURNING ve JSON_TABLE 17'de geliyor. Mevcut bir 14/15 üretim sisteminiz varsa pg_upgrade'i test ortamında doğrulamadan production'a almayın; major upgrade extension uyumluluğu (örn. PostGIS, TimescaleDB) gerektirir.
work_mem değerini nasıl seçmeliyim?
Formül: (RAM − shared_buffers) / (max_connections × 2). 8 GB RAM, 100 max_connections, 2 GB shared_buffers için yaklaşık 30 MB. Karmaşık sort/hash içeren analitik sorgular için tek seans bazında SET work_mem = '256MB'; ile artırılabilir — global olarak yüksek tutmak bellek tükenmesi riski oluşturur (her bağlantı × her sort/hash op kadar tahsis eder).
autovacuum yetişmiyor, dead_pct sürekli %30 üstünde — ne yapmalıyım?
Önce pg_stat_progress_vacuum ile aktif vacuum süreçlerini izleyin. Çözümler: autovacuum_max_workers 3'ten 5-6'ya çıkarın, autovacuum_vacuum_cost_limit artırın (default 200, 1000-2000 yapın), problemli tablo özelinde ALTER TABLE ... SET (autovacuum_vacuum_scale_factor = 0.05);. Tablo zaten ciddi bloat olmuşsa pg_repack ile online reorganize edin (VACUUM FULL üretimde tabloyu kilitler).
Streaming replication mi logical replication mı?
Streaming (physical) replication tüm cluster'ı bir bütün olarak replike eder — disaster recovery ve okuma standby'ı için ideal. Logical replication (PG 10+) tablo seviyesinde, farklı major sürümler arası taşıma ve sadece bazı tabloları replike etme senaryolarında kullanılır. Tipik HA için streaming + Patroni; selektif veri taşıma için logical.
PostgreSQL'i internete (5432) açmak güvenli mi?
Hayır. Otomatik tarayıcılar (shodan benzeri tarama, brute force) varsayılan portu sürekli yokluyor. Best practice: VDS firewall'ında 5432 dış kapalı, uygulama aynı VDS veya iç ağda; uzaktan yönetim için SSH tunnel (ssh -L 5432:localhost:5432 user@vds) veya WireGuard. Mutlaka açmak gerekiyorsa: hostssl zorunlu + IP allowlist + scram-sha-256 + fail2ban.
Sonuç
PostgreSQL 17, doğru yapılandırılmış bir VDS üzerinde yıllarca güvenli ve hızlı çalışacak temeli ücretsiz olarak sunuyor. Bu rehberde apt install adımından autovacuum tuning ve PITR'a kadar olan yolu DBA gözüyle gezdik; production checklist ile kritik 12 maddeyi listeledik.
Buyukweb VDS (Bursa Tier 3, root yetkili, ₺250/ay başlangıç) üzerinde PostgreSQL 17 + uygun extension'lar tamamen sizin kontrolünüzdedir. cPanel paylaşımlı paketler MariaDB ile küçük PHP/WordPress sitelere uygundur; PostgreSQL stack için VDS veya üzeri bir paket gereklidir.
Teknik destek için 0850 302 60 70 numaralı destek hattımıza veya iletişim sayfamıza ulaşabilirsiniz.
İlgili Büyükweb Hizmetleri
PostgreSQL self-host için altyapı seçenekleri:
- VDS Sunucu — Root yetkili, PostgreSQL 17 + extension'lar serbestçe kurulur
- E5 v4 VDS — NVMe SSD, yüksek IOPS, yoğun veritabanı iş yükleri için
- Fiziksel Dedicated — Tam donanım kontrol, büyük ölçekli cluster
- Paket Karşılaştırma — PostgreSQL ihtiyacınıza uygun paketi seçin
- cPanel Web Hosting — MariaDB 10.6 LTS, küçük PHP/WordPress siteler için
Sorularınız için 0850 302 60 70 numaralı destek hattımıza veya iletişim sayfamıza yazabilirsiniz.
Veritabanı Yönetimi İlgili Hizmetlerimiz
Bu yazıda anlatılan teknik konuyu profesyonel altyapıyla deneyimleyin
Etiketler:

