---
title: "İndeksler: Eksik Yavaşlatır, Fazlası Yazmayı Öldürür"
description: "Eksik indeks sorguyu yavaşlatır, gereğinden fazla indeks her yazma işlemini pahalılaştırır. Doğru dengeyi tahminle değil ölçümle kurmak."
url: https://sade.dev/tr/notes/indeks-yonetimi/
lang: tr
author: "Muhammet Şafak"
published: 2026-09-05
updated: 2026-09-06
section: Note
tags: ["postgresql","database","performance","indexing"]
summary: "İndeks bedava okuma hızı değil, yazmayla ödenmiş okuma hızıdır. Her INSERT tablonun her indeksine bir girdi yazar; her UPDATE de indeksli bir kolona dokunduğu anda aynısını yapar. HOT güncellemesi ve kısmi indeks istisnadır, varsayılan değil. Bu yüzden indeksi gerçek bir sorgu planı istediği için ekleyin, pg_stat_user_indexes idx_scan = 0 gösterdiği için silin."
---

# İndeksler: Eksik Yavaşlatır, Fazlası Yazmayı Öldürür

> İndeks bedava okuma hızı değil, yazmayla ödenmiş okuma hızıdır. Her INSERT tablonun her indeksine bir girdi yazar; her UPDATE de indeksli bir kolona dokunduğu anda aynısını yapar. HOT güncellemesi ve kısmi indeks istisnadır, varsayılan değil. Bu yüzden indeksi gerçek bir sorgu planı istediği için ekleyin, pg_stat_user_indexes idx_scan = 0 gösterdiği için silin.

İki karşıt ekip gördüm. Biri tabloya hiç indeks koymamıştı — her sorgu bir sequential scan, her liste sayfası saniyeler sürüyordu. Diğeri tam tersini yapmıştı: "ne olur ne olmaz" diye her kolona bir indeks açmıştı ve şimdi her `INSERT` ağır aksak ilerliyordu.

İkisi de aynı yanılgının iki ucu: indeksi ücretsiz bir hız kaynağı sanmak.

## İndeks ücretsiz hız değildir

Bir indeks okumayı hızlandırır, çünkü veritabanı tüm tabloyu taramak yerine sıralı bir yapıya bakar. Ama o sıralı yapı kendi kendine güncel kalmaz: tablodaki bir `INSERT`, o tablonun **her indeksine** bir girdi yazar; bir `UPDATE` de indeksli bir kolona dokunduğu anda aynısını yapar. İstisnalar var — indeksli hiçbir kolonu değiştirmeyen HOT güncellemesi indekslere dokunmaz, kısmi indeks yüklemi dışında kalan satırlar için güncellenmez, `DELETE` ise indeks girdilerini temizlemeyi `VACUUM`'a bırakır — ama bunlar istisna, varsayılan değil.

Yani her indeks bir takastır: okuma hızını, yazma maliyetiyle satın alırsınız. Beş indeksli bir tabloya tek satır eklemek, altı yapıyı birden güncellemektir. İndeks "bedava okuma hızı" değil, "yazmayla ödenmiş okuma hızı"dır.

## Eksik indeks: tahmin değil, ölçüm

Eksik indeksi sorgu planından bulun, tahminden değil:

```sql
EXPLAIN ANALYZE
SELECT * FROM orders WHERE status = 'pending';
```

Çıktıda büyük bir tabloda `Seq Scan` görüyorsanız ve sorgu satırların küçük bir kısmını döndürüyorsa, muhtemelen bir indeks eksiktir. `pg_stat_user_tables` tablosunda `seq_scan` sayısı yüksek olan büyük tabloları tarayın — bunlar adaylarınızdır.

İndeksi gerçek, yavaş bir sorgu için ekleyin. "İleride lazım olabilir" diye eklenen indeks, [spekülatif genelliğin](/tr/journal/ileride-lazim-olur-kodunun-faturasi) veritabanı katmanındaki hâlidir.

## Fazla indeks: kullanılmayanı bul

Ters yönde, hiç kullanılmayan indeksler her yazmayı boş yere pahalılaştırır. Onları da ölçümle bulun:

```sql
SELECT indexrelname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0;
```

`idx_scan = 0` olan bir indeks hiç okuma hızlandırmıyor ama her yazmaya maliyet ekliyor demektir. (Primary key ve unique kısıtların indekslerini elbette koruyun.) Bu, [veri yoğunluklu sistemlerin](/tr/systems/veri-yogunluklu-sistemler-kirilma-noktalari) yazma kırılma noktasında sayılan ilk temizliktir.

## Doğru indeksi nasıl seçersiniz?

İndeks "var/yok"tan ibaret değildir; doğru türü ve şekli seçmek önemlidir:

- **Bileşik indekste kolon sırası.** `(a, b)` indeksi, `a`'da eşitlik + `b`'de aralık sorgusuna hizmet eder; `b`'de tek başına yapılan bir arama da bu indeksi kullanabilir ama taranan indeks bölümünü daraltmaz — PostgreSQL 18 öncesinde indeksin tamamı taranır, 18'den itibaren skip scan optimizasyonu bunu daraltır. Eşitlikle filtrelenen kolonu başa, aralıkla filtreleneni sona koyun.
- **Kısmi indeks (partial).** Sorgu hep aynı alt kümeye bakıyorsa indeksi de o alt kümeyle sınırlayın: `CREATE INDEX ... WHERE status = 'active'`. Daha küçük indeks, daha ucuz bakım.
- **Covering indeks.** `INCLUDE` ile sık okunan kolonları indekse ekleyip veritabanının tabloya hiç gitmemesini sağlayabilirsiniz.
- **B-tree dışı türler.** Eşitlik/sıralama için B-tree; `jsonb` ve tam metin için GIN; saf sıralı, append ağırlıklı veri için küçük ve ucuz BRIN.

## Duplikat ve örtüşen indeksler

`(a)` üzerindeki bir indeks, zaten `(a, b)` indeksiniz varsa gereksizdir — bileşik indeks `a` ile başlayan sorgulara da hizmet eder. Bu tür örtüşmeleri periyodik olarak temizleyin; her biri sessiz bir yazma vergisidir.

## Denge sorgu planıyla kurulur

Tek kural: indeksi ne tahminle ekleyin ne tahminle silin. Bir indeks, gerçek bir sorgu planı onu istediği için eklenir; bir indeks, istatistikler onu kimsenin kullanmadığını gösterdiği için silinir. Eksik ile fazla arasındaki denge, hislerle değil, `EXPLAIN ANALYZE` ve `pg_stat_user_indexes` ile kurulur.

---

İndeks yönetimi, "daha çok indeks daha iyi" sanısından kurtulmakla başlar. Her indeks bir okuma kazancı ve bir yazma maliyetidir; iyi yönetim, bu ikisini ölçerek dengede tutmaktır.

Eksik indeks sorguyu yavaşlatır; fazlası ise tüm tabloyu. İkisinden de ölçüm korur.

## Sık sorulanlar

**Her INSERT tablodaki her indeksi güncellemek zorunda mıdır?**

INSERT için evet: yeni satır her indekste bir girdi alır. UPDATE farklıdır. İndeksli hiçbir kolonu değiştirmeyen HOT güncellemesi indekslere dokunmaz, kısmi indeks ise yüklemi dışında kalan satırlar için güncellenmez. DELETE ise indeks girdilerini temizlemeyi VACUUM'a bırakır.

**Kullanılmayan indeksler nasıl bulunur?**

pg_stat_user_indexes tablosunda idx_scan = 0 olanları sorgulayın. Bu indeksler hiçbir okumayı hızlandırmıyor ama her yazmaya maliyet ekliyordur. Primary key ve unique kısıtları taşıyan indeksleri her hâlükârda koruyun.


## Kaynaklar

- [CREATE INDEX: CONCURRENTLY, INCLUDE, partial indexes and index methods](https://www.postgresql.org/docs/current/sql-createindex.html) — PostgreSQL
- [Multicolumn Indexes: column order and the skip scan optimization](https://www.postgresql.org/docs/current/indexes-multicolumn.html) — PostgreSQL
- [PostgreSQL 18 Release Notes: allow skip scans of btree indexes](https://www.postgresql.org/docs/release/18.0/) — PostgreSQL
- [Heap-Only Tuples (HOT)](https://www.postgresql.org/docs/current/storage-hot.html) — PostgreSQL
