30 puan yazan GN⁺ 2026-01-26 | 1 yorum | WhatsApp'ta paylaş
  • PostgreSQL indeksleri, veri erişim hızını artırmak için kullanılan temel yapılardır; diskten okunması gereken veri miktarını azaltarak sorgu performansını iyileştirir
  • İndeksler Btree, Hash, BRIN, GIN, GiST, SP-GiST gibi çeşitli biçimlerde sunulur ve her biri farklı veri özellikleri ile sorgu kalıplarına göre optimize edilmiştir
  • İndeksler; disk alanı, yazma performansı, sorgu planlayıcısının karmaşıklığı, bellek kullanımı gibi çeşitli maliyetler de getirir
  • Kısmi indeks, çok sütunlu indeks, covering index, ifade indeksi gibi gelişmiş özelliklerle belirli durumlarda verimlilik en üst düzeye çıkarılabilir
  • Uygun indeks seçimi ve yönetiminin, PostgreSQL performans optimizasyonunun temel unsurlarından biri olduğu vurgulanır

İndekslerin temel kavramı

  • İndeks, veritabanının diskten okuduğu veri miktarını azaltarak sorgu hızını artıran bir yapıdır
    • Birincil anahtar, benzersiz anahtar ve dışlayıcı kısıtlar gibi yapılar da indeksler aracılığıyla uygulanır
    • Sorgu sonucu tüm tablonun %15~20'sinden az olduğunda indeksler etkilidir; bunun üzerindeyse sıralı tarama daha verimli olabilir
  • PostgreSQL varsayılan olarak 6 tür indeks sunar ve eklentilerle daha fazla tür kullanılabilir
    • Her indeks, anahtar değerleri ile ilgili veri konumunu (TID) birbirine bağlar

Diskte saklanan veri yapısı

  • PostgreSQL tabloları heap dosyaları olarak saklanır ve 8KB sayfalardan oluşur
  • Her satır (tuple) belirli bir sıra olmadan saklanır; iç adresi ctid (current tuple id) ile tanımlanır
    • Örnek: (0,1) sayfa 0'daki ilk tuple anlamına gelir
  • İndeksler bu heap konumlarını (ctid) ağaç yapısıyla bağlayarak hızlı aramayı destekler

İndekslerin veri erişimini hızlandırma biçimi

  • İndeks olmadığında PostgreSQL, tüm sayfaları okuyan bir sıralı tarama gerçekleştirir
    • Örnek sorguda name='Ronaldo' aranırken 6272 sayfa okunur ve 265ms sürer
  • İndeks eklendiğinde işlem Index Scan'e dönüşür; yalnızca 4 sayfa okunur ve 0.077ms'de tamamlanır
    • İndeks, değer ile ctid arasında eşleme kurarak yalnızca gerekli satırları hızlıca bulur
  • İndeks dosyası boyutu tablo boyutuna yakın olabilir (ör. 30MB tablo → 30MB indeks)

İndekslerin maliyet unsurları

  • İndeksler performans artışının yanında çeşitli yükler de getirir

Disk alanı

  • İndeksler ayrı depolama alanı kullanır ve tablodan daha büyük olabilir
    • Yedekleme, replikasyon ve felaket kurtarma sırasında ek maliyet oluşturur
    • Kısmi indeksler, çok sütunlu indeksler, BRIN gibi yöntemlerle alan verimliliği artırılabilir

Yazma işlemleri

  • UPDATE, INSERT, DELETE sırasında indeksli sütunlar değişirse indeks güncelleme ek yükü oluşur

Sorgu planlayıcısı

  • İndeks sayısı arttıkça, planlayıcının değerlendirmesi gereken seçenekler çoğalır ve sorgu planı oluşturma süresi uzar

Bellek kullanımı

  • İndeks sayfaları shared buffer içine yüklenip önbelleğe alınır; indeks sayısı arttıkça bellek yükü de artar
  • btree düğüm boyutu sınırı nedeniyle sütun büyüdükçe ağacın derinliği artar
  • Sıralama, çok sütunlu tarama, vacuum, reindex gibi işlemlerde de ek work memory kullanılır

Başlıca indeks türleri

Btree

  • PostgreSQL'in varsayılan indeks yapısıdır ve çoğu DBMS'te kullanılan genel amaçlı indeks türüdür
    • O(log n) zaman karmaşıklığıyla hızlı arama sağlar
    • Tüm yaprak düğümlerin aynı derinlikte olduğu dengeli ağaç yapısına sahiptir
    • ORDER BY, JOIN işlemlerinde avantaj sağlar ve birincil anahtar / benzersiz anahtar kısıtları için kullanılır
  • İç düğümler alt düğüm işaretçilerini, yaprak düğümler ise anahtar ve heap işaretçilerini saklar
  • Sol ve sağ düğüm işaretçileri sayesinde çift yönlü gezinme mümkündür
Birden fazla indeks kullanımı
  • PostgreSQL, birden fazla indeksi bitmap AND/OR işlemleriyle birleştirerek bileşik koşulları işler
    • Örnek: age=30 AND login_count=100 koşulunda iki indeksin bitmap'i birleştirilir
Çok sütunlu indeksler
  • Birden fazla sütun tek bir indeks altında birleştirilerek alan tasarrufu ve hız artışı sağlanabilir
    • Ancak sütun sırası önemlidir; yalnızca soldan başlayan eşleşen koşullar indeksi kullanabilir
Kısmi indeksler
  • Koşul ifadesi kullanılarak yalnızca belirli satırlar indekslenir
    • İndeks boyutunu küçültür, RAM'e sığma olasılığını artırır ve sorgu hızını iyileştirir
    • Örnek: create index on rules(status) where status='enabled';
    • Değer dağılımı dengesiz olduğunda faydalıdır (status <> 'TODO' gibi)
Covering index
  • Sorgunun ihtiyaç duyduğu tüm sütunlar indeks içinde yer alıyorsa, heap erişimi olmadan sonuç döndürülebilir (index-only scan)
    • create index abc_cov_idx on bar(a, b) including c;
    • Çok sütunlu indekslere göre alan açısından daha verimlidir
İfade indeksleri
  • Sütun değerinin kendisi yerine fonksiyon veya ifade sonucu indekslenir
    • Örnek: CREATE INDEX idx_lower_name ON customers (lower(name));
    • LOWER(name) gibi dönüştürülmüş değerlerle arama yapılırken kullanışlıdır
    • Yalnızca immutable fonksiyonlar kullanılabilir

Hash

  • Hash map yapısı tabanlı bir indeks olup, uzun dizeler veya UUID gibi durumlarda alan açısından verimlidir
    • 32 bit hash kodu saklayarak boyutu azaltır
    • Yalnızca eşitlik karşılaştırması (=) destekler; sıralama veya çok sütunlu indeks mümkün değildir
    • Hash dağılımı dengeliyse Btree'den daha hızlı okuma performansı sağlayabilir
  • Resmî belgelere göre hash indeksleri, bucket sayfalarına doğrudan erişim sayesinde büyük tablolarda I/O'yu azaltır

BRIN (Block Range Index)

  • Her blok aralığı için yalnızca minimum ve maksimum değerleri saklayan bir indeks türüdür
    • Son derece sıkıştırılmış ve cache dostudur
    • Büyük ölçekli, append-only, zaman serisi verileri için uygundur
  • Satırlar sık güncelleniyorsa, MVCC kaynaklı yinelenen saklama nedeniyle verim düşebilir
  • pages_per_range ayarıyla doğruluk ve boyut arasındaki trade-off düzenlenebilir

GIN (Generalized Inverted Index)

  • Bileşik veri aramaları için uygun bir indeks türüdür
    • Metin, dizi, JSONB gibi yapılarda belirli öğelerin aranmasını destekler
    • Veri türüne özel strateji sınıfları (opclass) kullanır
    • JSON için JSONB sütunu, metin içinse tsvector veya pg_trgm eklentisi ile birlikte kullanılması önerilir

GiST & SP-GiST

  • Genelleştirilmiş arama ağacı (GiST) ve uzay bölmeli ağaç (SP-GiST), belirli veri türleri için indeks uygulama çerçeveleridir
    • GiST dengeli ağaç, SP-GiST ise dengesiz yapı desteği sunar
    • Coğrafi veri, inet, aralık, metin vektörü gibi alanlarda kullanılır
    • GIN daha hızlı sorgulama, GiST ise daha düşük kurulum ve bakım maliyeti sunar
    • Tam metin araması yapılırken ihtiyaçlara göre iki yaklaşımdan biri seçilebilir

Sonuç

  • İndeksler, PostgreSQL performans optimizasyonunun merkezindedir; okuma hızındaki artış ile yazma ve depolama maliyetleri arasında denge kurmak önemlidir
  • Veri özellikleri ve sorgu kalıplarına uygun indeks türü seçildiğinde hızlı ve verimli bir veritabanı işletimi mümkündür
  • Doğru indeks tasarımı, büyük ölçekli sistemlerde ölçeklenebilirlik ve kararlılığı sağlamak için vazgeçilmezdir

1 yorum

 
GN⁺ 2026-01-26
Hacker News yorumları
  • PostgreSQL resmi dokümantasyonu gerçekten çok iyi yazılmış ve okuması da keyifli, o yüzden paylaşıyorum
    PostgreSQL Indexes giriş dokümanı

  • Çok sütunlu indeks bölümü benim öğrendiğim yöntemle neredeyse aynı
    Ama bunun en güncel PostgreSQL sürümlerinde hâlâ böyle olup olmadığını merak etmiştim
    Eskiden üçüncü örneğe benzer bir sorguda bitmap index scan kullanıldığını görmüştüm; o zamandan beri mevcut "yerleşik doğruları" yeniden düşünmeye başladım
    Bu arada indeksler konusunda Use The Index, Luke sitesinin ve kitabının tüm ekibin okumasına değer birer klasik kaynak olduğunu düşünüyorum

    • PostgreSQL 18 ile index skip scan eklendi; artık çok sütunlu indekslerde yalnızca alt sütunlarla da verimli arama yapılabiliyor
      Önceki sürümlerde de bu mümkündü, ama tüm indeksi taramak gerektiği için verimsizdi
      İlgili video: YouTube bağlantısı
    • bitmap index scan, veri bulunma ihtimali olan sayfaları daraltır ama gerçek koşul doğrulamasını yine yapmak gerekir; bu yüzden normal indeks taramasından daha düşük performans verir
  • PostgreSQL'in incremental view maintenance için yerleşik destek sunması iyi olurdu diye düşünüyorum
    Bu, indeksler gibi temel veri değiştiğinde otomatik güncellenen, ancak belirli bir görünümle sınırlı olmayıp herhangi bir görünüme uygulanabilen bir kavram

    • Bu, transaction processing işin içine girdiği için oldukça zor bir problem
      Noria, Materialize, Apache Flink, GCP Continuous Queries, Spark Streaming Tables, Delta Tables, ClickHouse streaming tables, TimescaleDB, ksqlDB, StreamSQL gibi ilgili birçok proje var
      PostgreSQL tarafında yakın zamanda pg_ivm adlı bir eklenti bu problemi ele almaya başladı
    • Zaman serisi verisinde TimescaleDB'nin continuous aggregates özelliği zaten bu rolü görüyor
  • B-tree vs Hash indeksleri tartışması ilginç
    Birçok kişi ID sütunlarında hash'in daha iyi olduğunu düşünür, ama pratikte varsayılan B-tree daha verimlidir
    Özellikle neredeyse sıralı değer eklemelerinde ağaç yapısı daha avantajlıdır
    Ancak bu kez bahsedilen blog yazısında, kıyaslamalarda hash'in kazandığı söyleniyor

  • Bu yazının zamanlaması iyiydi
    Çok sütunlu indekslerdeki leading column kuralı hep kafa karıştırıcıydı, ama bitmap index scan sayesinde eskisi kadar kritik olmaktan çıktı
    PostgreSQL 18'in skip scan özelliği mevcut kabulleri ciddi biçimde değiştiriyor; bu yüzden eski sürümler üzerinden öğrenenlerin zihinsel modelini güncellemesi gerekiyor

  • PostgreSQL için gerçekten harika bir kaynak olduğunu düşünüyorum
    B-tree indeksleri konusunda da uzun zamandır Use The Index, Luke kaynağına sık sık başvuruyorum

  • Bence mutlaka okunmalı
    Sadece basit bir giriş yazısının ötesine geçiyor; derinlikli ama iç yapıları ele almadığı sürece yeterince kolay okunuyor

  • Bu basit ve mütevazı yazım tarzını seviyorum
    Bilgiyi doğrudan aktaran yaklaşım hoşuma gidiyor