
Büyük Veritabanlarında Doğru İndeksleme (Indexing) Yaklaşımları
Diyarbakır Yazılım
16.08.2026
#Yazılım#Teknoloji#Topluluk
Bir sorgunun 40 milisaniyede çalışmasıyla 14 saniyede tamamlanması arasındaki fark çoğu zaman daha güçlü bir sunucudan değil, doğru erişim yolundan gelir. On yılı aşkın veritabanı ve backend çalışmalarında gördüğüm en yaygın hata, indekslemeyi tabloya kolon eklemek kadar mekanik bir işlem sanmaktır. Büyük Veritabanlarında Doğru İndeksleme (Indexing) Yaklaşımları aslında gerçek sorgu yükünü, veri dağılımını, execution plan davranışını, disk erişimini ve yazma maliyetini birlikte değerlendirmeyi gerektirir. Bu rehberde büyük veritabanlarında doğru indeksleme nasıl yapılır sorusunu B-tree mantığından composite, covering, partial, BRIN, vector index, partitioning, bakım ve production rollout süreçlerine kadar ele alacağız. Amacımız yalnızca sorguları hızlandırmak değil, veri büyüdükçe de yönetilebilir kalan bir indeks portföyü oluşturmaktır.
Veritabanı İndeksi Nedir?
Veritabanı indeksi, tablodaki satırlara daha az veri okuyarak ulaşmayı sağlayan yardımcı veri yapısıdır. Kitabın tamamını baştan sona okumak yerine alfabetik dizinden doğru sayfayı bulmaya benzetilebilir. Ancak veritabanı indeksleri yalnızca adres listesi değildir, sıralama, range lookup ve bazı durumlarda sorgunun ihtiyaç duyduğu veriyi doğrudan taşıma gibi görevler de üstlenebilir. İndeks türüne ve veritabanı motoruna göre veri yapısı farklılaşır. Bu nedenle “bir index ekleyelim” yaklaşımından önce hangi sorgunun hangi erişim desenine ihtiyacı olduğunu anlamak gerekir.
Index Ne İşe Yarar?
Index, sorgu motorunun aradığı satırları tüm tabloyu okumadan bulmasına yardımcı olur. Özellikle yüksek selectivity taşıyan equality veya dar range sorgularında okunan page sayısını ciddi biçimde azaltabilir. İndeks aynı zamanda belirli bir sıralamayı hazır taşıdığı için bazı ORDER BY işlemlerinde ayrıca sort yapılmasını önleyebilir. Covering yapı kullanıldığında sorgu base table'a hiç gitmeden sonuç üretebilir. Buna karşılık index her yazma işleminde güncellenmesi gereken ek bir veri yapısı olduğu için yalnızca gerçek sorgu faydası olduğunda oluşturulmalıdır.
Full Table Scan Nedir?
Full table scan sorgunun ilgili tablo veya partition içindeki geniş bir veri bölümünü satır satır ya da page page incelemesidir. Büyük bir tabloda yalnızca birkaç kayıt aranıyorsa bu yaklaşım yüksek I/O maliyeti oluşturabilir. Fakat tablonun büyük kısmının zaten okunacağı analitik sorgularda full scan gayet doğru plan olabilir. Sequential I/O birçok küçük random lookup'tan daha verimli çalışabilir. Bu nedenle execution plan içinde table scan görmek otomatik olarak hata bulunduğu anlamına gelmez.
Index Lookup Nasıl Çalışır?
B-tree tabanlı bir lookup genellikle root seviyesinden başlar ve uygun child page'lere doğru ilerler. Aranan key leaf seviyesine ulaştığında satırın kendisi veya satıra götüren locator bulunur. Clustered storage kullanan motorlarda lookup doğrudan veri page'ine ulaşabilir. Secondary index yapılarında ikinci bir base-table veya clustered-index erişimi gerekebilir. Sorgu çok fazla satır döndürüyorsa bu tekrar eden lookup maliyeti full scan'den pahalı hale gelebilir.
Index Kullanmak Query Complexity'yi Nasıl Değiştirir?
Teorik açıdan dengeli ağaç yapısı arama alanını her adımda küçülterek lineer taramaya göre daha avantajlı erişim sağlar. Ancak gerçek veritabanı performansı yalnızca Big O ifadesiyle açıklanamaz. Page cache, tree depth, row width, clustering ve kaç satır döndürüldüğü sonucu ciddi biçimde değiştirir. Bir index lookup az sayıda page okuyorsa çok hızlı olabilir, fakat milyonlarca random heap lookup gerçekleştiriyorsa aynı avantaj kaybolur. Bu nedenle complexity teorisini execution plan ve gerçek I/O ölçümleriyle birlikte yorumlamak gerekir.
İndeksler Neden Ücretsiz Değildir?
Her yeni indeks disk alanı tüketir ve buffer cache içinde yer ister. INSERT sırasında yeni key ilgili index page'e yazılır. UPDATE indekslenen bir değeri değiştiriyorsa eski entry kaldırılıp yenisi oluşturulabilir. DELETE işlemi de index yapısında bakım gerektirir ve kullanılan motora göre log üretimini artırır. Bu nedenle on tane sorguyu biraz hızlandıran ama bütün yazma trafiğini sürekli yavaşlatan bir index iyi yatırım olmayabilir.
Büyük Veritabanlarında İndeksleme Neden Daha Kritik Hale Gelir?
Küçük tabloda yanlış indeks stratejisi çoğu zaman güçlü donanım veya cache tarafından gizlenebilir. Veri milyonlarca ve ardından milyarlarca satıra çıktığında aynı hata disk erişimi ve memory pressure olarak görünür hale gelir. Working set RAM'e sığmadığında her gereksiz page okumasının maliyeti artar. Yüksek concurrency aynı veritabanı kaynaklarına daha fazla sorgunun aynı anda ihtiyaç duymasına neden olur. Bu ölçekte indeks tasarımı tek bir sorgunun hızından çok sistemin toplam I/O, CPU ve write throughput dengesini belirler.
Milyonlarca ve Milyarlarca Satır
Satır sayısı arttıkça full scan sırasında okunması gereken page miktarı büyür. İyi bir index aranan birkaç kaydı küçük bir erişim alanına indirir. Ancak index kendi boyutu da veriyle büyüdüğü için key width önemli hale gelir. Çok geniş composite index milyarlarca satırda yüzlerce gigabayt ek storage yaratabilir. Büyük tabloda bu nedenle her kolonun index içindeki byte maliyetini de düşünmek gerekir.
Disk I/O
Veritabanlarında sorgu süresinin önemli bölümü storage page'lerinin okunması veya yazılmasıyla ilişkili olabilir. İndeks daha az page okuyarak I/O ihtiyacını düşürür. Fakat indeksin kendisi büyükse onun page'leri de diskten getirilmek zorunda kalabilir. NVMe storage gecikmeyi azaltır ama kötü erişim desenini ortadan kaldırmaz. En iyi index tasarımı gereksiz veri okumayı donanımdan bağımsız biçimde azaltmaya çalışır.
Random I/O
Random I/O birbirinden uzak page'lere çok sayıda bağımsız erişim yapılmasıdır. Secondary index üzerinden binlerce row lookup bu davranışı oluşturabilir. SSD sistemlerde random erişim mekanik diske göre çok daha hızlıdır fakat yine de memory hit kadar ucuz değildir. Bir sorgu tablonun büyük kısmını döndürecekse sequential scan bazen daha verimlidir. Optimizer cost modeli bu nedenle yalnızca “index var mı?” sorusuna bakmaz.
Memory ve Buffer Cache
Database engine sık kullanılan data ve index page'lerini memory içinde tutmaya çalışır. İndeks portföyü gereğinden fazla büyürse cache içinde yararlı page'ler için daha az alan kalır. Hot index root ve upper-level page'leri genellikle sürekli cache'te bulunabilir. Leaf working set RAM'i aştığında cache miss oranı yükselir. Bu nedenle index size ile buffer pool kapasitesini birlikte takip etmek gerekir.
Yüksek Concurrency
Tek sorguda kabul edilebilir görünen maliyet yüzlerce concurrent request altında problem yaratabilir. Her request fazla logical read yapıyorsa CPU ve memory bandwidth ortak kaynaklarda baskı oluşturur. Yazma yoğun sistemde aynı hot index page'i üzerinde contention oluşabilir. Locking ve latch behavior motorlara göre farklılaşır. Production benchmark bu nedenle yalnızca tek bağlantıyla değil gerçek concurrency seviyelerine yakın koşullarda yapılmalıdır.
Read/Write Trade-Off
İndekslerin temel dengesi okuma kazancı ile yazma maliyetidir. Daha fazla index SELECT sorgularını hızlandırabilir fakat INSERT, UPDATE ve DELETE sırasında daha çok bakım gerektirir. Read-heavy raporlama sistemi ile write-heavy event ingestion sistemi aynı index sayısını taşımamalıdır. Workload yüzdesi zaman içinde değişebilir. Bu nedenle indeksler statik schema parçaları değil periyodik olarak yeniden değerlendirilmesi gereken performans varlıklarıdır.
İndeksleme Stratejisine Tablodan mı Sorgudan mı Başlanmalı?
İyi indeks tasarımına tablodaki kolon listesinden değil, production sorgularından başlamak daha güvenilir sonuç verir. “Bu kolon önemli, index ekleyelim” düşüncesi hangi predicate, sort ve join deseninin gerçekten kullanıldığını görmez. Query-driven tasarım yüksek toplam maliyet oluşturan workload'u önceliklendirir. Aynı tablo için birbirine benzeyen onlarca index yerine birkaç sorgu ailesini destekleyen daha anlamlı composite yapılar kurulabilir. SQL query execution plan ile eksik ve gereksiz indeksler nasıl tespit edilir sorusunun cevabı da önce gerçek workload'u görünür hale getirmektir.
Query-Driven Index Design
Query-driven tasarım index kolonlarını gerçek WHERE, JOIN, ORDER BY ve projection desenlerine göre belirler. Önce sorgunun ne kadar sık çalıştığı ve ne kadar kaynak tükettiği ölçülür. Sonra mevcut execution plan incelenir. Aday index staging veya representative data üzerinde test edilir. Kazanç doğrulandıktan sonra production rollout planlanır.
En Sık Çalışan Sorgular
Bir sorgu yalnızca 3 milisaniye sürse bile saniyede binlerce kez çalışıyorsa toplam sistem maliyeti yüksek olabilir. Bu nedenle tuning listesi yalnızca en yavaş sorgulardan oluşmamalıdır. Execution count ile average cost birlikte değerlendirilmelidir. Küçük bir logical-read azalması yüksek frekansta büyük CPU tasarrufu sağlayabilir. Query Store veya statement statistics araçları bu sorguları bulmak için kullanılabilir.
En Yavaş Sorgular
En yavaş sorgular kullanıcı experience'ında doğrudan gecikme yaratabilir. Ancak bir gece raporunun 20 saniye sürmesi, checkout sorgusunun 400 milisaniye sürmesinden daha düşük business priority taşıyabilir. Sorgu süresi p95 ve p99 üzerinden de incelenmelidir. Aynı SQL farklı parametrelerde farklı davranabilir. Bu nedenle yalnızca average latency üzerinden index kararı verilmemelidir.
Business-Critical Sorgular
Checkout, authentication veya sipariş oluşturma gibi sorgular düşük hacimli olsa bile iş açısından kritiktir. Bu query'ler için predictable latency bazen maksimum throughput'tan daha önemlidir. İndeks tasarımı failover ve cache-cold durumunda da test edilebilir. Bir rapor query'siyle aynı index portföyünü paylaşırken cache displacement etkisi değerlendirilmelidir. Business priority tuning sırasının teknik maliyet kadar önemli girdisidir.
Scanned Rows / Returned Rows Oranı
Sorgu 10 satır döndürmek için 5 milyon satır inceliyorsa güçlü bir optimizasyon sinyali vardır. Bu oran predicate'in mevcut access path tarafından iyi desteklenmediğini gösterebilir. Ancak filtre sonucu gerçekten milyonlarca satırsa yüksek scan doğal olabilir. Execution plan estimated ve actual row sayılarını birlikte göstermelidir. Yüksek scanned-to-returned oranı özellikle sık çalışan OLTP sorgularında dikkat çekicidir.
Production Workload'u Temel Almak
Development veritabanında birkaç bin satırla seçilen plan production'da yüz milyon satırda farklı olabilir. Data distribution ve cache behavior gerçek sistemde değişir. Sanitized production snapshot veya representative generator daha gerçekçi benchmark sağlar. Query telemetry uzun dönem kullanımı göstermelidir. Özellikle aylık rapor gibi seyrek sorgular yalnızca kısa monitoring window nedeniyle unutulmamalıdır.
İndeks Adayı Sorgular Nasıl Bulunur?
İndeks adaylarını bulmak için önce pahalı sorguları sistematik biçimde toplamak gerekir. Slow query log, statement statistics ve APM trace'leri farklı açılardan yardımcı olur. Top SQL listesi total execution time, CPU veya I/O bazında sıralanabilir. Sadece tek bir spike yerine uzun dönem workload trend'i önemlidir. İyi tuning süreci “hangi kolon indekslenmeli?” sorusundan önce “hangi sorgu sisteme en fazla maliyeti getiriyor?” sorusunu cevaplar.
Slow Query Log
Slow query log belirli latency eşiğini aşan sorguları kaydetmeye yardımcı olur. MySQL gibi sistemlerde threshold ayarlanarak yüksek gecikmeli sorgular bulunabilir. Eşik çok düşük olursa log hacmi gereksiz büyür. Çok yüksek olursa sık çalışan orta maliyetli sorgular kaçabilir. Log verisi execution count ve application context ile zenginleştirildiğinde daha değerli hale gelir.
PostgreSQL pg_stat_statements
pg_stat_statements normalize edilmiş SQL ifadeleri için çağrı sayısı ve execution time gibi toplu istatistikler sağlar. Toplam execution time üzerinden sıralama, sık çalışan ama tek başına çok yavaş görünmeyen sorguları ortaya çıkarabilir. Shared block hit ve read değerleri I/O davranışı hakkında fikir verir. Extension verisi belirli monitoring window için yorumlanmalıdır. Reset veya database restart history etkilerini operasyon ekibi bilmelidir.
SQL Server Query Store
Query Store sorgu text'leri, plan history ve runtime statistics bilgilerini kalıcı biçimde toplar. Plan regression araştırmak için özellikle kullanışlıdır. Aynı sorgunun yeni planla neden yavaşladığı geçmiş planlarla karşılaştırılabilir. Top CPU, duration veya reads gibi kriterlerle workload incelenebilir. Index değişikliğinden sonra plan history üzerinden gerçek etkinin devam edip etmediği izlenebilir.
MySQL Performance Schema
MySQL Performance Schema statement execution ve wait davranışları hakkında ölçüm sağlar. Digest bazlı tablolar benzer SQL ifadelerini gruplandırarak yüksek toplam maliyetli sorguları bulmaya yardımcı olabilir. Event instrumentation ihtiyaca göre ayarlanmalıdır. Fazla telemetry'nin kendi operasyon maliyeti de izlenmelidir. Slow log ile birlikte kullanıldığında hem latency hem workload frekansı daha iyi anlaşılır.
APM Database Traces
APM trace database query'yi web request veya business transaction ile ilişkilendirir. Böylece yavaş SQL'in kullanıcı tarafındaki gerçek etkisi görülebilir. Aynı sorgunun hangi endpoint veya background job tarafından üretildiği anlaşılır. N+1 gibi application-level problem yalnızca database log'undan daha net fark edilir. İndeks eklemekten önce sorgu sayısını azaltmanın daha büyük kazanç sağlayıp sağlamadığı bu bağlamla değerlendirilir.
Top SQL by Total Time
Total time execution count ile tek sorgu maliyetini birlikte yansıtır. Saniyede yüzlerce kez çalışan orta hızlı sorgu bu listede üst sıralara çıkabilir. Bu sorguda yüzde 20 iyileştirme sistem genelinde ciddi CPU tasarrufu sağlayabilir. Ortalama süreye tek başına bakmak bu fırsatı kaçırır. Tuning backlog'u total resource contribution üzerinden önceliklendirilebilir.
Top SQL by I/O
Logical ve physical read sayısı database workload'unun storage ve buffer cache üzerindeki baskısını gösterir. Çok page okuyan sorgu latency düşük olsa bile diğer sorguların cache'ini dışarı itebilir. İndeks veya query rewrite okunan page sayısını azaltabilir. Physical read storage dependency'sini, logical read ise database engine içindeki data access hacmini gösterir. İkisini ayrı izlemek daha doğru performans resmi verir.
B-Tree ve B+ Tree İndeksleri Nasıl Çalışır?
B-tree ailesi ilişkisel veritabanlarında en yaygın index yapılarından biridir. Veriler sıralı key alanında dengeli bir ağaç üzerinden erişilebilir hale gelir. Pek çok storage engine leaf seviyesinde key'leri ve satır locator'larını tutan B+ tree benzeri tasarımlar kullanır. Tree yüksekliği genellikle küçük kaldığı için milyonlarca kayıt arasında az sayıda page geçişiyle arama yapılabilir. Equality, range ve ordered scan davranışlarının güçlü olmasının nedeni bu sıralı ağaç yapısıdır.
Root Node
Root node index traversal'ın başlangıç noktasıdır. İçinde bütün satırlar değil child page aralıklarını yönlendiren key bilgileri bulunur. Çok sık erişildiği için büyük sistemlerde genellikle buffer cache içinde sıcak kalır. Index büyüdükçe root'tan leaf'e inmek birkaç level gerektirebilir. Key genişliği page başına düşen entry sayısını azalttığı için tree depth üzerinde dolaylı etki yaratabilir.
Internal Nodes
Internal node'lar arama key'ini doğru alt dal veya page'e yönlendirir. Her level arama alanını daha küçük bölümlere ayırır. Düşük fan-out daha fazla tree level gerektirebilir. Çok geniş index key internal page kapasitesini etkileyebilir. Bu nedenle composite index'e gereksiz büyük kolon eklemek yalnızca leaf storage maliyeti değildir.
Leaf Pages
Leaf pages index'in sıralı key entry'lerini taşır. Motorun storage modeline göre row locator, primary key veya included data burada bulunabilir. Range scan leaf page'ler boyunca ardışık ilerleyebilir. Page doluluk oranı ve split davranışı write-heavy workload'u etkiler. Covering index tasarımında ekstra payload genellikle leaf seviyesinde tutulmaya çalışılır.
Tree Depth
Tree depth root ile leaf arasında kaç seviye bulunduğunu ifade eder. Fan-out yüksek olduğunda milyarlarca entry bile şaşırtıcı derecede az level ile adreslenebilir. Ancak her level page erişimi ve CPU comparison maliyeti getirir. Cache'te bulunan upper-level page'ler disk I/O gerektirmeyebilir. Index width ve page utilization tree depth'i zaman içinde etkileyebilir.
Equality Search
WHERE id = ? gibi equality sorgusu B-tree için doğal kullanım alanıdır. Engine root'tan uygun key aralığına yönelir ve leaf seviyesinde matching entry'yi bulur. Unique index varsa sonuç sayısı hakkında optimizer daha güçlü bilgiye sahiptir. Nonunique key birden fazla leaf entry döndürebilir. Selectivity yüksekse equality lookup genellikle çok düşük page maliyetiyle tamamlanır.
Range Scan
created_at BETWEEN ... gibi sorgularda tree başlangıç sınırını hızlıca bulabilir. Sonra leaf page'ler range sonuna kadar sıralı biçimde okunur. Bu davranış time-based query'lerde oldukça etkilidir. Range çok genişse optimizer full veya sequential scan'i tercih edebilir. Composite index'te range predicate sonrasındaki kolonların scan sınırını ne kadar daraltabildiği engine'e göre değişir.
ORDER BY
Index key order sorgunun istediği sıralamayla uyumluysa ayrıca sort işlemi gerekmeyebilir. Özellikle ORDER BY created_at DESC LIMIT 50 gibi Top-N sorgularında büyük avantaj sağlar. Filter ve order aynı composite index içinde birlikte desteklenebilir. Mixed ASC ve DESC yönleri motor özelliklerine göre tasarlanmalıdır. Execution plan'da sort operator'ının ortadan kalkması gerçek kazancı doğrulayan işaretlerden biridir.
Temel İndeks Türleri
Her sorgu problemi B-tree ile çözülmez. Equality, full-text, spatial, JSON, time-series ve vector similarity farklı veri yapılarına ihtiyaç duyabilir. Veritabanı motorlarının desteklediği index türleri de birbirinden farklıdır. PostgreSQL GIN, GiST, SP-GiST ve BRIN gibi geniş access method seçeneklerine sahipken SQL Server columnstore tarafında güçlü seçenekler sunar. Bu nedenle index türünü ürün adına değil operator ve workload tipine göre seçmek gerekir.
B-Tree / B+ Tree
B-tree ailesi equality, range ve sıralı erişim için genel amaçlı seçimdir. Primary ve secondary relational index'lerin büyük bölümü bu yapıya dayanır. Key order composite query davranışını doğrudan etkiler. Düşük selectivity sorgularda her zaman avantaj sağlamaz. OLTP sistemlerinde temel index portföyünün çoğu genellikle bu yapıdadır.
Hash Index
Hash index equality lookup için tasarlanmıştır ve doğal sıralama taşımaz. Range veya ORDER BY ihtiyacında B-tree kadar uygun değildir. Destek ve durability davranışı database engine'e göre ciddi biçimde değişebilir. PostgreSQL kullanıcı tarafından oluşturulabilen hash index sunarken MySQL'de hash behavior storage engine'e bağlıdır. Sadece equality kullanılıyor diye otomatik hash seçmek yerine engine dokümantasyonu ve benchmark incelenmelidir.
Bitmap Index
Bitmap index düşük cardinality kolonlarda özellikle analitik workload'larda faydalı olabilen bir yapıdır. Birçok satır için bit map üzerinden koşulların AND veya OR kombinasyonu hızlı değerlendirilebilir. Bazı database ürünleri kalıcı bitmap index sunarken PostgreSQL farklı B-tree index sonuçlarını runtime bitmap scan içinde birleştirebilir. Yüksek write oranı olan OLTP sistemlerinde klasik bitmap index yapıları pahalı olabilir. Teknoloji seçimi ürünün gerçek bitmap desteğine göre yapılmalıdır.
Full-Text Index
Full-text index kelime, token ve linguistic search ihtiyaçları için tasarlanır. Normal B-tree %kelime% aramasını verimli biçimde çözemez. Full-text yapı stemming, tokenization ve ranking gibi özellikler sunabilir. PostgreSQL text search GIN veya GiST ile desteklenebilir. Daha gelişmiş distributed search gereksiniminde ayrı arama altyapısı değerlendirilir.
Spatial Index
Spatial index nokta, alan ve geometri sorgularında kullanılır. “Bu koordinata en yakın kayıtlar” veya “bu polygon içinde kalan nesneler” gibi sorgular normal scalar ordering'den farklıdır. GiST veya database-specific spatial yapı kullanılabilir. Coordinate reference system ve operator seçimi index usability'yi etkiler. Geospatial sorgular gerçek execution plan ile test edilmelidir.
BRIN
BRIN, PostgreSQL'de block range özetleri tutarak çok büyük ve fiziksel sıralamayla korelasyonlu tablolar için küçük index oluşturabilir. Timestamp ile append edilen event tablosu iyi adaydır. B-tree kadar kesin row lookup yapmaz. Uygun block range'leri bulup false positive page'leri yeniden kontrol eder. Buna karşılık index boyutu çok daha küçük olabilir.
GIN
GIN bir satır içindeki birden fazla anahtarın aranması gereken veri tipleri için güçlüdür. PostgreSQL array, JSONB ve full-text kullanımında sık görülür. Bir document içindeki token veya JSON key/value öğeleri ayrı index entry mantığıyla aranabilir. Write maliyeti B-tree'den daha yüksek olabilir. Pending list ve maintenance behavior yoğun write workload'unda izlenmelidir.
GiST
GiST farklı search tree stratejilerinin uygulanabildiği extensible bir index framework'üdür. Geometry, range ve benzeri özel operator class'ları destekleyebilir. Bazı GiST operator'ları lossy olabilir ve candidate row'ların recheck edilmesini gerektirir. B-tree ile aynı davranışı beklemek doğru değildir. Kullanılacak operator class sorgunun gerçek semantiğine uygun seçilmelidir.
SP-GiST
SP-GiST partitioned search tree ailesi için PostgreSQL access method'udur. Quad-tree veya trie benzeri partitioning yaklaşımlarına uygun veri dağılımlarında kullanılabilir. Veri uzayını non-balanced partition mantığıyla bölebilir. Her veri tipi için uygun değildir. Operator class ve query pattern desteği kontrol edilmeden tercih edilmemelidir.
Columnstore Index
Columnstore satır bazlı değil kolon bazlı depolama ve sıkıştırma yaklaşımıyla analitik taramalarda avantaj sağlar. Büyük aggregation sorguları yalnızca gerekli kolonları okuyabilir. SQL Server bu alanda güçlü clustered ve nonclustered columnstore seçenekleri sunar. Yüksek point-lookup OLTP sorguları için rowstore B-tree çoğu zaman daha uygundur. Hybrid sistemler sıcak OLTP verisini rowstore, analitik bölümü columnstore ile destekleyebilir.
Vector Index
Vector index embedding'ler arasında similarity search yapmak için kullanılır. Klasik scalar B-tree yüksek boyutlu nearest-neighbor problemini verimli çözmez. HNSW ve IVFFlat gibi ANN yapıları latency ile recall arasında farklı dengeler sunar. Index build süresi ve memory tüketimi önemli hale gelir. Metadata filter ile vector search birlikte kullanılacaksa relational ve vector index stratejileri beraber tasarlanmalıdır.
Doğru İndeks Türü Nasıl Seçilir?
Doğru index türü sorgunun kullandığı operator ve erişim deseninden çıkar. Equality query ile full-text search aynı veri yapısını istemez. Time-series workload fiziksel zaman korelasyonundan yararlanabilirken analytics columnstore tercih edebilir. JSON veya array aramasında GIN türleri öne çıkabilir. “En hızlı index hangisi?” yerine “bu sorgu hangi işi yapıyor?” sorusu daha doğru başlangıçtır.
Equality Query
Equality lookup için B-tree çoğu relational workload'da yeterli ve güvenilir seçimdir. Unique veya yüksek cardinality key üzerinde çok etkili olabilir. Bazı engine'lerde hash index de değerlendirilebilir. Fakat equality sorgusu aynı zamanda ordering veya range ihtiyacı taşıyorsa B-tree daha çok sorguyu destekler. Benchmark engine-specific davranışı doğrulamalıdır.
Range Query
Range query sıralı key space gerektirdiği için B-tree doğal seçimdir. Timestamp, amount veya sequence değerlerinde sık kullanılır. Index range'in başlangıcına hızlı ulaşır ve leaf boyunca ilerler. Range çok geniş olduğunda scan maliyeti yine yüksek olabilir. Time-series append-only dev tabloda BRIN alternatifi ayrıca değerlendirilmelidir.
Sorting
Sort performansı için index order sorgudaki filter ve ORDER BY ile uyumlu olmalıdır. Equality prefix ardından sort kolonları yaygın pattern'dir. Index direction bazı motorlarda backward scan veya explicit descending key ile karşılanabilir. Mixed direction senaryosu özel dikkat ister. Execution plan'da büyük sort veya temp spill ortadan kalkıyorsa index faydası somutlaşır.
Full-Text Search
Kelime bazlı search için full-text index gerekir. Leading wildcard B-tree'nin ordered prefix avantajını kullanamaz. Database-native full-text küçük ve orta ölçek ihtiyaçları karşılayabilir. Dil analizi ve ranking gereksinimleri engine özelliklerine göre değişir. Distributed search, typo tolerance veya complex relevance gerekiyorsa ayrı search engine değerlendirilebilir.
JSON / Array Search
JSON veya array içindeki öğeler aranıyorsa B-tree yalnızca belirli extracted scalar alanlarda kullanışlıdır. PostgreSQL JSONB için GIN sık kullanılan çözümdür. Çok sık sorgulanan tek property generated veya expression column üzerinden B-tree ile daha dar biçimde indekslenebilir. Tüm document'i indiscriminately indexlemek storage ve write maliyetini büyütebilir. Query pattern hangi alanların gerçekten indexlenmesi gerektiğini belirlemelidir.
Geospatial Query
Geospatial sorgular iki boyutlu veya daha yüksek uzamsal ilişkileri değerlendirir. B-tree tek scalar order üzerinden bunu yeterli biçimde temsil etmez. Spatial index veya GiST tabanlı operator class kullanılabilir. Bounding box candidate bulma sonrası exact geometry recheck gerekebilir. Coordinate system ve function kullanımının indexable operator ile uyumlu olması gerekir.
Time-Series
Time-series veride timestamp hemen her sorgunun önemli parçasıdır. Device veya tenant prefix ile timestamp composite index yaygın çözüm olabilir. Büyük append-only tabloda fiziksel sıra zamanla yüksek korelasyon gösteriyorsa BRIN çok küçük index sunabilir. Retention partitioning ile birlikte düşünülmelidir. Latest-N sorgular için descending veya backward index scan behavior test edilmelidir.
Analytics
Analytics sorguları geniş satır setlerini okuyup aggregation yapar. Binlerce random index lookup yerine column-oriented scan daha verimli olabilir. Columnstore veya bitmap benzeri yaklaşımlar düşük cardinality filtering için avantaj sağlayabilir. B-tree yine selective dimension lookup veya join için yardımcıdır. OLTP index kurallarını doğrudan OLAP warehouse'a taşımamak gerekir.
Vector Similarity Search
Embedding search exact scalar equality değildir. ANN index yakın komşuları yaklaşık biçimde bulup latency'yi düşürür. HNSW genellikle iyi recall ve hızlı query sağlayabilir fakat memory ve build maliyeti yüksektir. IVFFlat tuning cluster/list ve probe parametrelerine daha fazla bağlı olabilir. Exact search baseline'ı olmadan ANN kalite kaybını ölçmek mümkün değildir.
Selectivity Nedir?
Selectivity bir predicate veya index key'in toplam satırların ne kadar küçük bir bölümünü ayırabildiğini anlatan performans kavramıdır. Bir sorgu yüz milyon satırdan yalnızca on satır seçiyorsa erişim yolu için güçlü fırsat vardır. Buna karşılık boolean alan toplam tablonun yarısını döndürüyorsa standalone B-tree index zayıf kalabilir. Selectivity kolonun sabit özelliği değil query predicate ile ilişkili bir ölçüdür. Data distribution değiştikçe aynı kolon farklı koşullarda farklı selectivity gösterebilir.
Yüksek Selectivity
Yüksek selectivity az sayıda matching row anlamında pratikte güçlü eleme gücü sağlar. Unique e-mail veya order ID buna örnektir. Index lookup birkaç leaf entry ve row erişimiyle tamamlanabilir. Optimizer index kullanımını daha kolay tercih eder. Ancak term kullanımında bazı kaynakların selectivity oranını ters biçimde tanımlayabildiği unutulmamalı, ekip kendi metriğini açık biçimde tanımlamalıdır.
Düşük Selectivity
Düşük selectivity predicate'in çok sayıda satırı eşleştirmesi anlamına gelir. Boolean is_active alanı tablonun yüzde 90'ında true ise index az veri eler. Çok fazla matching row için random lookup full scan'den pahalı olabilir. Partial index yalnızca nadir değer tarafını tutarak daha iyi çözüm sunabilir. Composite index içinde başka selective kolonlarla birlikte düşük-cardinality alan yine değerli olabilir.
Bir İndeksin Kaç Satırı Elemesi Gerektiği
İndeksin faydası sabit bir yüzde eşiğiyle belirlenemez. Row width, storage speed, clustering ve covering durumu sonucu değiştirir. Bir query yüzde 5 satır döndürürken index iyi olabilir, başka tabloda yüzde 1 bile pahalı olabilir. Cost-based optimizer bu değişkenleri modellemeye çalışır. Gerçek EXPLAIN ANALYZE veya execution statistics daha güvenilir doğrulama sağlar.
Selectivity Nasıl Hesaplanır?
Basit yaklaşım matching rows ile total rows oranını incelemektir. Daha küçük matching oranı daha güçlü eleme anlamına gelir. Distinct value sayısını total rows'a bölmek kolon cardinality'sine dayalı yaklaşık selectivity göstergesi sağlayabilir. Ancak skew varsa bu ortalama yanıltıcıdır. Histogram ve most-common-value statistics belirli predicate için daha doğru tahmin verir.
Query Bazlı Selectivity
status='FAILED' toplam satırların yüzde 0,1'ini döndürebilirken status='SUCCESS' yüzde 95'ini döndürebilir. İki query aynı kolonu kullanmasına rağmen aynı selectivity'ye sahip değildir. Parameter-sensitive plan problemleri buradan doğar. Histogram optimizer'ın value distribution'ı görmesine yardım eder. Index kararları kolon adı üzerinden değil gerçek predicate value dağılımıyla verilmelidir.
Cardinality Nedir?
Cardinality genellikle bir kolon veya kolon kombinasyonundaki distinct value sayısını ifade eder. Unique ID yüksek cardinality taşırken boolean alan en fazla birkaç distinct değere sahiptir. Cardinality optimizer'ın kaç satır eşleşeceğini tahmin etmesinde önemli girdidir. Ancak aynı distinct sayısı farklı frequency distribution'larında farklı query davranışı yaratabilir. Bu nedenle cardinality ile histogram ve data skew birlikte değerlendirilmelidir.
Distinct Value Sayısı
Bir kolonda kaç farklı değer bulunduğu temel cardinality bilgisidir. On milyon satırda on milyon distinct ID çok yüksek cardinality gösterir. Aynı tabloda üç farklı status değeri düşük cardinality'dir. Composite statistics kolon kombinasyonlarının distinct sayısını ayrıca ölçebilir. Distinct count tek başına value frequency bilgisini göstermez.
Cardinality ile Selectivity Arasındaki Fark
Cardinality veri setinin distinct yapısını anlatır. Selectivity belirli predicate'in satırları ne kadar daralttığıyla ilgilidir. Yüksek cardinality kolon genellikle selective equality query üretir fakat bu mutlak kural değildir. Skewed data belirli popüler value için milyonlarca satır döndürebilir. Optimizer iki kavramı statistics üzerinden birlikte yorumlar.
Yüksek Cardinality
Order ID veya email gibi alanlar yüksek cardinality taşıyabilir. Equality lookup için ideal index adayları olabilir. Join key'leri de yüksek cardinality'den fayda görebilir. Bununla birlikte büyük text key index width'i artırabilir. Cardinality yüksek diye her kolon otomatik indexlenmemelidir.
Düşük Cardinality
Status veya boolean kolon az sayıda distinct value taşır. Standalone B-tree index çoğu değer için table scan'den daha iyi olmayabilir. Nadir value tarafı partial index ile güçlü aday olabilir. Analytics database bitmap yapıdan faydalanabilir. Composite index'te tenant gibi başka key ile birleşmesi selectivity'yi yükseltebilir.
Data Distribution Neden Cardinality Kadar Önemlidir?
Bir milyon distinct değerin biri satırların yarısında bulunuyorsa distribution çok skewed'dır. Average cardinality estimate popüler value için yanlış plan üretebilir. Histogram veya MCV statistics bu farkı modele ekler. Parameter sensitivity özellikle böyle data setlerinde görülür. Production data distribution index benchmark'ının temel parçası olmalıdır.
Düşük Cardinality Kolonlar İndekslenmeli mi?
Düşük cardinality kolonların indekslenmemesi gerektiğini söyleyen mutlak bir kural yoktur. Önemli olan query'nin hangi value'yu ne sıklıkla aradığı ve o değerin tablodaki oranıdır. status='pending' yalnızca yüzde 0,2 satırı temsil ediyorsa çok değerli bir index fırsatı doğabilir. Standalone full index yerine partial veya composite seçenek daha ekonomik olabilir. Karar execution plan ve write maliyetiyle doğrulanmalıdır.
Boolean Alanlar
Boolean alan yalnızca iki temel değer taşır ve cardinality düşüktür. Satırların yarısı true ise standalone index çoğu workload'da iyi eleme yapmaz. Ancak true kayıtlar yüzde 0,01 ise bu küçük subset sık aranıyorsa partial index etkili olabilir. Soft delete veya processing queue buna örnektir. Index predicate business state değişim hızını da dikkate almalıdır.
Status Kolonu
Status alanı genellikle birkaç değer içerir. Pending, failed veya active gibi belirli durumlar operational query'lerde çok sık aranabilir. Completed kayıtlar tarihle birlikte büyüyerek tablonun çoğunu oluşturuyorsa yalnızca active subset'i indexlemek anlamlıdır. Composite (status, created_at) queue query'lerini destekleyebilir. Status transition yoğunluğu write maintenance maliyetini artırabilir.
Gender / Category Gibi Alanlar
Az sayıda category değerinde standalone B-tree büyük satır grupları döndürebilir. Reporting workload bitmap veya columnstore yapısından daha fazla fayda görebilir. OLTP query category yanında tenant ve created_at filtreliyorsa composite index daha anlamlıdır. Demografik alanlar ayrıca privacy ve domain gereksinimleri açısından dikkatli kullanılmalıdır. Performance gerekçesi veri toplamayı haklı çıkaran tek sebep değildir.
Standalone Index'in Sınırlamaları
Düşük cardinality standalone index çok sayıda row locator döndürür. Base table lookup maliyeti hızla yükselir. Optimizer bu nedenle index'i tamamen görmezden gelebilir. Index yine yazma ve storage maliyeti taşımaya devam eder. Usage statistics uzun süre sıfırsa kaldırma adayı olabilir.
Composite Index ile Kullanım
Düşük-cardinality kolon tenant veya time key ile birleştiğinde daha selective access path oluşturabilir. Örneğin (tenant_id, status, created_at) belirli tenant'ın pending kayıtlarını hızlı bulabilir. Column order query predicate ve sort ihtiyacına göre seçilir. Standalone status index artık redundant hale gelebilir. Composite yapı gerçek query family üzerinden test edilmelidir.
Partial / Filtered Index Alternatifi
Yalnızca nadir veya sıcak subset'i indekslemek full düşük-cardinality index'ten çok daha küçük olabilir. PostgreSQL partial index ve SQL Server filtered index bu modeli doğrudan destekler. Predicate query koşuluyla uyumlu olmalıdır. Index küçüldükçe cache efficiency ve write cost avantajı oluşur. Database motorunun filtered/partial syntax ve optimizer kuralları ayrıca kontrol edilmelidir.
Composite Index Nedir?
Composite index birden fazla kolonu tek sıralı index key içinde tutar. Kolon sırası sorgunun index'i nasıl kullanacağını belirleyen temel karardır. Ayrı single-column index'lerden farklı olarak bir access path içinde filter ve sort birlikte desteklenebilir. Ancak her yeni key kolonu index width'i ve write maliyetini artırır. Composite index covering index ile aynı kavram değildir, çünkü covering olmak sorgunun ihtiyaç duyduğu tüm veriyi taşımasıyla ilgilidir.
Birden Fazla Kolonu Aynı İndekste Tutmak
(tenant_id, status, created_at) tek index içinde üç key'i lexicographic sırada tutabilir. Önce tenant, aynı tenant içinde status, sonra timestamp sıralaması oluşur. Bu yapı belirli tenant ve status altındaki son kayıtları hızlı bulabilir. Sadece created_at filtresi için aynı index her motorda verimli olmayabilir. Key order bütün desteklenen query'lerin ortak deseni üzerinden tasarlanmalıdır.
Composite Index ile Ayrı İndeksler Arasındaki Fark
Ayrı tenant_id ve status index'leri optimizer tarafından bazı motorlarda bitmap veya index merge ile birleştirilebilir. Composite index ise iki koşulu tek ordered traversal içinde çözebilir. Sort order korunması composite yapıda ek avantaj sağlayabilir. Ayrı index'ler farklı query'lere daha esnek hizmet edebilir. Storage ve write maliyeti gerçek workload üzerinde kıyaslanmalıdır.
Composite Index Hangi Sorgularda Avantajlıdır?
Birden fazla predicate'in sürekli birlikte kullanıldığı sorgular composite index için güçlü adaydır. Equality prefix ardından range veya sorting column yaygın pattern'dir. Multi-tenant list ekranları buna iyi örnektir. Tek bir index birden fazla sık query'yi destekleyebiliyorsa ROI yükselir. Nadiren kullanılan kolon kombinasyonları için aşırı özel index üretmekten kaçınılmalıdır.
Join + Filter + Sort Sorguları
Gerçek sorgular çoğu zaman yalnızca WHERE filtresi içermez. Join key, tenant filter ve order column aynı execution plan içinde rol oynar. Composite index nested-loop join'in inner lookup'ını ve order ihtiyacını birlikte destekleyebilir. Ancak key sırası join ve sort semantiğine göre test edilmelidir. En selective kolon kuralını mekanik biçimde uygulamak bu yüzden doğru değildir.
Composite Index Kolon Sırası Nasıl Belirlenir?
Composite index kolon sırası equality, range, sorting ve workload frequency birlikte değerlendirilerek belirlenmelidir. Equality predicate'lerin leading bölümde bulunması çoğu B-tree kullanımında avantaj sağlar. Range başlayan noktadan sonra scan alanını daraltma davranışı motor ve optimizer özelliğine göre değişebilir. ORDER BY veya GROUP BY index order'dan faydalanabiliyorsa sort maliyeti ortadan kalkabilir. Son karar her zaman gerçek execution plan ve ölçümle doğrulanmalıdır.
Equality Predicate'ler
Equality condition index key alanını belirli bir prefix'e sabitler. tenant_id = 42 gibi koşul leading key olduğunda sonraki kolonların ordered range'i daha dar hale gelir. Birden fazla equality kolonun kendi aralarındaki sırası bazı query'lerde daha az kritik olabilir. Ancak diğer query family'leri hangi prefix'i kullanabiliyor sorusu sıralamayı etkiler. Workload coverage tek sorgu optimizasyonundan daha değerli olabilir.
Range Predicate'ler
>, < veya BETWEEN index içinde range scan başlatır. Klasik B-tree düşüncesinde range sonrası kolonlar scan sınırını aynı ölçüde daraltamayabilir. Buna rağmen filter recheck veya modern skip-scan benzeri optimizasyonlar ek fayda sağlayabilir. Equality kolonları çoğu zaman range key'den önce konumlandırılır. Gerçek engine davranışı execution plan üzerinden doğrulanmalıdır.
ORDER BY
Sort gereken sorguda index order önemli kazanç sağlayabilir. Equality predicate ile sabitlenmiş prefix sonrasında order columns key'e eklenebilir. LIMIT varsa engine ilk birkaç kaydı bulduktan sonra durabilir. Bu durum Top-N query'lerde çok etkilidir. Yalnızca filter selectivity'ye bakıp sort maliyetini göz ardı etmek yanlış column order üretebilir.
GROUP BY
Bazı grouping sorguları index'in ordered yapısından faydalanabilir. Ancak aggregate workload geniş veri tarıyorsa columnstore veya hash aggregate daha uygun olabilir. Group key'leri composite index içinde bulunabilir. Index grouping'i desteklese bile projection için base table erişimi maliyetli olabilir. Execution plan aggregate strategy ile birlikte incelenmelidir.
Selectivity
Selectivity önemli karar girdisidir fakat tek kriter değildir. Yüksek selective range kolonu başa koymak sonraki equality ve sort kullanımını bozabilir. Equality prefix başka query'leri de destekliyorsa daha düşük cardinality alan leading olabilir. Data distribution parameter value'ya göre farklı plan oluşturabilir. Column order gerçek query family'lerinin toplam maliyetini düşürmelidir.
Query Frequency
Bir index bir sorguyu yüzde 90 hızlandırabilir fakat sorgu günde bir kez çalışıyorsa daha sık kullanılan query'yi bozmak mantıklı değildir. Frequency ağırlıklı workload modeli yapılabilir. En çok çağrılan sorgular için prefix coverage öncelik kazanabilir. Monthly report gibi business-critical exception'lar ayrıca değerlendirilir. Index design tek query benchmark'ına sıkışmamalıdır.
Gerçek Execution Plan
Teorik doğru görünen index optimizer tarafından hiç kullanılmayabilir. Plan index seek veya scan'ın hangi koşulları gerçekten kullandığını gösterir. Estimated ve actual row farkı statistics problemine işaret edebilir. Sort, key lookup ve residual predicate operator'ları ayrıca incelenir. Index değişikliği öncesi ve sonrası aynı representative parametrelerle plan karşılaştırılmalıdır.
“En Selective Kolon İlk Sırada Olmalı” Kuralı Her Zaman Doğru mu?
Hayır, bu kural yararlı bir sezgi olsa da composite index tasarımını tek başına belirleyemez. Equality ve range sırası, sort gereksinimi, join pattern ve diğer query'lerin prefix kullanımı daha önemli olabilir. Highly selective kolon range predicate ise onu başa almak index'in sonraki key'lerle faydasını azaltabilir. Daha düşük-cardinality tenant equality key'i leading olduğunda sistem daha iyi query coverage sağlayabilir. Workload-based tasarım textbook kuralından daha güvenlidir.
Equality + Range Senaryosu
tenant_id = ? AND created_at > ? query'sinde tenant equality, timestamp range'dir. Tenant tek başına çok selective olmayabilir. Buna rağmen (tenant_id, created_at) query'nin tek tenant içindeki zaman aralığını hızlı taramasını sağlar. Timestamp'i başa almak bütün tenant'ların range'ini tarama ihtiyacı doğurabilir. Gerçek data distribution yine plan ile kontrol edilmelidir.
Sort Gereksinimi
WHERE status='pending' ORDER BY created_at LIMIT 100 sorgusunda status düşük cardinality olsa bile leading key olarak değerli olabilir. Sonraki created_at sırası Top-N retrieval'i hızlandırır. Sadece created_at'ın daha selective olduğunu düşünmek query semantics'i kaçırabilir. Pending subset çok küçükse partial index daha da iyi olabilir. Sort operator'ının maliyeti plan içinde ayrıca ölçülmelidir.
Join Gereksinimi
Nested loop join inner table'da join key üzerinden tekrar lookup yapabilir. Join key'in uygun prefix'te olması toplam maliyeti ciddi azaltır. Tek bir filter kolon daha selective olsa bile join access path daha sık kullanılıyor olabilir. Composite key join ile additional filter'ı birlikte destekleyebilir. Join algorithm değiştikçe ideal index de değişebilir.
Bir İndeks ile Birden Fazla Query'yi Desteklemek
Bir query için kusursuz index başka on query'ye hiç fayda sağlamayabilir. Benzer query family'leri ortak prefix kullanıyorsa biraz daha genel composite index daha yüksek toplam ROI sağlayabilir. Redundant index sayısı azalır. Write amplification ve cache footprint düşer. Index design review her adayın hangi query ID'lerini desteklediğini kaydetmelidir.
Workload-Based Column Order
Workload-based yaklaşım query frequency, latency ve business importance değerlerini birlikte kullanır. Candidate column order'lar representative test set üzerinde benchmark edilir. Her query için logical reads ve execution plan kaydedilir. Tek sorgu kazanırken diğerlerinin regression yaşayıp yaşamadığı görülür. Production feedback ile index order gerektiğinde yeniden ele alınır.
Leftmost Prefix Rule Nedir?
Leftmost prefix kuralı composite B-tree index'in leading kolonları üzerinden en doğal biçimde kullanılabildiğini anlatan temel ilkedir. (a,b,c) index'i klasik olarak a, a,b ve a,b,c prefix'lerini etkili destekler. Leading kolon atlandığında index'in geleneksel seek avantajı azalabilir. Bununla birlikte modern optimizer'lar skip scan veya index combination gibi ek yollar kullanabilir. Bu nedenle leftmost prefix güçlü bir mental modeldir fakat bütün motor ve versiyonlarda mutlak fizik kuralı değildir.
MySQL Composite Index Davranışı
MySQL multiple-column index'leri leading prefix'leri üzerinden kullanabilir. (a,b,c) key sırası sorgu tasarımında bu nedenle önemlidir. MySQL optimizer bazı sürümlerde skip-scan range access gibi özel optimizasyonlar da uygulayabilir. Index Merge ayrı single-column index'leri bazı query'lerde birleştirebilir. Sonuç EXPLAIN ile doğrulanmalıdır.
(a, b, c) İndeksi
Bu index önce a, aynı a içinde b, ardından c değerlerine göre sıralıdır. Sıralama fiziksel olarak üç bağımsız index anlamına gelmez. Leading key kombinasyonları tek tree traversal içinde etkili olabilir. b veya c tek başına sorgulandığında kullanım motorun ek optimizasyonlarına bağlıdır. Bu yüzden index tasarımında hangi query'lerin leading prefix'e sahip olduğu bilinmelidir.
a
WHERE a = ? index'in ilk kolonunu doğrudan kullanır. Tree uygun a aralığına hızlıca gider. Aynı value altında b ve c sıralaması bulunur. Query başka kolon döndürüyorsa table lookup gerekebilir. a çok düşük selectivity taşıyorsa optimizer scan tercih edebilir.
a, b
WHERE a=? AND b=? ilk iki key üzerinden daha dar range bulabilir. c koşulu olmasa da prefix geçerlidir. Bu query family composite index için doğal hedeftir. Projection index içinde kalıyorsa covering davranışı oluşabilir. Additional sort c üzerinde ise aynı order'dan faydalanma ihtimali vardır.
a, b, c
Bütün key'lerde equality varsa index çok dar lookup sağlayabilir. Unique composite constraint ise sonuç cardinality hakkında güçlü bilgi verir. Range son kolon c üzerinde olduğunda da yapı oldukça etkilidir. Index width yüksekse write maliyeti yine ölçülmelidir. Her üç kolonun da query'lerde birlikte kullanılması index yatırımını daha anlamlı kılar.
Kolon Atlamanın Etkisi
WHERE b=? sorgusunda a leading key koşulu yoktur. Klasik leftmost prefix anlayışında efficient seek yapılamaz. Optimizer index full scan, skip scan veya başka index'i seçebilir. Leading kolon distinct value sayısı düşükse skip-scan benzeri yöntem ekonomik olabilir. Plan görmeden index'in “kesin kullanılamayacağını” söylemek güncel optimizer'lar için fazla kesin olur.
Range Predicate Sonrası Kolonlar
a=? AND b>? AND c=? sorgusunda b range oluşturur. Geleneksel yaklaşım c'nin scan başlangıç ve bitiş aralığını aynı doğrudanlıkla belirleyemediğini söyler. Engine c'yi index condition veya residual filter olarak yine kullanabilir. PostgreSQL skip scan bazı senaryolarda ek index searches ile daha fazla daraltma yapabilir. Gerçek scan edilen page ve row sayısı plan üzerinden incelenmelidir.
PostgreSQL Skip Scan Nedir?
PostgreSQL’in güncel multicolumn B-tree planlamasında skip scan, leading kolonlardan birinde doğrudan equality predicate bulunmadığında sonraki kolon koşullarından yararlanabilen bir optimizasyondur. Planner eksik leading kolon için olası değerler üzerinde dinamik equality aramaları oluşturabilir. Bu yöntem özellikle leading kolonun distinct value sayısı düşük olduğunda tüm index'i okumaktan daha ucuz olabilir. Çok fazla distinct leading value varsa tekrar eden search maliyeti artar ve sequential scan daha iyi olabilir. Bu davranış leftmost prefix kuralının hâlâ değerli olduğunu, fakat modern planner'ın bazı boşlukları akıllı şekilde aşabildiğini gösterir.
Leftmost Prefix Kuralının Sınırları
Leftmost prefix iyi bir tasarım rehberidir ancak optimizer implementasyonu zamanla gelişir. PostgreSQL sonraki kolon predicate'ini tamamen yok saymak zorunda değildir. Index içinde filtering veya skip-scan navigation uygulayabilir. Buna rağmen leading key'in yanlış seçilmesi çoğu workload'da hâlâ büyük scan alanı oluşturabilir. Tasarım optimizer istisnasına güvenmek yerine common query prefix'lerini desteklemelidir.
Skip Scan Optimizasyonu
Skip scan index'in bir bölümünü okuyup sonra sonraki uygun key grubuna yeni search ile atlayabilir. Böylece matching olmayan büyük leaf aralıklarının tamamını sequential biçimde geçmek zorunda kalmaz. Planner bu ek searches maliyetini full index veya table scan ile karşılaştırır. Optimization her query'de otomatik olarak seçilmez. EXPLAIN gerçek planın nasıl çalıştığını doğrulamak için kullanılmalıdır.
Distinct Leading Values
Leading kolon yalnızca birkaç distinct value içeriyorsa her value için ayrı probe yapılması ekonomik olabilir. Örneğin enum benzeri bir first key ve selective second key buna adaydır. Leading kolon milyonlarca distinct değere sahipse aynı yaklaşım verimsizleşir. Statistics burada kritik rol oynar. Stale distinct estimate optimizer'ın yanlış karar vermesine neden olabilir.
MySQL ve PostgreSQL Davranışlarının Farklı Olabilmesi
Her iki sistem de composite B-tree üzerinde klasik leading-prefix modelini temel alır ancak optimizer implementation ayrıntıları aynı değildir. MySQL de belirli koşullarda skip-scan range access kullanabilir. PostgreSQL’in güncel planner'ı multicolumn B-tree skip scan davranışını kendi cost modeline göre seçer. Aynı SQL iki motorda farklı plan üretebilir. Engine değiştiren ekiplerin index kurallarını olduğu gibi kopyalamaması gerekir.
Execution Plan ile Doğrulama
Skip scan'in gerçekten kullanılıp kullanılmadığı varsayımla belirlenmemelidir. PostgreSQL EXPLAIN planı index scan ve search davranışı hakkında bilgi verir. EXPLAIN ANALYZE gerçek rows ve timing değerlerini ekler. Buffers bilgisi okunan page miktarını görmeyi sağlar. Production'da pahalı query'yi gerçekten çalıştıran ANALYZE kullanımında operasyon etkisine dikkat edilmelidir.
Composite Index mi Birden Fazla Single-Column Index mi?
İki yaklaşımın da doğru olduğu workload'lar vardır. Composite index tek ordered path içinde birden fazla predicate ve sort gereksinimini karşılayabilir. Ayrı index'ler optimizer'a AND veya OR combination esnekliği verir. Composite yapı daha geniş olabilirken birden fazla single index toplamda daha fazla metadata ve write operation yaratabilir. Seçim yalnızca storage miktarıyla değil query plan kalitesiyle yapılmalıdır.
Composite Index Scan
Composite index uygun prefix predicate'lerinde tek traversal ile dar result set üretebilir. Ordering korunabildiği için separate sort gerekmeyebilir. Equality plus range query'lerde güçlüdür. Tek index read path cache locality açısından avantajlı olabilir. Ancak leading prefix olmayan query'leri destekleme esnekliği sınırlıdır.
Bitmap Index Combination
PostgreSQL birden fazla index scan sonucunu memory bitmap içinde AND veya OR ile birleştirebilir. Bu yaklaşım ayrı single-column index'leri birlikte kullanmayı mümkün kılar. Bitmap heap access physical page order üzerinden yapılabildiği için random lookup azaltılabilir. Buna karşılık original index ordering kaybolur ve ORDER BY için ayrıca sort gerekebilir. Planner composite scan ile bitmap combination arasında cost karşılaştırması yapar.
Index Merge
MySQL optimizer belirli query'lerde farklı index'lerin range scan sonuçlarını merge edebilir. Intersection veya union türü stratejiler kullanılabilir. Bu seçenek composite index olmadığı durumda faydalı olabilir. Ancak dedicated composite index common query için daha az work yapabilir. EXPLAIN hangi access method'un seçildiğini göstermelidir.
Storage Maliyeti
Üç single-column index ile bir üç-column composite index'in disk maliyeti aynı değildir. Row locator veya primary key payload her index entry'de tekrar bulunabilir. InnoDB secondary index'lerinde primary key kolonları da entry içinde taşındığı için geniş primary key bu maliyeti büyütür. Composite index daha geniş key taşısa da duplicate structure overhead'ini azaltabilir. Gerçek index size catalog view üzerinden ölçülmelidir.
Write Maliyeti
Her INSERT bütün uygun index'lere entry ekler. Birden fazla single index daha fazla tree update demektir. Composite index tek structure update eder fakat key daha geniştir. Update edilen kolon hangi index'lerde bulunuyorsa maintenance orada oluşur. Write benchmark candidate tasarımları gerçek DML oranıyla karşılaştırmalıdır.
Query Pattern'e Göre Karar
Sorgular kolonları sürekli birlikte kullanıyorsa composite index güçlü adaydır. Kolonlar farklı query'lerde bağımsız kullanılıyorsa separate index daha esnek olabilir. OR-heavy workload index combination'dan faydalanabilir. Sorting requirement composite ordered path lehine karar değiştirebilir. Tek doğru cevap değil workload'a göre ölçülen en iyi denge vardır.
Covering Index Nedir?
Covering index sorgunun ihtiyaç duyduğu bütün kolonları index içinde sağlayabilen yapıdır. Böylece base table veya heap üzerinden ek row lookup ihtiyacı azalabilir. SQL Server ve PostgreSQL INCLUDE gibi özelliklerle projection kolonlarını search key'e dönüştürmeden leaf seviyesinde taşıyabilir. MySQL'de ayrı INCLUDE syntax'i olmasa da secondary index gerekli kolonları taşıyorsa covering erişim oluşabilir. Covering kazancı büyük olabilir fakat index'i gereksiz genişletmek cache ve write performansını bozabilir.
Query İçin Gerekli Tüm Veriyi İndekste Tutmak
Query filter ve select kolonlarının tamamı index entry içinde bulunuyorsa engine base row'a gitmeden sonuç üretebilir. Bu özellikle çok sık point veya range lookup yapan sorgularda random I/O azaltır. Her SELECT kolonunu index'e eklemek yine de doğru değildir. Wide text veya large payload index boyutunu hızla büyütür. Sadece kritik query'nin gerçekten ihtiyaç duyduğu dar kolonlar seçilmelidir.
Index-Only Scan
PostgreSQL index-only scan gerekli kolonlar index içinde olduğunda heap access ihtiyacını azaltabilir. MVCC visibility nedeniyle bazı tuple'larda visibility map kontrolü ve gerektiğinde heap ziyareti yine oluşabilir. Dolayısıyla “covering index var, heap hiç okunmaz” varsayımı mutlak değildir. Read-mostly ve vacuum tarafından iyi yönetilen tablolarda kazanç daha belirgin olabilir. Plan ve buffers gerçek heap fetch davranışını göstermelidir.
Table/Heap Lookup'ı Önlemek
Non-covering secondary index matching row'u bulduktan sonra eksik kolon için base storage'a gider. Çok sayıda row döndüğünde bu lookup'lar pahalı hale gelir. Included projection data bu ikinci erişimi azaltabilir. Buna karşılık index leaf page'leri büyüdüğü için daha az entry page'e sığar. Kazanç lookup sayısı ile ek storage maliyeti üzerinden değerlendirilmelidir.
SQL Server INCLUDE
SQL Server nonclustered index'te nonkey kolonları INCLUDE ile leaf seviyesinde saklayabilir. Bu kolonlar search order'ın parçası değildir. Query'nin projection ihtiyacını karşılayarak key lookup'ı azaltabilir. Çok sayıda veya geniş include column page density'yi düşürür. Bu nedenle covering uğruna bütün tabloyu index içinde kopyalamamak gerekir.
PostgreSQL INCLUDE
PostgreSQL desteklenen access method'larda non-key payload kolonlarını INCLUDE ile index'e ekleyebilir. Bu kolonlar tree navigation key'i değildir. Index-only scan için gerekli projection data sağlanabilir. Included data leaf tuple boyutunu artırır ve bazı B-tree optimizasyonlarını etkileyebilir. Kullanım read benefit ile storage ve DML maliyeti üzerinden ölçülmelidir.
MySQL Covering Index Davranışı
MySQL'de covering index bir sorgunun ihtiyaç duyduğu kolonların index entry içinden karşılanmasıyla oluşur. InnoDB secondary index entry'si primary key kolonlarını da taşıdığı için bazı query'ler bunu doğal olarak kullanabilir. Ayrı bir INCLUDE syntax'i yoktur. Projection kolonlarını key sonuna eklemek index order ve width'i etkiler. EXPLAIN covering behavior hakkında ipucu verebilir.
Covering Index Ne Zaman Fazla Genişler?
Covering index faydalı olduğu için her sorgunun bütün SELECT kolonlarını index'e doldurmak cazip gelebilir. Fakat geniş leaf row daha az entry'nin aynı page'e sığmasına neden olur. Tree ve cache footprint büyür. Her DML daha fazla byte yazabilir. Covering yalnızca yüksek-value query'lerde kontrollü uygulanmalıdır.
Wide Index
Wide index çok sayıda veya büyük kolon taşıyan index'tir. Key veya included payload page kullanımını artırır. Daha fazla page daha fazla buffer cache gerektirir. Scan sırasında daha çok page okunabilir. Query benefit düşerse geniş index net performans kaybına dönüşebilir.
Disk Kullanımı
Index data table data'nın önemli bölümünü tekrar depolayabilir. Birkaç wide covering index toplam storage'ı table size'ın üzerine çıkarabilir. Backup ve restore süreleri de büyüyebilir. Replica transfer ve snapshot maliyeti artar. Capacity planning index storage'ını ayrı metrik olarak takip etmelidir.
Buffer Cache
Büyük index daha fazla cache page tüketir. Sık kullanılan küçük index'lerin page'leri eviction yaşayabilir. Query kendi covering index'inden fayda görürken sistem genelinde cache churn yaratabilir. Cache hit oranı tek global metric yerine object bazında incelenebilir. Index ROI bu sistem etkisini kapsamalıdır.
Write Amplification
Included column update edildiğinde index leaf entry de değişebilir. Birden fazla covering index aynı geniş payload'ı taşıyorsa tek row update birçok page write oluşturur. WAL veya redo hacmi artar. Replica bandwidth ve lag etkilenebilir. High-write table'da covering index sayısı bu nedenle sınırlı tutulmalıdır.
Bütün SELECT Kolonlarını İndekse Eklememek
Bir query SELECT * kullanıyorsa onu tamamen cover etmeye çalışmak çoğu zaman kötü fikirdir. Önce projection gerçekten ihtiyaç duyulan kolonlara indirilebilir. Large text veya JSON kolonları base lookup'ta bırakılabilir. Sık kullanılan list page için dar summary index yeterli olabilir. Query rewrite ile index design birlikte düşünülmelidir.
Clustered ve Nonclustered Index Arasındaki Fark
Clustered ve nonclustered kavramlarının anlamı database engine storage modeline göre değişir. SQL Server clustered index leaf seviyesinde data row'larının kendisini organize eder. MySQL InnoDB primary key'i clustered index olarak kullanır ve secondary entries primary key değerini taşır. PostgreSQL ise heap storage ile index'leri ayrı tutar. Bu fark primary key genişliği, lookup maliyeti ve index bakım kararlarını doğrudan etkiler.
Clustered Index
Clustered structure row data'yı index key düzeniyle yakın ilişki içinde saklar. Bu nedenle primary veya clustered-key lookup doğrudan data page'e ulaşabilir. Bir tabloda fiziksel storage organizasyonu nedeniyle genellikle tek clustered ordering bulunur. Key değişikliği row movement veya ağır maintenance gerektirebilir. Motorun gerçek storage implementation'ı detaylarda farklılaşır.
Nonclustered / Secondary Index
Secondary index base storage'dan ayrı bir search structure'dır. Entry matching row'a erişmek için locator taşır. SQL Server locator clustered key veya RID olabilir. InnoDB secondary entry primary key'i taşır. PostgreSQL index tuple heap TID üzerinden row'a referans verir.
SQL Server Davranışı
SQL Server clustered index data row'larını leaf level'da taşır. Nonclustered index gerekli olduğunda clustered key üzerinden base row'a ulaşabilir. Included columns covering query oluşturabilir. Clustered key genişliği nonclustered index footprint'ini etkileyebilir. Heap kullanılan tabloda nonclustered locator farklı davranır.
MySQL InnoDB Davranışı
InnoDB primary key'i clustered index olarak kullanır. Secondary index entry'lerinde indexed key yanında row'un primary key kolonları bulunur. Bu yüzden uzun UUID string veya geniş composite primary key bütün secondary index'leri büyütebilir. Secondary lookup önce secondary tree'de, sonra clustered tree'de ikinci search gerektirebilir. Primary key tasarımı bu nedenle InnoDB'da özellikle önemlidir.
PostgreSQL Heap Storage Farkı
PostgreSQL table rows heap içinde index'ten ayrı saklanır. B-tree index row'un heap tuple location bilgisine referans verir. Normal index scan hem index hem heap page'lerine erişebilir. Index-only scan visibility koşulları uygunsa heap ziyaretini azaltabilir. SQL Server veya InnoDB clustered davranışını PostgreSQL'e doğrudan taşımamak gerekir.
Primary Key Seçimi İndeks Performansını Nasıl Etkiler?
Primary key yalnızca entity identity değildir, bazı storage engine'lerde bütün secondary index yapısının maliyetini etkiler. Kısa ve stable key page density açısından avantaj sağlar. Sequential key insertion locality'yi artırabilir. Random key insert tree'nin farklı page'lerine dağılarak cache ve split davranışını etkileyebilir. Distributed ID gereksinimi varsa UUIDv7 veya ULID gibi zaman sıralı seçenekler değerlendirilirken engine ve uniqueness ihtiyaçları birlikte ele alınmalıdır.
BIGINT
BIGINT auto-increment key küçük ve sıralı bir identifier sağlar. InnoDB clustered primary key için iyi locality üretebilir. Secondary index'lerde payload olarak taşındığında byte maliyeti kontrollüdür. Distributed ID generation için merkezi sequence dependency'si oluşturabilir. Security açısından guessable ID olması public authorization modelinden ayrı çözülmelidir.
UUID
Klasik random UUID geniş ve dağıtık uniqueness sağlar. Random insertion clustered B-tree'de farklı page'lere write yapabilir. String formatta saklamak binary representation'a göre daha fazla alan tüketir. InnoDB secondary index'lerinde primary key payload büyüyebilir. Distributed system kolaylığı ile storage maliyeti birlikte değerlendirilmelidir.
UUIDv7
UUIDv7 zaman sıralı yapı taşıdığı için random UUID'ye göre insert locality'sini iyileştirebilir. Yine UUID boyutunda identifier sağlar ve distributed generation için uygundur. Aynı timestamp içinde randomness uniqueness'i destekler. Database native type kullanımı string storage'dan daha verimli olabilir. Gerçek page split ve contention davranışı workload benchmark ile ölçülmelidir.
ULID
ULID timestamp ve randomness bileşimiyle lexicographically sortable identifier sunar. Uygulama tarafında kolay üretilebilir. Text representation binary key'e göre daha geniş olabilir. Native database semantics UUID kadar standartlaşmış olmayabilir. Index key olarak kullanırken collation ve storage format seçimi önemlidir.
Random vs Sequential Keys
Sequential keys tree'nin sağ tarafında yoğun insert locality sağlar. Bu cache açısından avantajlı olabilir fakat aşırı concurrency hot-page contention yaratabilir. Random keys write'ları ağaca dağıtır ancak daha fazla page churn ve split oluşturabilir. Modern storage engine'ler bu davranışları farklı tekniklerle yönetir. Tek genel kural yerine write concurrency ve page behavior ölçülmelidir.
Secondary Index Boyutu
Özellikle InnoDB'da primary key secondary index entry'lerinde bulunduğu için key width çarpan etkisi yaratır. On adet secondary index varsa geniş primary key defalarca depolanır. SQL Server clustered key de nonclustered locator olarak etkili olabilir. PostgreSQL storage modeli farklıdır. Primary key seçimi database engine'e göre değerlendirilmelidir.
Page Split
Yeni key mevcut dolu page'in ortasına girmek zorundaysa page split oluşabilir. Random insertion bu durumu daha geniş key space'e yayabilir. Sequential insertion genellikle rightmost page üzerinde ilerler. Fill factor belirli engine'lerde future insert için boşluk bırakabilir. Split sayısı tek başına değil write latency ve page density ile birlikte izlenmelidir.
Partial ve Filtered Index Nedir?
Partial veya filtered index tablonun yalnızca predicate'e uyan alt kümesini indeksler. PostgreSQL buna partial index, SQL Server filtered index terminolojisini kullanır. Özellikle hot data toplam tablonun küçük bölümü olduğunda büyük avantaj sağlar. Index daha küçük kaldığı için cache ve write maliyeti azalır. Query predicate'in index predicate'iyle optimizer tarafından eşleştirilebilir olması kritik şarttır.
Tablonun Sadece Bir Alt Kümesini İndekslemek
Bir milyar order'ın yalnızca iki milyonu pending olabilir. Bütün order'ları status index'e koymak yerine yalnızca pending subset'i taşımak daha ekonomik olabilir. Query sürekli bu subset'i arıyorsa yüksek değer üretir. Completed historical row'lar index maintenance dışında kalabilir. Data distribution zamanla değişirse fayda yeniden ölçülmelidir.
WHERE deleted_at IS NULL
Soft-delete tablosunda aktif kayıtlar deleted_at IS NULL predicate'iyle seçilebilir. Eğer aktif kayıtlar küçük subset ise partial index oldukça kompakt olur. Aktif kayıtlar tablonun yüzde 99'uysa avantaj daha sınırlıdır. Query'nin aynı predicate'i açık biçimde kullanması gerekir. Unique partial index aktif kayıtlar için özel uniqueness rule da sağlayabilir.
Aktif Kullanıcılar
Uzun geçmişe sahip account tablosunda yalnızca aktif users operational query'lerde kullanılıyor olabilir. Active subset için filtered index login veya assignment sorgularını hızlandırabilir. Status sık değişiyorsa row index'e girip çıktığı için write cost oluşur. Dormant historical data index dışı kalır. Privacy ve retention policy ayrıca uygulanmalıdır.
Pending Orders
Queue benzeri order processing sisteminde pending kayıtlar hızlı seçilmelidir. Completed rows zamanla milyonlarca birikir. Partial index pending subset'i küçük ve cache-friendly tutar. created_at key'iyle birlikte oldest-first worker query desteklenebilir. Status transition index maintenance oluşturur fakat full index'e göre daha küçük footprint korunur.
PostgreSQL Partial Index
PostgreSQL CREATE INDEX ... WHERE predicate ile partial index oluşturur. Planner query predicate'in index predicate'ini imply edebildiğinde kullanabilir. Parameterized veya farklı biçimde yazılmış predicate bazı durumlarda eşleşmeyi zorlaştırabilir. Partial index common values'ı dışarıda bırakmak için de kullanılabilir. Statistics ve execution plan gerçek kullanımın doğrulamasıdır.
SQL Server Filtered Index
SQL Server filtered nonclustered index belirli row subset'i için oluşturulur. Daha küçük index ve filtered statistics plan kalitesine yardımcı olabilir. Simple predicate desteği ve gerekli SET options gibi engine-specific kurallar vardır. Included columns ile filtered covering index oluşturulabilir. Query predicate uyumu plan seçimi için önemlidir.
Partial Index Ne Zaman Özellikle Faydalıdır?
Partial index en çok küçük fakat sık erişilen hot subset bulunduğunda değer üretir. Common ve nadiren sorgulanan değerleri index dışında bırakmak storage maliyetini düşürür. Write işlemleri yalnızca predicate'e dahil row'lar için index maintenance gerektirir. Ancak predicate query'lerle uyumlu değilse index hiç kullanılmayabilir. Data distribution ve status transition oranı production telemetry ile izlenmelidir.
Hot Data Azınlıktaysa
Toplam row'ların yüzde 1'i operational query'lerde kullanılıyorsa full index gereksiz büyüyebilir. Partial index bu yüzde 1'i cache içinde tutmayı kolaylaştırır. Queue, active session veya unprocessed event tabloları tipik örneklerdir. Sıcak subset büyürse index ROI azalabilir. Metric ile subset ratio takip edilmelidir.
Common Value'ları İndeks Dışında Bırakmak
Bir status value satırların yüzde 98'ini oluşturuyor ve neredeyse hiç sorgulanmıyorsa index'te yer kaplaması anlamsız olabilir. Nadir değerler için partial index oluşturulabilir. Bu davranış selectivity ve maintenance açısından faydalıdır. Query common value aradığında full scan doğal plan olabilir. İki workload aynı anda doğru olabilir.
İndeks Boyutunu Küçültmek
Daha az entry daha az disk page anlamına gelir. Tree depth ve leaf footprint azalabilir. Cache hit oranı yükselir. Backup ve replication storage maliyeti düşebilir. Boyut avantajı catalog metrics ile doğrudan ölçülebilir.
Write Maliyetini Azaltmak
Predicate dışında kalan row insert veya update işlemleri index'i her zaman değiştirmez. Bu durum write-heavy historical data için önemli kazanç sağlar. Row predicate sınırını geçtiğinde index entry ekleme veya çıkarma gerekir. Status transition yoğun queue'larda bu maliyet yine vardır. Full index ile karşılaştırmalı write benchmark yapılmalıdır.
Predicate'in Query ile Uyumlu Olması
Optimizer partial index'in yalnızca güvenli olduğu query'lerde kullanılması gerektiğini kanıtlamalıdır. Query predicate daha genişse index eksik satır döndüreceği için kullanılamaz. SQL'in eşdeğer ama farklı expression biçimi bazı motorlarda implication detection sınırına takılabilir. Prepared statement parameterization özel dikkat gerektirebilir. Production plan'lar mutlaka gözlemlenmelidir.
Functional / Expression Index Nedir?
Functional veya expression index kolonun ham değeri yerine bir expression sonucunu indeksler. Case-insensitive email search veya hesaplanan JSON property buna örnektir. PostgreSQL expression index, MySQL functional key parts ve SQL Server computed-column index gibi farklı mekanizmalar sunabilir. Query expression ile index expression semantic olarak uyumlu olmalıdır. Her function'ın determinism veya immutability şartları engine'e göre kontrol edilmelidir.
LOWER(email)
WHERE LOWER(email)=... sorgusu normal email B-tree index'ini her motorda doğrudan kullanamayabilir. LOWER(email) expression index bu access pattern'i destekleyebilir. Ancak case-insensitive collation veya data type kullanmak daha doğal alternatif olabilir. Email normalization business identity semantiğiyle karıştırılmamalıdır. Unique case-insensitive constraint gerekirse ayrıca tasarlanmalıdır.
Hesaplanmış Alanlar
Frequently queried expression generated veya computed column olarak materialize edilebilir. Bu kolon normal index ile desteklenebilir. Hesaplama write sırasında oluşur fakat read query daha basit hale gelir. Deterministic expression requirement engine tarafından uygulanabilir. Storage overhead ile query frequency karşılaştırılmalıdır.
Tarih Fonksiyonları
DATE(created_at)=? gibi predicate ham timestamp index'ini kullanmayı zorlaştırabilir. Query'yi range olarak yeniden yazmak çoğu zaman daha iyidir. Alternatif olarak expression index oluşturulabilir. Time zone semantics doğru tanımlanmalıdır. Gün sınırı kullanıcı locale'inden değil business time zone'dan gelebilir.
JSON Property
JSON içindeki tek scalar property sürekli equality veya range ile aranıyorsa expression veya generated column index kullanışlı olabilir. Tüm JSON document'ini GIN ile indekslemekten daha küçük olabilir. Schema-less data içinde bu property'nin type consistency'si doğrulanmalıdır. Missing value ve null semantics açık olmalıdır. Query expression exact index extraction mantığıyla uyumlu tutulmalıdır.
Query Expression ile Index Expression Uyumunu Sağlamak
Optimizer expression index'i kullanabilmek için query expression'ını tanıyabilmelidir. Farklı cast veya function nesting eşleşmeyi bozabilir. Application shared query helper aynı expression pattern'ini kullanabilir. Plan regression test bu bağı korur. Expression değiştirildiğinde index definition migration'ı da gözden geçirilmelidir.
SARGability Nedir?
SARGability predicate'in index üzerinden etkili search argument olarak kullanılabilmesini ifade eder. Kolona function uygulamak, implicit conversion veya leading wildcard index seek imkanını azaltabilir. Bazen yeni index eklemek yerine sorguyu SARGable biçimde yeniden yazmak daha iyi çözümdür. SARGability engine optimizer kurallarıyla ilişkilidir. Execution plan predicate'in seek condition mı residual filter mı olduğunu göstermelidir.
İndeks Kullanılabilir Predicate
created_at >= ? AND created_at < ? gibi range predicate B-tree index için doğaldır. Kolon ham biçimde comparison tarafında kalır. Parameter type kolon type'ıyla uyumludur. Optimizer scan sınırlarını kolayca hesaplayabilir. Bu pattern function-wrapped date comparison'dan daha iyi olabilir.
Kolona Function Uygulamak
LOWER(column) veya DATE(column) gibi expression normal index key'den farklı değer üretir. Functional index yoksa engine row başına function hesaplamak zorunda kalabilir. Query rewrite mümkünse ham kolon range'i tercih edilir. Expression index gerçekten sık pattern ise kullanılır. Function deterministic behavior taşımak zorundadır.
Implicit Type Conversion
String kolon numeric parameter ile karşılaştırılırsa optimizer type conversion uygulayabilir. Conversion index kolon tarafında gerçekleşirse seek capability bozulabilir. Parameter binding doğru database type kullanmalıdır. Execution plan conversion warning veya function gösterebilir. Application ORM mapping bu tür hataların yaygın kaynağıdır.
Leading Wildcard
LIKE '%abc' araması B-tree prefix order'dan yararlanamaz. LIKE 'abc%' uygun collation ve engine behavior ile range benzeri index kullanabilir. Contains search için full-text veya trigram benzeri özel index daha uygundur. Kullanıcı search gereksinimi önce semantic olarak tanımlanmalıdır. Yanlış index ile wildcard sorgusunu zorlamak yeterli çözüm değildir.
SARGable Query Rewrite
İlk adım mevcut predicate'i index-friendly range veya equality biçimine dönüştürmektir. Tarih function'ı yerine sınır değerleri hesaplanabilir. Cast parameter tarafına taşınabilir. Derived computation stored/generated column'a alınabilir. Query rewrite sonrası yeni index gerekip gerekmediği tekrar plan ile ölçülmelidir.
İndeks Var Ama Database Neden Kullanmıyor?
Bir index'in varlığı optimizer'ın onu seçmesi gerektiği anlamına gelmez. Cost-based optimizer full scan'in toplam maliyetini daha düşük bulabilir. Düşük selectivity, stale statistics veya type conversion index'i değersiz hale getirebilir. Composite key sırası query predicate'iyle uyuşmayabilir. Index hint vermeden önce optimizer'ın neden başka plan seçtiğini anlamak gerekir.
Düşük Selectivity
Predicate tablonun büyük kısmını döndürüyorsa index önce milyonlarca locator bulur ve sonra base row'lara gider. Bu iki aşamalı erişim sequential scan'den pahalı olabilir. Covering index bu maliyeti azaltabilir fakat yine scan volume yüksektir. Optimizer histogram üzerinden result ratio tahmin eder. Estimate yanlışsa statistics güncellenmelidir.
Tablonun Büyük Bölümünün Döndürülmesi
Query satırların yüzde 60'ını istiyorsa full scan çoğu zaman mantıklıdır. Index kullanmak random access ve ek tree traversal getirir. Analytical query bunu sık yapabilir. Index hint ile zorlamak latency'yi artırabilir. Planın business expectation ile uyumlu olduğunu anlamak önemlidir.
Eski Statistics
Statistics distribution eskiyse optimizer yanlış row estimate yapabilir. Yeni status value hızla büyümüş olabilir. Cardinality estimate yanlış plan seçimine yol açar. ANALYZE veya engine-specific statistics update plan kalitesini düzeltebilir. Index eklemek stale statistics problemine geçici yama olmamalıdır.
Type Conversion
Predicate data type index column type'ıyla uyuşmazsa implicit conversion oluşabilir. Conversion kolon üzerinde uygulanırsa seek zorlaşabilir. ORM parameter type'ı schema ile eşleştirilmelidir. Plan conversion operator'ını görünür kılar. Query düzeltildiğinde mevcut index kullanılmaya başlayabilir.
Function Kullanımı
Indexed kolon function içinde sarılıysa normal B-tree ham value order'ını doğrudan temsil etmez. Functional index veya SARGable rewrite gerekir. Date truncation buna sık örnektir. Expression kullanımı convenience için bütün query'lere yayılmamalıdır. Shared repository method doğru pattern'i standardize edebilir.
Yanlış Composite Order
Query leading key'leri kullanmıyorsa composite index'in etkisi azalabilir. Sort veya range behavior da farklılaşır. Yeni single index eklemeden önce mevcut composite'in order'ı workload'a göre yeniden değerlendirilebilir. Ancak order değişikliği başka query'leri bozabilir. Index replacement planı usage telemetry ile yapılmalıdır.
Cost-Based Optimizer'ın Full Scan'i Daha Ucuz Bulması
Optimizer index'i görür fakat estimated total cost daha yüksekse kullanmaz. Disk page sayısı, random access ve row count tahmini bu kararı etkiler. Bu her zaman optimizer hatası değildir. Gerçek runtime full scan gerçekten daha hızlı olabilir. Hint kullanmadan önce benchmark bunu doğrulamalıdır.
Full Table Scan Her Zaman Kötü müdür?
Hayır, full scan bazı workload'larda en doğru plandır. Küçük table tamamıyla memory'de ise index traversal gereksiz overhead yaratabilir. Query büyük row oranı döndürüyorsa sequential scan daha ucuz olabilir. Analytics ve aggregation sorguları zaten geniş veri bölümünü okuyabilir. Performance tuning'in amacı index kullanım oranını değil toplam resource ve latency'yi iyileştirmektir.
Küçük Tablolar
Bir lookup table birkaç yüz row içeriyorsa full scan birkaç memory page okuyabilir. Index traversal ek fayda sağlamaz. Optimizer table size'ı statistics üzerinden görür. Bu table için unused index tutmak write ve storage maliyeti yaratabilir. Schema review küçük lookup tablolarını özel olarak değerlendirebilir.
Tablonun Büyük Bölümünün Okunması
Query yüzde 70 row döndürecekse index üzerinden her row'a ayrı ulaşmak pahalıdır. Sequential read data page'lerini toplu biçimde işler. Covering columnstore gibi başka yapı analytics için daha uygun olabilir. Predicate selectivity gerçek parameter'a göre değişebilir. Parameter sensitivity plan davranışını etkiler.
Sequential I/O
Sequential I/O page'lerin art arda okunmasını sağlar. Storage subsystem bunu random lookup'tan daha verimli işleyebilir. Read-ahead mekanizması throughput'u artırır. SSD sistemlerde fark azalsa da tamamen yok olmaz. Büyük scan workload'unda layout ve compression index kadar önemlidir.
Analytical Queries
Analytics query milyonlarca row üzerinde sum veya group işlemi yapabilir. Rowstore index selective filter yoksa yeterli fayda sağlamaz. Columnstore, partition pruning ve parallel scan daha etkili olabilir. OLTP tuning prensibini aynen uygulamak yanlış sonuç üretir. Workload tipini baştan sınıflandırmak gerekir.
Index Lookup'ın Daha Pahalı Olduğu Durumlar
Non-covering index çok sayıda matching row üretirse her row için base lookup gerekir. Random page access cache miss oluşturabilir. Table scan aynı page'leri bir kez okuyarak daha hızlı tamamlanabilir. Optimizer cost modeli bu trade-off'u hesaplar. Gerçek buffers ve read count kararın doğruluğunu test eder.
EXPLAIN ile İndeks Kullanımı Nasıl Analiz Edilir?
EXPLAIN optimizer'ın sorgu için seçtiği access plan'ı gösterir. Hangi index'in kullanıldığı kadar hangi operator'ların yüksek maliyet taşıdığı da önemlidir. Estimated rows, sort, join ve scan type birlikte okunmalıdır. Engine'ler plan formatı ve terminolojide farklıdır. Ama temel amaç sorgunun veriye hangi yoldan ulaştığını anlamaktır.
Query Plan
Query plan operator'lardan oluşan execution tree veya graph'tır. Scan, join, sort ve aggregate adımları görülür. Parent node maliyeti child operation'ları kapsayabilir. Tek bir pahalı operator gerçek root cause olmayabilir. Plan yukarıdan aşağı değil data flow mantığıyla dikkatli okunmalıdır.
Cost
Optimizer cost gerçek milisaniye değildir. CPU ve I/O gibi tahmini kaynakların engine-specific birimlerle birleşimidir. İki plan alternatifi arasında karşılaştırma yapmak için kullanılır. Cost model hardware gerçeğini tam yansıtmayabilir. Actual runtime ile estimate birlikte değerlendirilmelidir.
Estimated Rows
Estimated rows optimizer'ın statistics üzerinden beklediği cardinality'dir. Join algorithm ve index seçimini doğrudan etkiler. Tahmin 10 iken actual 1 milyon ise plan büyük ihtimalle yanlış kaynak dağıtır. Stale statistics veya correlated columns sebep olabilir. Extended statistics veya histogram çözüm sağlayabilir.
Actual Rows
Actual rows yalnızca query gerçekten çalıştırıldığında ölçülebilir. Estimate ile karşılaştırma cardinality model kalitesini gösterir. Büyük farklar join ve memory grant sorunlarına işaret edebilir. Loop count ile birlikte okunmalıdır. Production'da execution side-effect ve yük göz önünde bulundurulmalıdır.
Index Scan / Seek
Seek dar key range'ine doğrudan erişimi ifade eder. Index scan index'in daha geniş bölümünü okur. Scan kötü olmak zorunda değildir, covering ve ordered scan oldukça verimli olabilir. PostgreSQL terminolojisinde index scan aynı şekilde SQL Server seek ayrımına sahip değildir. Engine-specific operator anlamı bilinmelidir.
Sequential / Table Scan
Sequential veya table scan geniş veri okumasını ifade eder. High selectivity query'de görülmesi missing index veya SARGability sorunu olabilir. Wide analytical query'de ise normaldir. Rows removed by filter benzeri değerler wasted work'ü gösterebilir. Query purpose bilinmeden scan eleştirilmemelidir.
Bitmap Scan
Bitmap scan önce index üzerinden matching row location bitmap'i oluşturur. Sonra heap page'lerini daha toplu sırayla okuyabilir. Birden fazla index bitmap AND veya OR ile combine edilebilir. Ordering korunmadığı için sort gerekebilir. Medium-selectivity query'lerde index seek ve full scan arasında iyi denge sağlayabilir.
Key Lookup
SQL Server'da nonclustered index query'nin bütün kolonlarını taşımıyorsa key lookup base row'a erişebilir. Birkaç row için ucuzdur. Yüz binlerce row için dominant maliyete dönüşebilir. INCLUDE ile covering index çözüm olabilir. Alternatif olarak query projection daraltılabilir.
EXPLAIN ANALYZE Ne Zaman Kullanılır?
EXPLAIN ANALYZE plan tahminlerini gerçek execution sonuçlarıyla karşılaştırmak istediğinizde kullanılır. PostgreSQL'de query gerçekten çalıştırılır ve actual row ile timing bilgileri plana eklenir. Bu durum SELECT için çoğu zaman güvenli olsa da ağır sorgu production kaynaklarını tüketebilir. DML ifadelerinde gerçek side effect oluşacağı için dikkat gerekir. Önce staging veya transaction rollback stratejisi tercih edilmelidir.
Tahmini ve Gerçek Satır Sayıları
Estimated ile actual rows arasındaki fark optimizer statistics kalitesini gösterir. On kat veya yüz kat sapma yanlış join veya index kararına yol açabilir. Correlated columns bağımsızlık varsayımını bozabilir. Histogram veya extended statistics gerekli olabilir. Index eklemeden önce estimate problemini düzeltmek daha doğru çözüm olabilir.
Gerçek Execution Time
Actual time operator bazında çalışma süresini gösterir. Ancak instrumentation kendi overhead'ini ekleyebilir. Cache-warm ve cache-cold çalıştırmalar farklı sonuç verir. Network transfer süresi plan ölçümüne tam dahil olmayabilir. Tek run yerine kontrollü tekrarlarla benchmark yapılmalıdır.
Buffer / I/O Bilgileri
PostgreSQL buffers bilgisi shared hit, read, dirtied ve written page sayılarını gösterir. Bu değerler latency'den daha stabil performans sinyali olabilir. İndeks sonrası logical reads büyük ölçüde düşmüşse gerçek resource kazancı vardır. Physical reads cache state'e daha duyarlıdır. WAL bilgisi DML tuning sırasında write amplification'ı anlamaya yardımcı olabilir.
Production'da Dikkat Edilmesi Gerekenler
ANALYZE query'yi gerçekten çalıştırır. Ağır SELECT CPU ve I/O saturation yaratabilir. DML gerçek değişiklik yapabilir, bu nedenle transaction içinde rollback yaklaşımı bile lock ve WAL üretimini tamamen ortadan kaldırmaz. Production replica veya sampled environment daha güvenli olabilir. Query plan capture için engine'in non-executing plan seçenekleri önce değerlendirilebilir.
Database Statistics İndeks Seçimini Nasıl Etkiler?
Optimizer index'in faydasını data distribution hakkında tuttuğu statistics üzerinden tahmin eder. Cardinality estimate yanlışsa doğru index mevcut olsa bile plan kötü olabilir. Histograms popular ve rare value farkını gösterir. Stale statistics zamanla eski distribution'ı temsil etmeye başlar. Maintenance plan index kadar statistics health'i de takip etmelidir.
Cardinality Estimate
Cardinality estimate her operator'dan kaç row çıkacağını tahmin eder. Bu sayı join order, join algorithm ve access path seçimini etkiler. Çok düşük estimate nested loop'u gereksiz büyütebilir. Çok yüksek estimate selective index'i gözden düşürebilir. Estimate quality query tuning'in temel göstergesidir.
Histograms
Histogram value distribution'ın belirli aralık ve frequency bilgilerini özetler. Skewed data'da average distinct assumption'dan daha doğru estimate sağlar. Popular status value ile rare value farklı cardinality üretebilir. Histogram bucket sayısı sınırlı olduğu için her value exact değildir. Statistics target veya sampling policy gerektiğinde ayarlanabilir.
Data Distribution
Data uniform değilse aynı query farklı parametrelerde çok farklı row sayısı döndürür. Tenant büyüklükleri buna tipik örnektir. Histogram ve extended statistics distribution'ı optimizer'a anlatmaya çalışır. Production growth yeni skew oluşturabilir. Plan monitoring distribution shift'i fark etmeye yardımcı olur.
Stale Statistics
Table hızla büyüdüğünde eski statistics row count ve frequency'leri yanlış temsil eder. Optimizer outdated estimate ile kötü plan seçebilir. Auto statistics çoğu durumda yardımcıdır. Bulk load sonrası manual analyze veya update gerekli olabilir. Tuning öncesi statistics freshness mutlaka kontrol edilmelidir.
ANALYZE / Statistics Update
PostgreSQL ANALYZE planner statistics'i günceller. SQL Server statistics update mekanizmaları benzer amacı taşır. MySQL de engine-specific statistics toplar. Büyük tablo sampling behavior'ı estimate kalitesini etkileyebilir. Maintenance gereksiz fullscan yükü yaratmadan yeterli accuracy sağlamalıdır.
Correlated Columns İçin Extended Statistics
Optimizer çoğu zaman kolon predicate'lerini bağımsız varsayabilir. Gerçekte city ve postal code veya tenant ve status güçlü biçimde correlated olabilir. Bu durumda single-column statistics combined row count'u yanlış tahmin eder. PostgreSQL extended statistics n-distinct, dependencies ve most-common combinations gibi ek bilgi sağlayabilir. Daha doğru estimate daha doğru index ve join planına dönüşebilir.
Bağımsızlık Varsayımı
İki predicate'in selectivity değerini basitçe çarpmak kolonların bağımsız olduğunu varsayar. Correlated data'da bu sonuç ciddi hata üretir. Örneğin ülke ile şehir bağımsız değildir. Optimizer combined frequency bilgisini bilmiyorsa satır sayısını çok düşük tahmin edebilir. Extended statistics bu boşluğu azaltır.
Şehir + Posta Kodu
Postal code belirli şehirlerle güçlü ilişkidedir. city=? AND postal_code=? predicate'lerinin bağımsız hesaplanması gerçek row count'tan sapabilir. Extended MCV veya dependency statistics daha doğru bilgi sağlayabilir. Index zaten doğru olsa bile yanlış cardinality join order'ı bozabilir. Bu nedenle index ve statistics ayrı ama ilişkili tuning araçlarıdır.
Tenant + Status
Büyük tenant'ın pending row oranı küçük tenant'lardan tamamen farklı olabilir. Global status histogram tenant-specific dağılımı açıklamaz. Composite index doğru olsa bile optimizer tenant parametresine göre yanlış plan seçebilir. Extended statistics correlation'ı görünür hale getirebilir. Multi-tenant workload'larda bu problem sık ölçülmelidir.
Yanlış Cardinality Estimate
Yanlış estimate memory allocation ve join method seçiminde zincirleme etki yaratır. Planner index lookup'ın yalnızca yüz kez çalışacağını düşünürken milyon kez çalıştırabilir. Query latency hızla artar. Plan üzerinde estimated ve actual karşılaştırması root cause'u gösterir. İndeks hint vermeden önce statistics modeli iyileştirilmelidir.
Daha Doğru Query Plan
Statistics düzeldikten sonra optimizer aynı index set'iyle daha iyi plan seçebilir. Hash join yerine nested loop veya tersine geçiş olabilir. Selective composite index daha doğru değerlendirilebilir. Plan regression riski azaltılır. Statistics object'leri de schema asset olarak version control'da yönetilebilir.
B-Tree Yerine BRIN Ne Zaman Kullanılmalı?
BRIN çok büyük tabloda index boyutunu minimum tutmak istediğiniz ve indexed kolon fiziksel row order ile güçlü korelasyon taşıdığı zaman değerlidir. Append-only timestamp tablosu bunun klasik örneğidir. BRIN her row için entry tutmak yerine block range özetleri saklar. Bu nedenle B-tree'den çok daha küçük olabilir. Karşılığında false positive page'ler okunur ve yüksek hassasiyetli point lookup için genellikle B-tree kadar güçlü değildir.
Çok Büyük Append-Only Tablolar
Event veya audit table sürekli sona yeni row ekler. Timestamp fiziksel insertion order ile doğal korelasyon gösterir. BRIN page range min ve max özetlerinden faydalanır. Milyarlarca row için B-tree footprint'ine göre çok küçük kalabilir. Random historical updates korelasyonu zamanla azaltabilir.
Timestamp ile Fiziksel Sıralama Korelasyonu
BRIN'in gücü query value ile page location arasındaki ilişkiden gelir. Zaman arttıkça row'lar da physical olarak ileri page'lere gidiyorsa dar time range az page aralığına denk gelir. Data random order'da load edilirse summary ranges genişleyebilir. Correlation metric ve query plan izlenmelidir. Periodic clustering veya partition strategy bazı workload'larda yardımcı olabilir.
Event ve Log Tabloları
Log table write-heavy olduğu için dev B-tree maintenance pahalı olabilir. Query'ler çoğunlukla son saat veya belirli tarih aralığını okur. BRIN küçük write footprint ile range pruning sağlar. Specific event ID lookup için ayrı B-tree gerekebilir. Bir tabloda farklı access pattern'ler farklı index türleriyle desteklenebilir.
BRIN Index Boyutu
BRIN block ranges için summary tuttuğu için row-per-entry B-tree modelinden çok daha küçüktür. pages_per_range granularity ile index size arasında denge kurar. Küçük range daha precise ama daha büyük index olabilir. Büyük range daha küçük index fakat daha fazla false positive page üretir. Workload benchmark optimum değeri bulmalıdır.
Daha Fazla False Positive Page Scan
BRIN summary query range ile kesişen block range'i candidate olarak işaretler. Range içinde matching olmayan page veya row'lar da okunabilir. Bu nedenle exact B-tree seek kadar selective değildir. Physical correlation kötüleştikçe false positive oranı artar. Buffers metriği gerçek scan amplification'ı gösterir.
BRIN vs B-Tree Karar Matrisi
Point lookup ve yüksek selective random access için B-tree güçlüdür. Dev append-only ve correlated range workload için BRIN storage açısından öne çıkar. Write rate, index size ve latency SLO birlikte değerlendirilmelidir. Bazı tablolar hem BRIN timestamp hem B-tree entity key taşıyabilir. Seçim birbirini dışlayan ideolojik karar değildir.
Time-Series Veriler İçin İndeksleme
Time-series workload genellikle zaman range'i ile entity veya device filter'ını birlikte kullanır. Composite key order query'nin önce hangi boyutu daralttığına göre seçilir. Latest-N sorgular timestamp order'dan güçlü biçimde faydalanabilir. Çok büyük history için partitioning retention yönetimini kolaylaştırır. BRIN ve B-tree aynı time-series sisteminde farklı query'leri destekleyebilir.
Timestamp
Timestamp range query'nin temel kolonudur. Standalone B-tree zaman aralığını sıralı scan ile destekler. Çok büyük append-only table'da BRIN daha küçük alternatif olabilir. Timestamp precision key width ve duplicate frequency'yi etkiler. Time zone storage semantics ayrıca doğru modellenmelidir.
(device_id, timestamp)
Belirli device için zaman aralığı sorgulanıyorsa bu composite order doğaldır. Device equality ile prefix sabitlenir. Timestamp range ardından hızlı taranır. Sadece global time range query'si aynı index'i verimli kullanmayabilir. Workload iki access pattern taşıyorsa ek zaman index'i gerekebilir.
Latest-N Queries
“Cihazın son 20 ölçümü” tipik time-series sorgusudur. Device equality ardından timestamp descending order desteklenebilir. LIMIT sayesinde engine çok az leaf entry okur. Covering index değer kolonu için base lookup'ı azaltabilir. Wide sensor payload'ı index'e eklemekten kaçınılmalıdır.
Descending Index
Descending key order bazı engine'lerde latest-first query için doğrudan destek sağlar. Bazı B-tree implementasyonları backward scan ile ascending index'i ters okuyabilir. Mixed sort direction composite index'te daha önemli hale gelir. Plan sort operator'ı olup olmadığını göstermelidir. DDL syntax engine-specific kontrol edilmelidir.
BRIN
Global time range ve append-only history için BRIN çok küçük footprint sağlar. Recent range physical tail'e yakın olduğu için yüksek correlation oluşur. Device-specific query için tek timestamp BRIN yeterli olmayabilir. Partition pruning ile birlikte daha da az page taranabilir. Summary maintenance insert pattern'e göre izlenmelidir.
Partitioning
Time partitioning month veya day gibi interval üzerinden büyük history'yi parçalara ayırır. Query time predicate içerdiğinde irrelevant partition'lar prune edilir. Her partition kendi local index'lerine sahip olabilir. Retention eski partition'ı drop ederek hızlı uygulanır. Çok fazla küçük partition planning overhead yaratabileceği için granularity dengelenmelidir.
Retention
Time-series storage sonsuza kadar büyümemelidir. Retention policy eski partition veya rows'u kaldırır. Index footprint de buna paralel küçülür. Row-by-row delete yerine partition drop büyük operasyon avantajı sağlar. Compliance archive requirement varsa hot database'den ayrı katman kullanılabilir.
JSON Verileri Nasıl İndekslenir?
JSON column esnek schema sağlar fakat her property'yi aynı yöntemle indekslemek doğru değildir. PostgreSQL JSONB GIN gibi inverted index'lerden faydalanabilir. Çok sık sorgulanan scalar property expression veya generated column B-tree ile daha verimli olabilir. Document'in tamamını indekslemek write ve storage maliyetini hızla büyütebilir. JSON access pattern'leri normal relational schema kadar dikkatli ölçülmelidir.
JSONB / JSON
PostgreSQL JSONB parsed binary representation ve indexing özellikleri açısından JSON text type'ından farklıdır. MySQL JSON kendi binary storage modeline sahiptir. Her engine JSON operator ve index capabilities bakımından farklıdır. Index strategy kullanılan expression ve containment query'ye göre seçilmelidir. JSON field database schema düşüncesini tamamen ortadan kaldırmaz.
GIN
GIN JSONB içinde key veya value membership ve containment aramalarında güçlü olabilir. Bir row birden fazla index term üretir. Bu nedenle index build ve write cost yükselebilir. Operator class seçimi desteklenen query ve index size'ı etkiler. Sadece birkaç property sorgulanıyorsa daha dar alternative daha ekonomik olabilir.
Generated Column
JSON property generated column'a çıkarılarak normal B-tree indexlenebilir. Query bu kolon üzerinden equality veya range yapar. Type açık hale gelir ve statistics daha anlamlı olabilir. Data duplication küçük ekstra storage yaratır. Schema-critical property'nin aslında relational column olması gerekip gerekmediği de düşünülmelidir.
Functional Index
Expression index JSON extraction sonucunu doğrudan indeksleyebilir. Ek generated column görünürlüğü gerektirmez. Query aynı extraction expression'ını kullanmalıdır. Cast ve type normalization doğru olmalıdır. Engine determinism kuralları dikkate alınmalıdır.
Belirli JSON Alanlarını İndekslemek
Production telemetry hangi JSON paths'in gerçekten filter veya sort içinde kullanıldığını göstermelidir. Yalnızca bu alanlar dar index alabilir. Nadir ad hoc analytics full scan veya separate search pipeline'a bırakılabilir. Index count kontrol altında tutulur. Schema evolution path rename durumunda migration gerektirir.
Tüm JSON'u Körlemesine İndekslememek
Büyük document içindeki her token'ı indexlemek storage'ı katlayabilir. Write latency ve WAL hacmi artar. Query'lerin yalnızca yüzde 5'i bu index'ten faydalanıyorsa ROI düşüktür. GIN gibi yapı doğru workload'da çok değerlidir fakat varsayılan çözüm değildir. Usage ve size periyodik olarak izlenmelidir.
Full-Text Search için B-Tree Neden Yeterli Değildir?
B-tree ordered prefix ve scalar comparison için uygundur. Metnin ortasında kelime aramak bu order yapısından doğrudan faydalanmaz. Leading wildcard query bütün key alanını tarayabilir. Full-text index document'i token'lara ayırarak kelime bazlı erişim sağlar. Arama requirement ranking, stemming ve typo tolerance içeriyorsa daha özel altyapı gerekir.
%keyword% Aramaları
LIKE '%keyword%' leading wildcard nedeniyle normal B-tree prefix seek kullanamaz. Büyük text table'da full scan oluşturabilir. Trigram index gibi engine-specific seçenekler substring search için kullanılabilir. Full-text semantics substring'den farklıdır. Kullanıcının gerçekten ne aradığı önce tanımlanmalıdır.
Full-Text Index
Full-text index metni token ve term yapısına dönüştürür. Query kelime occurrence üzerinden candidate document bulur. Language-specific stemming ve stopword kuralları uygulanabilir. Update maliyeti normal B-tree'den farklıdır. Search freshness requirement index maintenance modelini etkiler.
GIN
PostgreSQL full-text search tsvector verisini GIN ile indeksleyebilir. Her document birden fazla lexeme taşıdığı için inverted index yapısı uygundur. Query term'leri hızlı eşleşir. Ranking yine additional computation gerektirebilir. Write-heavy sistemde GIN pending behavior izlenmelidir.
Native Database Search
Database-native full-text küçük ve orta ürünlerde ayrı search cluster ihtiyacını ortadan kaldırabilir. Transactional data ile consistency daha kolaydır. Operational complexity düşer. Ancak advanced relevance, distributed scaling veya cross-index search sınırlı olabilir. Requirement büyüdükçe ayrı search system'e geçiş değerlendirilebilir.
Elasticsearch/OpenSearch Ne Zaman Gerekir?
Çok gelişmiş relevance tuning, typo tolerance, faceting ve distributed search ihtiyacı ayrı search engine'i anlamlı hale getirebilir. Bunun karşılığında data synchronization ve eventual consistency gibi yeni sorunlar gelir. Ana database authoritative source olarak kalabilir. Change data capture search index'i besleyebilir. Basit contains query için gereksiz ikinci sistem kurmamak gerekir.
Vector Index Nedir?
Vector index yüksek boyutlu embedding'ler arasında benzer kayıtları bulmak için kullanılır. Semantic search ve recommendation sistemlerinde yaygındır. Exact distance calculation bütün vector'ları taradığında veri büyüdükçe pahalı hale gelir. ANN index daha az candidate inceleyerek latency'yi düşürür. Karşılığında bazı yakın komşuları kaçırma ihtimali olduğu için recall ölçülmelidir.
Embedding Aramaları
Text, image veya başka nesneler numeric vector'a dönüştürülebilir. Query embedding database'deki vector'larla distance metric üzerinden karşılaştırılır. Cosine, inner product veya Euclidean distance farklı kullanım alanlarına sahiptir. Index metric ile uyumlu olmalıdır. Metadata filter ve tenant isolation ayrıca relational predicate gerektirir.
Approximate Nearest Neighbor
ANN bütün vector'ları exact karşılaştırmak yerine daha küçük candidate set bulur. Böylece yüksek veri hacminde latency düşer. Approximation recall kaybı yaratabilir. Search quality benchmark ground-truth exact result ile yapılmalıdır. Product acceptable recall eşiğini teknik ekipten önce tanımlamalıdır.
HNSW
HNSW çok katmanlı graph yapısı üzerinden nearest-neighbor arar. Query latency ve recall açısından güçlü sonuçlar verebilir. Buna karşılık index build süresi ve memory kullanımı yüksektir. Insert behavior ve persistence kullanılan implementation'a göre test edilmelidir. Tuning parameter'ları latency-recall dengesini etkiler.
IVFFlat
IVFFlat vector space'i list veya centroid kümelerine böler. Query belirli sayıda cluster'ı probe eder. Daha fazla probe recall'ı yükseltirken latency'yi artırır. Index training veya data distribution yapısı kaliteyi etkileyebilir. HNSW ile aynı memory ve build karakteristiğine sahip değildir.
Recall vs Latency
Vector index tuning'in temel trade-off'u hız ve sonuç kalitesidir. Çok agresif approximate search düşük latency verirken doğru neighbor'ları kaçırabilir. Exact benchmark recall@k hesabı için kullanılabilir. Query class veya tenant size'a göre farklı tuning gerekebilir. Sadece p95 latency optimize etmek ürün kalitesini bozabilir.
Memory Kullanımı
Graph tabanlı vector index büyük memory footprint oluşturabilir. Vector dimensions arttıkça raw data da büyür. Quantization veya disk-based ANN seçenekleri farklı trade-off sunabilir. Cache ve database buffer ihtiyaçları relational index'lerle yarışabilir. Capacity plan vector index'i ayrı object olarak ölçmelidir.
Klasik B-Tree ile Farkı
B-tree scalar total ordering üzerinden equality ve range search yapar. Yüksek boyutlu vector space tek lexicographic order ile nearest neighbor problemini çözemez. ANN graph veya partition yapıları farklı algoritmalar kullanır. B-tree yine metadata filter için vector index yanında kullanılabilir. Hybrid query iki access path'i birlikte optimize etmeyi gerektirir.
OLTP ve OLAP Sistemlerinde İndeks Stratejisi Nasıl Farklıdır?
OLTP küçük ve hızlı transaction'lara, OLAP ise geniş scan ve aggregation'a odaklanır. Bu nedenle aynı index portföyü iki workload için uygun değildir. OLTP dar B-tree ve selective lookup'tan faydalanır. OLAP columnstore, bitmap ve partition pruning gibi geniş tarama optimizasyonlarına daha fazla ihtiyaç duyabilir. Hybrid sistemlerde workload isolation ayrıca düşünülmelidir.
OLTP
OLTP sorguları çoğunlukla point lookup, küçük range ve kısa transaction şeklindedir. Write rate yüksek olabilir. Her ekstra index transaction maliyetini artırır. Dar ve yüksek-value index'ler tercih edilir. Latency p95 ve p99 önemli performans göstergeleridir.
Point Lookup
Primary key veya unique business key üzerinden tek row erişimi yaygındır. B-tree bu pattern için güçlüdür. Covering küçük lookup'larda base access'i azaltabilir. Çok geniş index gerekli değildir. Query path mümkün olduğunca birkaç page içinde kalmalıdır.
Yüksek Write Rate
OLTP sistemde sürekli order, payment veya event insert edilebilir. Fazla index her transaction'ın log ve page update maliyetini artırır. Hot page contention görülebilir. Index sayısı read benefit ile gerekçelendirilmelidir. Write benchmark gerçek concurrency ile yapılmalıdır.
Dar B-Tree İndeksleri
Dar key daha fazla entry'nin page'e sığmasını sağlar. Cache efficiency yükselir. Tree depth düşük kalabilir. DML daha az byte günceller. OLTP design bu nedenle yalnızca “cover everything” yaklaşımından kaçınır.
OLAP
OLAP büyük data setlerini tarayıp aggregation yapar. Query birkaç saniye veya dakika sürebilir ama throughput ve scan efficiency önemlidir. Columnar compression storage bandwidth'i azaltır. Partition pruning tarih range'lerini daraltır. Rowstore B-tree belirli selective dimension sorgularında yine faydalıdır.
Büyük Scan
Analitik query milyarlarca row'un belirli kolonlarını okuyabilir. Index lookup yerine sequential veya columnar scan daha uygundur. Parallel execution throughput'u artırabilir. Data skipping metadata scan alanını azaltır. Cache bütün dataset'i taşıyamayacağı için storage bandwidth kritik hale gelir.
Aggregation
SUM, COUNT ve GROUP BY büyük row seti üzerinde çalışır. Columnstore gerekli kolonları sıkıştırılmış biçimde okuyabilir. Pre-aggregation veya materialized view başka seçeneklerdir. B-tree her aggregation sorununu çözmez. Query workload ve refresh latency birlikte değerlendirilmelidir.
Bitmap / Columnstore
Düşük-cardinality dimension filtreleri bitmap yaklaşımıyla verimli birleşebilir. Columnstore row groups üzerinde metadata pruning yapabilir. SQL Server columnstore analitik query'lerde önemli avantaj sağlayabilir. Engine-specific compression ve segment elimination behavior ölçülmelidir. DML-heavy real-time analytics için hybrid design gerekebilir.
Aynı Kuralları İki Workload'a Uygulamamak
OLTP'de başarılı olan dar B-tree stratejisini data warehouse'a aynen taşımak geniş scan maliyetini çözmez. OLAP için kullanılan çok geniş analytical index de transaction table'ında write latency yaratabilir. Workload mümkünse ayrı storage veya replica üzerinde ayrılabilir. Index governance object'in workload sınıfını kaydetmelidir. Performance hedefleri query tipine göre farklı tanımlanmalıdır.
Partitioning ile Indexing Arasındaki İlişki
Partitioning ve indexing farklı problemlere çözüm üretir ancak büyük tablolarda birlikte güçlü çalışırlar. Partitioning tabloyu logical veya physical bölümlere ayırır. Index partition içindeki row'ları hızlı bulur. Query partition key predicate'i taşıyorsa pruning önce gereksiz bölümleri eleyebilir. Sonra yalnızca kalan partition index'leri taranır.
Partition Key
Partition key row'un hangi partition'a gideceğini belirler. Time-series için tarih sık seçimdir. Multi-tenant sistemde tenant key bazen kullanılabilir fakat tenant skew risklidir. Query'lerin partition key predicate'i taşıması pruning için önemlidir. Yanlış key bütün partition'ların taranmasına yol açabilir.
Partition Pruning
Optimizer query predicate üzerinden irrelevant partition'ları plan veya execution sırasında çıkarabilir. Böylece scan ve index lookup daha az data üzerinde çalışır. Pruning için predicate SARGable olmalıdır. Function veya type mismatch pruning'i engelleyebilir. Plan hangi partition'ların gerçekten okunduğunu göstermelidir.
Partition-Level Index
Her partition kendi index structure'ına sahip olabilir. Daha küçük tree maintenance ve cache locality avantajı sağlar. Yeni partition gerekli index set'iyle otomatik oluşturulmalıdır. Schema drift partition'lar arasında problem yaratabilir. Migration tooling bütün partition index'lerini doğrulamalıdır.
Local Index
Local index partition boundaries ile uyumlu parçalara ayrılır. Partition drop veya switch operasyonlarını kolaylaştırabilir. Her partition kendi index bölümünü taşır. Query pruning sonrası ilgili local index'i kullanır. Terminoloji ve özellik database engine'e göre farklı olabilir.
Global Index
Global index birden fazla partition üzerindeki key space'i tek yapıda kapsar. Cross-partition unique veya lookup ihtiyacında faydalı olabilir. Partition maintenance global index'i daha pahalı etkileyebilir. Her engine global index'i aynı biçimde desteklemez. Partition strategy engine capability'sine göre tasarlanmalıdır.
Büyük Tablolarda Partition + Index Birlikte Kullanımı
Partitioning indeks ihtiyacını ortadan kaldırmaz. Bir aylık partition içinde yine milyonlarca row bulunabilir. Composite local index query'yi partition içinde daraltır. Retention partition drop ile, query lookup index ile çözülür. İki mekanizma farklı ölçek sorunlarına birlikte cevap verir.
Partial Index Partitioning Yerine Kullanılmalı mı?
Partial index bazı hot subset sorgularını küçültür fakat gerçek partitioning'in veri yaşam döngüsü ve pruning avantajlarının tamamını sağlamaz. Çok sayıda partial index ile her tarih aralığını taklit etmek yönetim yükü yaratır. Partitioning ayrı physical/data-management boundary sağlar. Küçük bir active subset için partial index daha basit olabilir. Ölçek ve retention ihtiyacına göre iki teknik birlikte de kullanılabilir.
Çok Sayıda Partial Index Riski
Her ay veya her tenant için ayrı partial index oluşturmak metadata ve maintenance yükünü büyütür. Planner daha fazla candidate index değerlendirebilir. Deployment script karmaşık hale gelir. Index predicate drift riski oluşur. Gerçek partitioning daha doğal boundary sunabilir.
Optimizer Maliyeti
Çok fazla index optimizer'ın candidate plan alanını büyütebilir. Compile time artabilir. Benzer redundant index'ler yanlış plan seçim ihtimalini yükseltebilir. Statistics object sayısı da büyür. Index portföyü mümkün olduğunca küçük ve anlamlı tutulmalıdır.
Gerçek Partitioning
Partitioning row'ları partition key'e göre ayrı bölümlere yerleştirir. Retention ve bulk maintenance daha kolay hale gelir. Query pruning full partition'ları tamamen atlayabilir. Index her partition içinde ayrıca kullanılabilir. Bu özellik partial index'ten farklıdır.
Partition Pruning
Pruning query'nin irrelevant data bölümlerine hiç erişmemesini sağlar. Partial index yalnızca alternate access path sunar, table data hâlâ aynı logical bölümde bulunur. Time range query partition pruning ile büyük scan alanını azaltabilir. Predicate partition key ile uyumlu olmalıdır. Plan pruning davranışını açıkça göstermelidir.
Hangi Ölçekte Partitioning'e Geçilmeli?
Belirli satır sayısı herkese uyan eşik değildir. Retention operasyonu, maintenance window, partition pruning kazancı ve table growth hızı birlikte değerlendirilir. Tek table index maintenance kabul edilemez süreye ulaşıyorsa partitioning güçlü adaydır. Query'ler doğal partition key taşıyorsa fayda artar. Gereksiz erken partitioning ise schema ve operasyon yükü yaratabilir.
Sharded Veritabanlarında İndeksleme
Sharding veriyi birden fazla node veya shard arasında dağıttığı için index tasarımına routing boyutu ekler. En iyi shard-local index bile query hangi shard'a gideceğini bilmiyorsa scatter-gather maliyetini çözmez. Shard key query pattern ile uyumlu olmalıdır. Global secondary index cross-shard lookup sağlayabilir ancak write consistency maliyeti getirir. Sharding önce query routing, sonra local indexing problemidir.
Shard Key
Shard key row'un hangi shard'da saklanacağını belirler. Tenant ID sık kullanılan seçimdir. Query shard key'i taşıyorsa request tek shard'a yönlenebilir. Skewed key büyük tenant'ı tek shard'da aşırı büyütebilir. Hash veya compound sharding distribution sorununu azaltabilir.
Shard-Local Index
Her shard kendi local table index'lerini taşır. Index boyutu toplam dataset'in yalnızca shard parçasını kapsar. Query routing doğruysa lookup lokal ve hızlıdır. Schema migration bütün shard'larda aynı index version'ını korumalıdır. Monitoring shard bazında plan farklarını göstermelidir.
Global Secondary Index
Global secondary index shard key dışındaki lookup için tüm cluster'ı temsil eden ek mapping sağlar. Bu mapping ayrı distributed service veya database feature olabilir. Her write global index'i de güncel tutmak zorundadır. Consistency ve failure handling daha zor hale gelir. Yalnızca yüksek-value lookup pattern'leri için gerekçelendirilmelidir.
Scatter-Gather Query
Shard key olmayan query bütün shard'lara gönderilebilir. Her shard local index kullansa bile toplam network ve compute maliyeti büyür. Tail latency en yavaş shard'a bağlı kalabilir. Global index veya alternate data model gerekebilir. Analytics workload ayrı warehouse'a taşınabilir.
Cross-Shard Index Lookup
Cross-shard lookup önce global mapping'den target shard bulup sonra local row'a gidebilir. İki network hop latency ekler. Mapping stale olmamalıdır. Transaction move veya resharding sırasında consistency korunmalıdır. Cache frequent mapping lookup'ları hızlandırabilir.
Global Index Write Maliyeti
Local row write yanında global index update gerekir. Synchronous update latency'yi artırabilir. Asynchronous update stale-read ihtimali doğurur. Failure recovery duplicate veya missing mapping yaratmamalıdır. Global index ROI read requirement ile write overhead üzerinden hesaplanmalıdır.
Multi-Tenant Veritabanlarında İndeksleme
Multi-tenant sistemlerde query'lerin büyük bölümü tenant scope taşır. Bu nedenle tenant ID çoğu composite index tasarımının doğal parçasıdır. Ancak her query'de tenant leading key olmak zorunda değildir. Global admin veya background job farklı pattern kullanabilir. Tenant size skew optimizer estimates ve plan sensitivity üzerinde özel sorunlar yaratabilir.
Tenant ID'yi İndeks Tasarımına Dahil Etmek
WHERE tenant_id=? hemen her request'te varsa leading composite key güçlü adaydır. Tenant isolation query access alanını daraltır. Index aynı tenant içinde sonraki filter ve sort kolonlarını organize eder. Security authorization yine sadece index veya query filter'a bırakılmamalıdır. Database row-level security gibi mekanizmalar ayrı sorumluluktur.
(tenant_id, created_at)
Tenant activity listesi veya event history için doğal index'tir. Equality tenant prefix'i zaman range'ini daraltır. Latest-N query aynı index'ten faydalanabilir. Global recent events query'si farklı index isteyebilir. Workload iki pattern arasında denge kurmalıdır.
(tenant_id, status, created_at)
Tenant içindeki status-filtered queue veya order listesi için uygundur. Status düşük cardinality olsa da tenant scope içinde anlamlı olabilir. created_at ordering pagination ve Top-N query'yi destekler. Eğer yalnızca pending status aranıyorsa partial index daha küçük olabilir. Query frequency hangi alternatifi seçtiğinizi belirler.
Büyük Tenant Skew
Bir tenant toplam verinin yüzde 40'ını oluştururken diğerleri küçük olabilir. Aynı prepared query küçük tenant için index seek, dev tenant için geniş scan gerektirebilir. Tek cached plan her ikisi için iyi olmayabilir. Histograms ve parameter-sensitive planning izlenmelidir. Large tenant ayrı shard veya partition adayı olabilir.
Tenant Bazlı Query Pattern
Enterprise tenant bazı report'ları kullanırken küçük tenant kullanmayabilir. Global workload average bu farkı gizler. Query statistics tenant segmentiyle ilişkilendirilebilir fakat privacy-safe aggregation kullanılmalıdır. Special index yalnızca tek büyük tenant için gerekiyorsa partial veya partition stratejisi düşünülebilir. Tenant-specific physical design operational complexity yaratır.
Pagination İçin Doğru İndeks Tasarımı
Pagination büyük tabloda performans farkının çok belirgin olduğu alanlardan biridir. OFFSET derinleştikçe database önceki satırları bulup atmak zorunda kalabilir. Keyset pagination son görülen stable sort key üzerinden devam eder. Composite (created_at,id) hem sıralama hem deterministic cursor sağlar. API pagination contract index order ile birlikte tasarlanmalıdır.
OFFSET/LIMIT
LIMIT 50 OFFSET 500000 database'in ilk yarım milyon row'u işleyip atmasını gerektirebilir. Index order sort'u çözse bile skip maliyeti devam eder. Küçük page numaralarında kullanım basittir. Admin ekranında random page jump gerekiyorsa kabul edilebilir. Infinite scroll veya API feed için keyset genellikle daha ölçeklenebilir.
Deep Pagination Problemi
Page number büyüdükçe query latency artabilir. Concurrent insert veya delete sayfa içeriğinin kaymasına da yol açar. Offset aynı logical row'un tekrar veya eksik görünmesine neden olabilir. Index bu semantik problemi çözmez. Cursor model daha stabil continuation sağlar.
Keyset / Cursor Pagination
Cursor son görülen sort values'ı taşır. Sonraki query WHERE (created_at,id) < (?,?) benzeri boundary kullanır. B-tree doğrudan boundary'den devam edebilir. Büyük offset taraması yapılmaz. Cursor opaque ve validated biçimde API'ye sunulabilir.
(created_at, id) Composite Index
Timestamp tek başına unique olmayabilir. ID tie-breaker stable total ordering sağlar. Composite index cursor predicate ve order ile aynı sırayı taşımalıdır. DESC direction engine behavior'a göre tanımlanabilir. Projection covering yapılacaksa yalnızca dar kolonlar eklenmelidir.
Stable Ordering
Pagination sırası deterministic değilse aynı row farklı sayfalara kayabilir. Unique tie-breaker order'a eklenmelidir. Sort key update edilirse item'ın feed içindeki yeri değişebilir. Immutable creation timestamp bu nedenle sık kullanılır. Product semantics update-time sıralama gerektiriyorsa cursor behavior ayrıca ele alınmalıdır.
ORDER BY için İndeks Nasıl Tasarlanır?
İndeks sort işlemini önleyebildiğinde özellikle büyük result set veya Top-N query'lerde büyük kazanç sağlayabilir. Filter predicate ile sort order aynı composite key içinde düşünülmelidir. Equality predicate leading kolonları sabitledikten sonra order kolonları doğal sırayı sağlayabilir. Direction ve null ordering engine'e göre önemlidir. Plan üzerindeki explicit sort maliyeti tuning öncesi ve sonrası karşılaştırılmalıdır.
Sort Operasyonunu Önlemek
Sort memory tüketir ve büyük result set'te disk spill oluşturabilir. Index zaten istenen order'da row'ları sağlıyorsa bu adım atlanabilir. Query çok az row döndürüyorsa sort zaten ucuz olabilir. Index yalnızca sort için oluşturulurken write maliyeti düşünülmelidir. High-frequency Top-N query daha güçlü adaydır.
ASC ve DESC
B-tree çoğu engine'de forward veya backward scan ile tek yön index'ten iki order sağlayabilir. Composite mixed-direction durumunda explicit direction daha önemli olabilir. SQL syntax engine-specific desteklenir. Query order ve index definition exact plan üzerinden kontrol edilmelidir. Sadece DDL'de DESC görmek performance garantisi değildir.
Mixed Sort Directions
ORDER BY a ASC, b DESC tek-direction scan'den farklıdır. Index key direction kombinasyonu query ile uyumlu olmalıdır. Bazı engine'ler mixed order index'i doğrudan destekler. Uygun değilse sort operator kalır. Workload gerçekten bu order'ı sık kullanıyorsa özel index gerekçelendirilebilir.
Filter + Sort Composite Index
WHERE tenant_id=? AND status=? ORDER BY created_at DESC ortak pattern'dir. Composite (tenant_id,status,created_at) filter ve sort'u birlikte çözebilir. Low-cardinality status burada equality prefix rolü oynar. LIMIT varsa sadece ilk birkaç entry okunur. Bu index ayrı tenant ve created_at index'lerinden daha değerli olabilir.
LIMIT ile Top-N Query
Limit planner'ın bütün result set'i üretmek zorunda olmadığını gösterir. Ordered index ilk N row'dan sonra scan'i durdurabilir. Dashboard latest items sorguları bu nedenle çok hızlı hale gelir. Covering küçük payload ekstra lookup'ı azaltır. Top-N pattern index tasarımında özellikle yüksek ROI taşır.
JOIN Performansı için İndeksleme
Join performansı yalnızca foreign key varlığıyla çözülmez. Join algorithm hangi table'ın outer ve inner olduğunu, kaç lookup yapılacağını belirler. Nested loop inner side'da uygun index yoksa büyük maliyet yaratabilir. Primary ve foreign key kolonları query pattern'e göre indekslenmelidir. Bazı database engine'ler foreign key constraint için supporting index'i otomatik oluştururken bazıları oluşturmaz.
Primary Key
Primary key genellikle unique index ile desteklenir. Join parent row'a primary key üzerinden ulaşıyorsa lookup hızlıdır. Key width secondary structures üzerinde ek etki yaratabilir. Composite natural key büyükse surrogate key değerlendirilebilir. Business uniqueness ayrı unique constraint ile korunabilir.
Foreign Key
Referencing foreign key child lookup veya delete/update constraint kontrolünde index'ten faydalanabilir. PostgreSQL foreign key tanımlamak referencing kolon üzerinde otomatik index oluşturmaz. SQL Server da otomatik olarak her foreign key için index oluşturmaz. MySQL InnoDB foreign key constraint için uygun index gerektirir ve gerektiğinde oluşturabilir. Bu nedenle “FK zaten indexed” varsayımı engine bağımsız doğru değildir.
Join Columns
Join condition'daki kolonların data type ve collation uyumu önemlidir. Implicit conversion index kullanımını bozabilir. Composite join ve filter query'sinde join key tek başına yeterli olmayabilir. Inner table access pattern'e göre additional predicate key'e eklenebilir. Plan actual row count ile nested lookup sayısını göstermelidir.
Join Order
Optimizer hangi table'dan başlayacağını estimated cardinality'ye göre seçer. Highly selective filter önce uygulanırsa inner lookup sayısı azalır. Yanlış statistics büyük table'ın outer side'a gelmesine neden olabilir. Index yalnızca access path değil join order seçeneklerini de etkiler. Hint vermeden önce estimates düzeltilmelidir.
Nested Loop ve Index Lookup
Nested loop küçük outer result ve hızlı inner index lookup ile çok etkilidir. Outer milyon row olursa aynı lookup milyon kez çalışır. Bu durumda hash veya merge join daha iyi olabilir. Index tek başına nested loop'u her zaman doğru yapmaz. Estimated vs actual outer rows kritik sinyaldir.
Foreign Key Kolonu Her Zaman Otomatik İndekslenir mi?
Hayır, bu davranış veritabanı motoruna göre farklıdır. PostgreSQL constraint oluşturduğunuzda referencing foreign key için otomatik B-tree oluşturmaz. SQL Server da constraint nedeniyle otomatik index garantisi vermez. InnoDB foreign key enforcement için index requirement uygular ve uygun index yoksa oluşturabilir. Schema review her engine için gerçek catalog'u kontrol etmelidir.
Queue ve İş Kuyruğu Tabloları Nasıl İndekslenir?
Database-backed queue tablosunda worker genellikle pending kayıtları belirli sırayla seçer. Completed jobs zamanla tablonun büyük çoğunluğunu oluşturabilir. (status,created_at) veya pending subset partial index bu access pattern'i hızlandırır. Concurrency için row locking ve SKIP LOCKED benzeri özellikler kullanılabilir. Queue throughput index write ve status transition maliyetiyle birlikte ölçülmelidir.
status
Status queue item lifecycle'ını temsil eder. Pending, processing ve done gibi değerler düşük cardinality taşır. Standalone status index done kayıtlar çoğunluktaysa büyük ve zayıf olabilir. Worker yalnızca pending arıyorsa partial index daha uygun olabilir. Status update row'u index subset'inden çıkarıp başka state'e geçirir.
created_at
FIFO queue en eski pending item'ı önce işler. created_at ordering bu behavior'ı sağlar. Tek created_at index bütün status'ları karıştırır. Status equality ile composite olduğunda scan alanı daralır. Unique tie-breaker gerekiyorsa ID eklenebilir.
(status, created_at)
Worker query WHERE status='pending' ORDER BY created_at LIMIT N ise bu index doğal çözümdür. Low-cardinality status leading olsa da equality predicate onu sabitler. Timestamp order ekstra sort'u önler. Done row'lar index'i büyüttüğü için partial alternative değerlendirilebilir. Query frequency yüksekse küçük kazanç büyük throughput etkisi yaratır.
Partial Index
Yalnızca pending jobs indexlenirse active queue working set küçük kalır. Worker index leaf page'lerini cache'te kolay tutabilir. Job completed olduğunda entry index'ten çıkar. Historical done row'lar queue performance'ını etkilemez. PostgreSQL partial index bu pattern için çok uygundur.
SKIP LOCKED
Birden fazla worker aynı queue'dan item alırken locked row'ları beklemek throughput'u düşürebilir. Destekleyen engine'lerde skip-locked semantics başka worker'ın aldığı row'u geçmeye izin verir. Index oldest pending rows'u hızlı bulmalıdır. Transaction kısa tutulmalıdır. Crash recovery processing status ve lease design'ıyla ayrıca çözülmelidir.
Sadece Bekleyen İşleri İndekslemek
Queue history milyonlarca completed row'a ulaştığında full status index gereksizleşir. Pending subset küçükse filtered structure çok yüksek selectivity sağlar. Storage ve vacuum/maintenance yükü azalır. Worker query predicate exact uyumlu olmalıdır. Queue depth metric partial index size ile birlikte izlenebilir.
Soft Delete Kullanılan Tablolarda İndeksleme
Soft delete row'u fiziksel olarak kaldırmak yerine flag veya timestamp ile inactive hale getirir. Zamanla historical deleted data active set'ten çok daha büyük olabilir. Çoğu application query yalnızca active rows'u arar. Partial veya filtered index active subset'i küçük tutabilir. Ancak bütün query'lerin delete predicate'ini doğru uygulaması data correctness açısından index'ten daha önemlidir.
deleted_at
deleted_at IS NULL active row anlamına gelebilir. Timestamp aynı zamanda delete audit bilgisini taşır. Active partial index predicate için doğal seçimdir. Deleted history üzerinde ayrı analytics index gerekebilir. Null semantics application ORM tarafından tutarlı üretilmelidir.
is_deleted
Boolean flag daha basit model sunar. Düşük cardinality nedeniyle standalone index çoğu durumda zayıftır. WHERE is_deleted=false subset küçükse filtered index faydalı olabilir. Delete timestamp gereksinimi varsa iki alanın drift etmemesi gerekir. Tek source of truth tercih edilmelidir.
Partial / Filtered Index
Active row'lar için business key unique partial index oluşturmak mümkündür. Örneğin silinmiş username tekrar kullanılabiliyorsa uniqueness yalnızca active subset'e uygulanabilir. Performance ve constraint aynı structure ile çözülebilir. Engine feature support kontrol edilmelidir. Legal retention requirement soft delete strategy'den ayrıdır.
Aktif Verinin Azınlık Olması
Archive ağırlıklı table'da active subset yüzde birkaç olabilir. Full index historical entries nedeniyle büyür. Partial structure hot query'yi RAM içinde tutabilir. Active ratio yükseldiğinde avantaj azalır. Monitoring data lifecycle değişimini takip etmelidir.
Historical Data'nın Query Plan'a Etkisi
Table row count historical data nedeniyle çok büyür. Statistics active subset distribution'ını yeterli ayrıntıda göstermeyebilir. Filter statistics veya partial index planner'a daha iyi cardinality sinyali verebilir. Archive partitioning ek seçenek olabilir. History query'leri operational index portföyünü gereksiz büyütmemelidir.
Fazla İndeksleme (Over-Indexing) Nedir?
Over-indexing tablo üzerinde gerçek workload faydasından daha fazla index bulundurulmasıdır. Her WHERE kolonu için index eklemek bu sorunun tipik kaynağıdır. Duplicate veya redundant index'ler aynı page write'larını tekrarlar. Kullanılmayan index cache ve disk alanı tüketir. Büyük Veritabanlarında Doğru İndeksleme (Indexing) Yaklaşımları yalnızca yeni index eklemeyi değil gereksiz index'i düzenli kaldırmayı da kapsar.
Her Kolona Index Eklemek
Her kolon query predicate'inde geçmiyor olabilir. Geçse bile low selectivity nedeniyle index hiç kullanılmayabilir. Index sayısı arttıkça write amplification büyür. Optimizer daha fazla candidate değerlendirir. Index yalnızca ölçülen query benefit ile oluşturulmalıdır.
Duplicate Index
İki index aynı key order ve aynı properties'e sahipse duplicate olabilir. ORM migration veya farklı ekipler fark etmeden aynı structure'ı oluşturabilir. Unique ve nonunique farkı correctness açısından önemlidir. INCLUDE veya predicate farkları kontrol edilmelidir. Catalog audit duplicate candidate'ları otomatik bulabilir.
Redundant Index
(a) ve (a,b) bazı workload'larda ilk index'i redundant hale getirebilir. Ancak narrower (a) daha küçük olduğu için belirli query'de daha iyi cache behavior sağlayabilir. Unique constraint farklıysa kaldırılamaz. Sort direction veya included data farkı da önemlidir. Silme kararı yalnızca prefix karşılaştırmasıyla verilmemelidir.
Kullanılmayan Index
Usage statistics uzun süre hiç scan veya seek göstermeyen index'i aday olarak işaretler. Ancak aylık veya quarterly job monitoring window dışında kalabilir. Replica veya failover workload farklı olabilir. Constraint enforcement index usage metric'inde görünmeyebilir. Removal önce invisible veya staged test ile yapılabilir.
Index Boyutunun Tablo Boyutunu Geçmesi
Çok sayıda wide index toplamda base table'dan daha büyük olabilir. Bu durum otomatik olarak yanlış değildir ama güçlü review sinyalidir. Backup, cache ve replication maliyeti büyür. Her index'in desteklediği query listesi belgelenmelidir. Düşük-value structure kaldırılmalıdır.
Write Throughput Kaybı
INSERT bir row yazarken on beş index update ediyorsa transaction latency artar. Random keys page split oluşturabilir. WAL veya redo log hacmi yükselir. Replica lag büyüyebilir. Index cleanup write throughput'u ekstra donanım almadan iyileştirebilir.
Bir İndeks Yazma Performansını Nasıl Etkiler?
Her index data change sırasında consistency'yi korumak zorundadır. INSERT yeni entry ekler, DELETE entry'yi kaldırır veya engine lifecycle'a göre dead hale getirir, UPDATE ise indexed key değişirse iki iş yapabilir. Bu işlemler page modification ve transaction log üretir. Replica aynı değişiklikleri taşımak zorunda kalır. Bu nedenle read optimization'ın write system üzerindeki toplam maliyeti ölçülmelidir.
INSERT
Yeni row her applicable index'e eklenir. Sequential key locality sağlar, random key farklı page'lere write yapar. Unique index duplicate kontrolü ek iş gerektirir. GIN veya vector index B-tree'den farklı insert maliyeti taşıyabilir. Bulk load sırasında secondary index strategy ayrıca planlanabilir.
UPDATE
Indexed kolon değişmiyorsa bazı engine'lerde index maintenance sınırlı olabilir. Key veya included column değişirse leaf entry güncellenir. PostgreSQL HOT update gibi engine-specific optimizasyonlar index etkisine bağlıdır. Wide covering index sık update edilen kolonları taşıyorsa maliyet artar. Update-heavy column'lar index design review'da özel işaretlenmelidir.
DELETE
Delete index entry lifecycle'ını etkiler. MVCC engine immediate physical removal yerine dead version bırakabilir. Vacuum veya purge daha sonra cleanup yapar. Çok sayıda index cleanup yükünü büyütür. Soft delete ise physical delete yerine status update yaparak farklı maintenance pattern oluşturur.
Index Page Updates
Her key insert uygun leaf page'i değiştirir. Page full ise split gerekebilir. Dirty page daha sonra storage'a yazılır. Hot page concurrent latch pressure yaratabilir. Page-level metrics write bottleneck'i anlamada değerlidir.
WAL / Redo / Binlog
Index changes durability ve replication için loglanır. PostgreSQL WAL, InnoDB redo ve MySQL binlog farklı amaç ve katmanlarda rol oynar. Daha fazla index daha fazla write volume oluşturabilir. Log storage ve archive bandwidth etkilenir. Bulk index build ayrıca yüksek log hacmi yaratabilir.
Replication Bandwidth
Primary üzerindeki index DDL veya logged changes replica'lara aktarılır. Büyük index build replica storage ve apply performansını etkileyebilir. Engine physical veya logical replication modeline göre davranış farklıdır. Network bandwidth planlanmalıdır. Production change sırasında replication lag alarmı kurulmalıdır.
Write Amplification
Application tek logical row değiştirir ama storage birden fazla index page ve log record yazar. Bu fark write amplification'dır. Wide index ve random insert oranı etkiyi artırabilir. SSD endurance bile uzun vadede etkilenebilir. Index ROI calculation write bytes metriğini içermelidir.
İndeks Boyutu RAM'den Büyükse Ne Olur?
Index'in RAM'den büyük olması tek başına sistemin çalışamayacağı anlamına gelmez. Önemli olan aktif working set'in ne kadarının memory'de tutulabildiğidir. Query sadece küçük hot key aralığını kullanıyorsa dev index'in büyük bölümü hiç okunmayabilir. Random access bütün leaf area'ya dağılıyorsa cache miss artar. Bu durumda storage latency query performansının belirleyici parçası haline gelir.
Working Set
Working set belirli zaman penceresinde gerçekten kullanılan data ve index page'lerinin toplamıdır. Total database size'dan daha anlamlı cache metric'idir. Hot tenant veya recent time range küçük working set oluşturabilir. Random UUID lookup geniş index alanını sıcak tutmayı zorlaştırabilir. Monitoring page access distribution'ını anlamaya yardımcı olur.
Buffer Pool
Database buffer pool storage page'lerini memory'de cache eder. MySQL InnoDB buffer pool buna örnektir. PostgreSQL shared buffers ve OS cache birlikte rol oynar. SQL Server buffer pool kendi memory yönetimine sahiptir. Sizing engine-specific olmalıdır.
Cache Miss
Needed page memory'de değilse storage'dan okunur. Random cache miss latency'yi artırır. High concurrency storage queue depth'i büyütebilir. Working set RAM'e yaklaşınca hit rate yükselir. Index küçültme bazen donanım büyütmekten daha ekonomik çözümdür.
Random Disk I/O
Index lookup birbirinden uzak leaf ve heap page'lerine gidebilir. SSD bunu hızlı yapar fakat memory access'ten çok daha yavaştır. Covering index base random lookup'ı azaltabilir. Clustering locality yardımcı olur. Query batch pattern page reuse sağlayabilir.
Cache Churn
Büyük scan hot lookup page'lerini cache'ten çıkarabilir. Sonraki OLTP query storage okumaya başlar. Analytical workload isolation bu nedenle önemlidir. Over-indexing de cache'e daha fazla object sokar. Object-level hit metric churn source'u bulmaya yardım eder.
Hot Index Pages
Root ve upper internal pages neredeyse her lookup'ta kullanıldığı için sıcak kalır. Leaf page access workload distribution'a göre değişir. Sequential insert rightmost leaf'i hot hale getirebilir. Read hotspot belirli tenant key range'inde yoğunlaşabilir. Partition veya sharding contention'ı dağıtabilir.
Page Split Nedir?
Page split dolu bir B-tree page'e yeni key yerleştirmek için page'in iki veya daha fazla bölüme ayrılması sürecidir. Bu işlem ek write ve log üretir. Random insertion tree'nin birçok farklı yerinde split oluşturabilir. Sequential insert genellikle tree'nin edge tarafında daha predictable büyüme sağlar. Fill factor bazı engine'lerde future insert için boş alan bırakmak amacıyla kullanılabilir.
B-Tree Page Doluluğu
Page mümkün olduğunca dolu olduğunda read density yüksektir. Ancak ortalara sürekli insert gelen workload için hiç boşluk kalmaması split oranını artırabilir. Optimal density workload'a göre değişir. Read-heavy immutable index yüksek fill'den faydalanır. Write-heavy random key index biraz free space isteyebilir.
Random Inserts
Random key her insert'i tree'nin farklı leaf page'ine yönlendirebilir. Cache locality düşer. Dolmuş page'lerde split oluşur. UUIDv4 clustered key bu davranışın yaygın örneğidir. Modern SSD ve engine optimizasyonları etkileri azaltabilir fakat ölçüm yine gerekir.
Sequential Inserts
Monotonic key yeni entry'leri çoğunlukla rightmost leaf'e ekler. Page dolduğunda yeni page ayrılarak ilerlenir. Bu write locality açısından avantajlıdır. Çok yüksek concurrency aynı rightmost page üzerinde contention oluşturabilir. Sequence choice workload scale'e göre değerlendirilmelidir.
Fill Factor
Fill factor index build sırasında page'lerde ne kadar boşluk bırakılacağını belirleyen engine-specific ayardır. Daha düşük değer future insert için alan bırakabilir. Ancak index hemen daha büyük olur ve read cache density azalır. Her index'e otomatik düşük fill factor vermek doğru değildir. Page split metriği gerçek ihtiyaç göstermelidir.
Fragmentation ve Write Amplification
Page split logical order ile physical layout arasında parçalanma yaratabilir. Daha fazla page yazılır ve loglanır. Read-ahead bazı workload'larda etkilenebilir. SQL Server güncel bakım yaklaşımında fragmentation tek başına rebuild gerekçesi olarak görülmemelidir. Query impact ve page density birlikte değerlendirilmelidir.
Index Bloat ve Fragmentation Nedir?
Bloat ve fragmentation farklı database motorlarında aynı anlama gelmez. PostgreSQL MVCC nedeniyle dead tuples ve reusable olmayan space ile bloat yaşayabilir. SQL Server fragmentation logical page order ve page density kavramlarıyla izlenir. InnoDB page utilization ve free space başka araçlarla değerlendirilir. Engine-specific bakım terminolojilerini birbirine karıştırmamak gerekir.
PostgreSQL Bloat
PostgreSQL update ve delete eski row version'larını bir süre saklar. Vacuum bunları reusable hale getirir fakat relation file hemen küçülmeyebilir. Index de dead entries ve page utilization nedeniyle büyüyebilir. Bloat cache footprint'i artırır. Reindex veya table rewrite ancak ölçülen ihtiyaç olduğunda uygulanmalıdır.
SQL Server Fragmentation
SQL Server logical fragmentation leaf page sequence'in physical order ile ne kadar uyumlu olduğunu ölçebilir. Random I/O modern storage'da etkisini değiştirmiştir. Page density çoğu workload'da daha önemli resource sinyali olabilir. Reorganize veya rebuild kararı query pattern'e göre verilmelidir. Sadece yüzde threshold script'i körlemesine çalıştırmak önerilmez.
InnoDB Page Utilization
InnoDB B-tree page'leri insert ve delete davranışına göre farklı doluluk gösterebilir. Purge ve page merge mekanizmaları zaman içinde space'i yeniden kullanabilir. File size immediate küçülmeyebilir. Clustered primary key pattern utilization'ı etkiler. Table rebuild yalnızca gerçek space veya performance ihtiyacı varsa planlanmalıdır.
Engine-Specific Kavramların Ayrılması
PostgreSQL VACUUM ile SQL Server REORGANIZE aynı işi yapmaz. InnoDB optimize operation'ın locking ve rebuild davranışı farklıdır. Maintenance playbook engine'e özel olmalıdır. Tek “index fragmentation yüzde 30 oldu, rebuild et” kuralı platformlar arası taşınmamalıdır. Official documentation ve production metric birlikte kullanılmalıdır.
Bloat'ın Query ve Cache Etkisi
Büyük index aynı logical entry sayısı için daha fazla page okuyabilir. Buffer cache içinde daha fazla alan tüketir. Range scan daha çok block üzerinden geçer. Backup ve replica storage büyür. Bloat reduction sonrası logical read değişimi gerçek performance impact'i gösterir.
İndeks Bakımı Nasıl Yapılır?
İndeks bakımının amacı her gece bütün index'leri rebuild etmek değildir. Statistics, dead row cleanup, page density ve actual query impact izlenmelidir. PostgreSQL, SQL Server ve MySQL farklı maintenance mekanizmalarına sahiptir. Büyük operation maintenance window ve replication etkisiyle planlanmalıdır. Otomasyon metric-driven olmalı, sabit kuralları körlemesine uygulamamalıdır.
ANALYZE
ANALYZE planner için data statistics toplar. PostgreSQL autovacuum bunu çoğu durumda otomatik yapar. Bulk load veya büyük distribution shift sonrası manual analyze gerekebilir. Expression index yeni oluşturulduğunda statistics availability ayrıca önemlidir. Analyze index bloat'ı fiziksel olarak düzeltmez.
VACUUM
PostgreSQL VACUUM MVCC dead tuples'ın space'ini yeniden kullanılabilir hale getirir. Transaction ID wraparound korumasında da kritik rol oynar. Normal vacuum table file'ı her zaman küçültmez. Autovacuum threshold ve workload uygun ayarlanmalıdır. Long-running transaction cleanup'ı engelleyebilir.
REINDEX
PostgreSQL REINDEX index structure'ını yeniden oluşturur. Gerçek bloat veya corruption gibi durumlarda kullanılabilir. Büyük index build ciddi I/O ve storage gerektirebilir. Concurrent seçenek veya operasyon planı production availability için değerlendirilir. Routine schedule olmadan önce ölçülen gerekçe aranmalıdır.
Rebuild
SQL Server index rebuild index'i yeniden oluşturur ve statistics davranışını da etkileyebilir. Online seçenek desteklenen sürüm ve edition'da availability avantajı sağlar. Rebuild yüksek CPU, I/O ve log üretebilir. Page density veya actual query impact gerekçelendirilmelidir. Her fragmentation seviyesinde otomatik rebuild kaynak israfı olabilir.
Reorganize
SQL Server reorganize leaf-level pages üzerinde daha hafif online maintenance seçeneğidir. Rebuild kadar resource yoğun olmayabilir. Statistics'i rebuild ile aynı şekilde yenilemez. Uzun süre çalışabilir fakat interruptible özellik sunar. Güncel guidance workload etkisi ve page density üzerinden karar verilmesini önerir.
Maintenance Window
Büyük index operation normal traffic'i etkileyebilir. Düşük kullanım saati seçilmelidir. Ancak global product'ta gerçek “gece” olmayabilir. Online veya concurrent method yine kaynak tüketir. Capacity ve throttling planı maintenance window kadar önemlidir.
Otomatik Bakım Politikaları
Automation object size, update rate ve query impact metric'lerine göre çalışmalıdır. Küçük index'i sık rebuild etmek anlamsızdır. Statistics freshness ayrı policy olabilir. Replica lag veya disk free space threshold operation'ı durdurabilir. Her automated action audit log ve outcome metriği üretmelidir.
Büyük Tabloda İndeks Oluşturmak Production'ı Nasıl Etkiler?
Büyük index build yalnızca DDL statement değildir, ciddi bir production workload'dur. Table scan CPU ve disk bandwidth tüketir. Sort veya temporary structure ek disk isteyebilir. Transaction log büyür ve replica apply geride kalabilir. Build mode lock behavior'ı kullanıcı trafiğini doğrudan etkileyebilir.
CPU
Index build key extraction ve sorting için CPU kullanır. Parallel build operation çok sayıda core tüketebilir. Application query latency aynı anda yükselir. Maintenance resource group veya concurrency limit kullanılabilir. CPU headroom change planında önceden hesaplanmalıdır.
Disk I/O
Table tamamıyla okunabilir ve yeni index page'leri yazılır. Storage throughput iki yönlü baskı görür. Aynı disk üzerinde transaction workload latency yaşayabilir. Replica veya cloud volume burst limit'i dikkate alınmalıdır. I/O dashboard operation sırasında canlı izlenmelidir.
Locking
Offline build write veya daha geniş access'i bloke edebilir. Online/concurrent seçenekler lock süresini azaltır fakat tamamen locksuz değildir. Metadata lock veya kısa finalization lock yine bulunabilir. Long transaction build'in beklemesine neden olabilir. Lock timeout ve kill policy önceden belirlenmelidir.
WAL / Redo Üretimi
Index build durability için büyük log volume üretebilir. Engine ve operation mode miktarı etkiler. Log disk dolması production incident yaratabilir. Archive veya backup pipeline kapasitesi izlenmelidir. Change öncesi free space güvenlik payı bırakılmalıdır.
Replication Lag
Primary index build veya DDL change replica tarafında ağır apply yaratabilir. Read replica stale hale gelebilir. Failover readiness düşebilir. Replication lag threshold operation pause veya rollback kriteri olabilir. Global service read consistency requirement'ı change window'ı etkiler.
Geçici Disk Alanı
Sort ve build sırasında temporary files oluşabilir. Concurrent veya online operation ek structure tutabilir. Table size kadar veya daha fazla transient space gerekebilecek senaryolar engine dokümantasyonundan hesaplanmalıdır. Disk dolması build'i ve database'i etkileyebilir. Capacity check deployment gate olmalıdır.
Online ve Concurrent Index Creation
Online veya concurrent index build production yazma trafiğini tamamen durdurmadan index eklemeyi amaçlar. Ancak “online” ifadesi sıfır lock veya sıfır performans etkisi anlamına gelmez. PostgreSQL CREATE INDEX CONCURRENTLY ek scan ve wait aşamaları taşır. SQL Server online operations belirli sürüm ve edition kurallarına bağlıdır. MySQL InnoDB online DDL operasyon türüne göre concurrent DML desteği sağlar.
Blocking Index Build
Standart build bazı motorlarda uzun write lock tutabilir. Büyük table saatler sürebilir. Bu durum user transaction timeout'larına yol açar. Offline build daha hızlı veya daha az toplam work yapabilir. Maintenance window yeterliyse yine tercih edilebilir.
PostgreSQL CREATE INDEX CONCURRENTLY
CREATE INDEX CONCURRENTLY normal writes'ı engelleyen uzun table lock almadan index oluşturmayı amaçlar. Bunun karşılığında PostgreSQL birden fazla scan ve transaction wait aşaması gerçekleştirir. Operation daha uzun sürebilir ve failure sonrası invalid index bırakabilir. Transaction block içinde çalıştırılamaz. Büyük production table'da monitoring ve cleanup planı zorunludur.
SQL Server Online Index Operations
SQL Server ONLINE=ON desteklenen index operation'larında kullanıcıların table'a erişmeye devam etmesini sağlar. Operation sırasında kısa schema lock aşamaları yine olabilir. Temporary disk alanı ve CPU tüketimi devam eder. Feature availability edition ve operation türüne göre kontrol edilmelidir. Resumable online create seçenekleri bazı modern sürümlerde ek operasyon esnekliği sunar.
MySQL Online DDL
InnoDB birçok secondary index operation'ını in-place ve concurrent DML ile gerçekleştirebilir. Operation türüne göre table rebuild veya lock requirement değişir. Primary key değişiklikleri clustered storage nedeniyle daha pahalıdır. Explicit ALGORITHM ve LOCK seçenekleri beklenen behavior'ı doğrulamaya yardımcı olur. Production öncesi engine sürümünün exact capability tablosu kontrol edilmelidir.
Avantaj ve Operasyonel Riskler
Online build downtime riskini azaltır. Buna karşılık daha uzun çalışma, ekstra disk ve CPU maliyeti oluşabilir. Long-running transaction completion'ı geciktirebilir. Replica lag ve storage saturation yine mümkündür. Change plan stop criteria ve post-build validation içermelidir.
Kullanılmayan İndeks Güvenli Şekilde Nasıl Silinir?
Unused index silmek write performansı ve storage için önemli kazanım sağlayabilir. Ancak kısa monitoring window yanlış karar üretebilir. Aylık rapor veya failover workload index'i nadiren kullanıyor olabilir. Engine destekliyorsa invisible index ile optimizer etkisi önce test edilebilir. Plan regression görülmezse physical drop sonraki kontrollü adım olur.
Usage Statistics
Database catalog index scan veya seek count gibi kullanım metrikleri sunabilir. PostgreSQL pg_stat_user_indexes buna örnektir. SQL Server DMV'leri benzer sinyaller sağlar. Restart veya stats reset history'yi silebilir. Usage count sıfır olmak tek başına silme kararı değildir.
Uzun Monitoring Window
Window business cycle'ı kapsamalıdır. Aylık close veya quarterly report gibi query'ler kısa gözlemde görünmez. En az bir tam operasyon döngüsü tercih edilebilir. Seasonal traffic ayrıca düşünülmelidir. Index owner silme öncesi ilgili ekiplerle kontrol yapmalıdır.
Aylık/Çeyreklik Sorguları Unutmamak
Financial reporting düşük frekanslı ama business-critical olabilir. Index ay boyunca kullanılmasa bile ay sonunda saatler kazandırabilir. Query Store history veya scheduled job inventory bunu gösterir. Reporting replica üzerinde ayrı index set'i taşımak seçenek olabilir. OLTP primary üzerindeki write maliyetiyle rapor kazancı dengelenmelidir.
Invisible Index
MySQL invisible index optimizer tarafından normal query planlarında göz ardı edilebilir. Physical structure durduğu için hızlı geri dönüş mümkündür. Constraint ve engine-specific exception'lar kontrol edilmelidir. Observation period sırasında plan ve latency izlenir. Problem yoksa drop daha güvenli hale gelir.
Plan Değişikliklerini İzlemek
Index görünmez veya drop edildiğinde optimizer alternate plan seçer. Top query'lerin p95 latency'si karşılaştırılır. CPU ve logical reads artabilir. Plan regression alert otomatik kurulabilir. Sadece hedef query değil table'a erişen bütün workload izlenmelidir.
Sonra Fiziksel Olarak Silmek
Observation başarılıysa index physical olarak kaldırılabilir. Büyük index drop çoğu engine'de metadata ağırlıklı olsa da cleanup ve log davranışı farklı olabilir. Backup ve rollback strategy düşünülmelidir. Migration repository definition da güncellenmelidir. Index tekrar otomatik migration ile gelmemelidir.
Invisible Index Nedir?
Invisible index optimizer'ın normal plan selection sırasında kullanmadığı fakat fiziksel olarak varlığını sürdüren index'tir. MySQL bu özelliği index removal riskini azaltmak için sunar. Write maintenance devam ettiği için performans kazancının yalnızca read plan etkisi test edilir. Index gerektiğinde yeniden visible yapılabilir. Bu yaklaşım dev index'i silip yeniden saatlerce build etme riskini azaltır.
Optimizer'ın İndeksi Görmezden Gelmesi
Index invisible olduğunda optimizer onu normal candidate list'e almaz. Query alternate index veya full scan seçer. Plan regression daha index drop edilmeden gözlemlenir. Storage ve DML maintenance ise devam eder. Bu yüzden write benefit physical drop sonrası ayrıca ölçülür.
İndeksi Silmeden Etkisini Test Etmek
Büyük production index'in rebuild'i pahalı olabilir. Invisible state reversible safety step sağlar. Observation sırasında critical queries izlenir. Application error veya latency yükselirse index tekrar visible yapılabilir. Feature engine-specific olduğu için diğer database'lerde farklı hypothetical veya plan-control araçları gerekir.
Query Plan Regression
Index kaldırıldığında optimizer daha pahalı plan seçebilir. Bazı query'ler yalnızca nadir parameters altında etkilenebilir. Parameter set representative olmalıdır. Plan history Query Store veya APM ile karşılaştırılabilir. Regression threshold önceden belirlenmelidir.
Hızlı Geri Alma
Physical index hâlâ bulunduğu için visibility geri çevrilebilir. Bu operation yeniden full build gerektirmez. Incident response daha hızlıdır. Ancak exact metadata lock behavior engine sürümüne göre kontrol edilmelidir. Rollback procedure change ticket içinde yazılmalıdır.
Büyük Tablolarda Avantajı
Terabaytlık index'i drop ettikten sonra geri build etmek saatler sürebilir. Invisible test bu riski azaltır. Storage hemen kazanılmaz fakat confidence artar. Observation başarılı olunca final drop planlanır. Production-safe index cleanup için güçlü ara adımdır.
Redundant Index Nasıl Tespit Edilir?
Redundant index tespiti yalnızca index key listelerini karşılaştırmaktan daha fazlasını gerektirir. Prefix relation, uniqueness, included columns, predicates ve sort direction kontrol edilmelidir. Aynı görünen index farklı query'ye daha dar ve hızlı path sunabilir. Usage statistics gerçek workload faydasını gösterir. Silme öncesi invisible veya staging workload test edilmelidir.
(a) ve (a,b)
(a,b) index leading a query'sini destekleyebilir. Bu yüzden (a) redundant adaydır. Ancak narrower index daha küçük ve cache-friendly olabilir. (a) unique ise semantics farklıdır. Usage ve write cost birlikte değerlendirilmelidir.
(a,b) ve (a,b,c)
Uzun index kısa prefix query'leri genellikle destekleyebilir. Buna rağmen size farkı büyükse short index önemli performance sağlayabilir. c wide text ise long index leaf footprint büyüyebilir. Query plan'lar hangi index'i seçtiğini gösterir. Frequency ağırlıklı benchmark removal kararını doğrular.
Unique Constraint Farkı
Unique index yalnızca performance değil data correctness sağlar. Nonunique wider index aynı constraint'i yerine getirmez. Duplicate detection semantics korunmalıdır. Constraint ayrı unique definition'a taşınmadan index drop edilmemelidir. Schema metadata tuning script'inde hesaba katılmalıdır.
INCLUDE Columns
Aynı key'e sahip iki index farklı included projection taşıyabilir. Biri kritik query'yi covering yapıyor olabilir. Key listesi karşılaştırması bunu kaçırır. Include union yaparak iki index'i tek structure'da birleştirmek bazen mümkündür. Fakat yeni wide index write cost'u yeniden ölçülmelidir.
Sort Direction
Composite index direction bazı mixed-order query'lerde fark yaratır. Aynı kolonlar farklı ASC/DESC kombinasyonuyla redundant görünmeyebilir. Engine backward scan capability incelenmelidir. Plan sort operator'ı karşılaştırılır. DDL metadata tam equality yerine semantic coverage açısından değerlendirilmelidir.
Silmeden Önce Workload Testi
Candidate index önce staging workload replay veya invisible mode ile test edilmelidir. Top queries latency ve reads açısından karşılaştırılır. Rare scheduled job'lar ayrıca çalıştırılır. Write throughput physical drop sonrası yeniden ölçülür. Removal outcome index governance kaydına eklenir.
Index Hint Kullanılmalı mı?
Index hint optimizer'a belirli access path'i seçmesi için müdahale eder. Kısa vadede kötü planı düzeltebilir. Ancak root cause stale statistics veya data skew ise hint problemi gizler. Data distribution değiştiğinde zorlanan plan kötüleşebilir. Hint bu nedenle ölçülmüş ve belgelenmiş son çare olmalıdır.
FORCE INDEX
MySQL FORCE INDEX optimizer'ın belirli index seçeneklerini daha güçlü değerlendirmesini sağlar. Query bazında kontrol sunar. Yanlış kullanılırsa full scan'in daha ucuz olduğu durumda performance düşer. Index rename veya schema change query'yi etkileyebilir. Production telemetry hint sonrası sürekli izlenmelidir.
Optimizer Hint
Database motorları join, access path veya plan behavior için farklı hint syntax'leri sunabilir. Hint engine-specific ve version-sensitive olabilir. Migration portability azalır. Plan stability ihtiyacı gerçekten yüksekse kullanılabilir. Her hint neden var olduğu ve kaldırma koşuluyla belgelenmelidir.
Kötü Statistics Problemini Hint ile Gizlemek
Optimizer yanlış cardinality nedeniyle kötü index seçiyorsa önce statistics düzeltilmelidir. Hint yalnızca symptom'u bypass eder. Yeni data distribution'da forced plan daha da kötüleşebilir. Extended stats veya query rewrite daha kalıcı çözüm olabilir. Hint incident workaround olarak geçici tutulabilir.
Data Distribution Değişince Hint'in Bozulması
Bugün selective olan status yarın table'ın çoğunu oluşturabilir. Forced index lookup milyonlarca row'a çıkabilir. Cost-based optimizer normalde scan'e geçmek isterdi. Hint bu adaptasyonu engeller. Monitoring hinted query'leri ayrı inventory'de takip etmelidir.
Hint'i Son Çare Olarak Kullanmak
Statistics, schema, query rewrite ve index design seçenekleri önce denenmelidir. Optimizer bug veya stable special workload gibi durumlarda hint haklı olabilir. Performance baseline açık olmalıdır. Upgrade sırasında hint tekrar test edilir. Teknik borç olarak owner ve review date atanmalıdır.
İndeks Eklemek Başka Sorguları Yavaşlatabilir mi?
Evet, yeni index sadece hedef sorguyu etkilemez. Optimizer diğer query'ler için de bu index'i candidate olarak değerlendirebilir. Yeni plan daha kötü olabilir. Write operations bütün index'leri maintain ettiği için doğrudan yavaşlar. Cache içinde yeni structure hot data'yı dışarı itebilir.
Query Plan Değişimi
Schema change plan invalidation veya recompile tetikleyebilir. Optimizer yeni index'i görüp farklı join order seçebilir. Hedef query hızlanırken başka query regression yaşayabilir. Query Store veya plan history bunu gösterir. Deployment sonrası top SQL listesi karşılaştırılmalıdır.
Optimizer'ın Yeni Index'i Yanlış Seçmesi
Statistics imperfect olduğunda yeni index estimated cost'ta çekici görünebilir. Gerçekte çok fazla lookup yapabilir. Parameter skew yalnızca bazı values'ta problem çıkarır. Index hint vermek yerine statistics ve query shape incelenir. Gerekirse index kaldırılır veya yeniden tasarlanır.
Plan Regression
Regression aynı query'nin önceki plana göre daha fazla latency veya resource tüketmesidir. Index deployment bunu tetikleyebilir. Baseline plan hash ve runtime metric tutulmalıdır. Alert release sonrası change correlation sağlar. Rollback index'i invisible veya drop etmeyi içerebilir.
Write Amplification
Yeni index hedef SELECT dışındaki bütün relevant DML'i etkiler. High-volume insert table'da küçük SELECT kazancı büyük write kaybına dönüşebilir. WAL ve replica lag artar. CPU tree maintenance için kullanılır. Read/write benchmark aynı release planında olmalıdır.
Buffer Cache Displacement
Yeni index query'ler tarafından sık okunursa buffer cache'te page tutar. Bu page'ler başka hot table veya index page'lerini çıkarabilir. Sistem genelinde cache miss artabilir. Hedef query latency düşerken total database CPU ve I/O yükselebilir. Object-level cache metrics bu yan etkiyi bulmaya yardımcı olur.
Parameter Sensitivity ve Data Skew İndeks Seçimini Nasıl Etkiler?
Aynı SQL text farklı parameter value'larda tamamen farklı row sayıları döndürebilir. Optimizer tek cached plan kullanıyorsa bütün values için ideal olmayabilir. Çok yaygın value full scan, nadir value index seek isteyebilir. Histogram distribution farkını göstermeye yardımcı olur. Plan monitoring parameter-sensitive query'leri ayrı sınıfta ele almalıdır.
Aynı Query, Farklı Parametre
WHERE status=? query'sinde parameter sonucu plan ekonomisini değiştirir. Pending yüzde 0,1, completed yüzde 95 olabilir. Tek plan ikisine de uygulanırsa biri kötü çalışabilir. Engine custom/generic plan veya parameter-sensitive optimization özellikleri farklıdır. Representative values ile test yapılmalıdır.
Çok Yaygın Değer
Popular value table'ın büyük kısmını döndürür. Index lookup random access nedeniyle pahalı olabilir. Full scan daha iyi olabilir. Histogram optimizer'ın frequency'yi bilmesini sağlar. Hint rare-case planını common value'ya zorlamamalıdır.
Çok Nadir Değer
Rare value birkaç row döndürür. Selective index lookup idealdir. Common-value plan scan ise rare query gereksiz data okuyabilir. Partial index yalnızca rare state için çözüm sağlayabilir. Parameter-specific recompile başka engine-dependent seçenektir.
Tek Planın Her Parametre İçin İyi Olmaması
Plan cache compile overhead'i azaltır fakat skewed workload'da trade-off yaratır. SQL Server parameter-sensitive plan özellikleri belirli durumlarda birden fazla plan variant yönetebilir. PostgreSQL prepared statements custom ve generic plan arasında davranış gösterebilir. MySQL optimizer kendi parameter handling modeline sahiptir. Engine sürümü ve plan cache mekanizması bilinmelidir.
Histograms
Histogram popular ve rare values'ı optimizer'a anlatır. Statistics sample yetersizse tail distribution kaçabilir. Tenant plus status correlation tek-column histogram'da görünmez. Extended stats veya filtered statistics yardımcı olabilir. Histogram freshness sürekli growth olan tablolarda takip edilmelidir.
Plan Monitoring
Query ID bazında plan hash ve runtime metrics tutulabilir. Aynı query birden fazla plan kullanıyorsa latency dağılımı karşılaştırılır. Regression particular parameter veya tenant ile ilişkilendirilebilir. Sensitive values loglanırken PII ve security kuralları korunmalıdır. Monitoring çözümün kalıcı olup olmadığını gösterir.
Bir İndeksin Başarısı Nasıl Ölçülür?
İndeks başarı ölçümü sadece query'nin artık “index scan” göstermesi değildir. Latency, logical reads, CPU ve scanned rows öncesi-sonrası karşılaştırılmalıdır. p95 ve p99 tail behavior kullanıcı experience'ı için önemlidir. Write latency ve storage artışı aynı testte hesaba katılmalıdır. İyi index toplam sistem maliyetini düşürürken hedef SLO'yu karşılar.
Query Latency Öncesi/Sonrası
Aynı representative parameter set'iyle baseline alınır. Cache state kontrol edilir. Index sonrası median ve tail latency karşılaştırılır. Tek hızlı run karar için yeterli değildir. Production telemetry final doğrulamayı sağlar.
Logical Reads
Logical reads database engine'in cache veya storage üzerinden kaç page eriştiğini gösterir. Query latency external noise'dan etkilenirken logical read daha doğrudan work metric'idir. Index başarılıysa selective query'nin page count'u ciddi düşebilir. Covering index lookup sayısını azaltabilir. Read count başka query'lerde artıyorsa regression incelenir.
Physical Reads
Physical read memory'de olmayan page'in storage'dan gelmesini ifade eder. Cache-warm testte düşük olabilir. Restart sonrası veya büyük working set'te artar. Storage latency physical read cost'u belirler. Index fit-to-memory avantajı bu metrikte görülür.
Rows Scanned
Rows scanned veya examined query'nin ne kadar gereksiz data işlediğini gösterir. Returned rows ile oranı önemlidir. Index seek sonucunda scanned count ciddi düşebilir. Residual predicate hâlâ çok row filtreliyorsa composite order iyileştirilebilir. Engine metric terminology'si farklı olabilir.
CPU Time
Daha az page ve row işlemek CPU consumption'ı da azaltır. High-frequency query'de birkaç milisaniye CPU tasarrufu büyük toplam kazanç oluşturabilir. Index maintenance write CPU'sunu artırabilir. Total database CPU iki yönlü ölçülmelidir. Query başına ve saniye başına CPU ayrı takip edilebilir.
p95/p99
Average latency tail sorunlarını gizler. Cache miss veya skewed parameter p99'da görünür. Index değişikliği median'ı az etkileyip tail'i ciddi iyileştirebilir. Tersi de mümkündür. SLO değerlendirmesi percentile üzerinden yapılmalıdır.
Write Latency
INSERT ve UPDATE p95 değerleri index sonrası ölçülmelidir. Transaction batch throughput karşılaştırılır. Lock veya page contention artabilir. WAL/redo bytes yükselir. Read kazancı write regression'ını karşılayabiliyor mu business workload'a göre karar verilir.
Storage Artışı
Index size doğrudan disk cost'udur. Cloud database storage ve backup faturası etkilenebilir. Replica sayısı maliyeti çarpar. Cache footprint daha önemli indirect cost'tur. Index başına GB maliyeti ROI kaydına eklenebilir.
Index ROI Nasıl Hesaplanır?
Index ROI read performans kazancını write, storage ve maintenance maliyetiyle karşılaştırır. Sadece bir query'nin latency düşüşü yeterli değildir. Query'nin kaç kez çalıştığı toplam faydayı belirler. CPU ve I/O tasarrufu infrastructure cost'a dönüştürülebilir. Review periyodu sonunda index'in beklenen faydayı gerçekten üretip üretmediği yeniden değerlendirilir.
Kaç Query Hızlandı?
Bir composite index birden fazla query family'yi destekleyebilir. Query ID listesi index owner kaydında tutulabilir. Her sorgunun execution count'u faydayı ağırlıklandırır. Bir query hızlanırken diğerleri regression yaşıyorsa net etki hesaplanır. Portfolio yaklaşımı tek sorgu yaklaşımından daha doğrudur.
Ne Kadar CPU Tasarrufu Sağlandı?
Before-after total CPU per query ölçülür. Execution count ile çarpıldığında günlük CPU savings tahmin edilebilir. Database instance scale-down potansiyeli oluşabilir. Write CPU artışı bu tasarruftan düşülmelidir. Peak period CPU headroom ayrı değer taşır.
Ne Kadar I/O Azaldı?
Logical ve physical read delta ölçülür. Storage throughput veya IOPS saturation düşebilir. Replica read workload ayrıca fayda görebilir. Cache hit iyileşmesi secondary benefit sağlar. Büyük scan azaltımı infrastructure stability'yi artırır.
Ne Kadar Disk Kullanıldı?
Index size ve replica çarpanı toplam storage cost'u verir. Backup retention ek kopyalar oluşturur. Temporary build space sürekli maliyetten ayrıdır. Wide index birkaç yüz GB ise business gerekçesi güçlü olmalıdır. Storage growth rate gelecekteki maliyeti öngörür.
Write Maliyeti Ne Kadar Arttı?
Insert throughput ve update latency index öncesi-sonrası ölçülür. Log bytes per transaction değişebilir. Replica lag peak saatlerde artabilir. Batch import süresi uzayabilir. Bu maliyet read benefit hesabından düşülmelidir.
Maintenance Maliyeti
Index statistics, vacuum, rebuild veya backup sürelerini etkiler. Operasyon ekibi maintenance incident riskini taşır. Large index create/drop change window gerektirir. Tuning yalnızca runtime query metric değildir. İnsan ve operasyon zamanı da ROI içinde değerlendirilebilir.
İndeksler Nasıl İzlenmeli?
İndeks monitoring kullanım, boyut, cache ve write davranışını birlikte kapsamalıdır. Scan veya seek count kullanım sinyali verir. Index size ve cache hit footprint etkisini gösterir. Page split ve bloat maintenance ihtiyacına işaret edebilir. Trend verisi tek anlık snapshot'tan daha değerlidir.
Index Scan / Seek Count
Usage count hangi index'lerin read workload'da kullanıldığını gösterir. Count query importance'i tek başına anlatmaz. Tek kritik monthly query düşük count taşıyabilir. Restart sonrası counters sıfırlanabilir. Monitoring sistemi uzun dönem history tutmalıdır.
Index Size
Index byte veya page size capacity açısından takip edilir. Ani büyüme data distribution veya included column değişikliğini gösterebilir. Size table size ile oranlanabilir. Partition bazlı distribution ayrıca incelenebilir. Çok büyük unused index hızlı cleanup fırsatıdır.
Index Cache Hit
Cache hit index page'lerinin ne kadarının memory'den geldiğini gösterir. Düşük oran storage dependency anlamına gelebilir. Object çok nadir kullanılıyorsa düşük hit doğal olabilir. Hot critical index düşük hit taşıyorsa RAM veya footprint sorunu araştırılır. Engine-specific metric definitions farklıdır.
Write Count
Index üzerinde kaç insert, update veya delete maintenance operation oluştuğu takip edilebilir. Çok yüksek write ve düşük read usage kötü ROI sinyalidir. Queue state index'i yüksek write rağmen kritik read benefit sağlayabilir. Read/write ratio yorumlanmalıdır. DML cost CPU ve log bytes ile desteklenir.
Bloat / Fragmentation
Engine-specific health metric ayrı dashboard'da tutulmalıdır. PostgreSQL bloat estimate ve dead tuple davranışı, SQL Server page density ve fragmentation farklıdır. Threshold tek platformdan diğerine taşınmamalıdır. Query impact olmadan rebuild yapılmamalıdır. Maintenance outcome logical read değişimiyle doğrulanmalıdır.
Leaf/Page Splits
Split frequency random insert veya düşük page free space sorununa işaret edebilir. High split log volume ve fragmentation yaratabilir. Fill factor veya key strategy değerlendirilebilir. Sequential hotspot başka bottleneck oluşturabilir. Split metric workload context içinde yorumlanmalıdır.
Usage Trends
Bir index bugün yoğun kullanılırken feature deprecation sonrası anlamsız hale gelebilir. Trend usage düşüşünü gösterir. Seasonal query'ler pattern olarak ayrılır. New release sonrası index usage değişebilir. Governance review trend verisine dayanmalıdır.
Index Governance Nasıl Kurulur?
Index governance her index'in neden var olduğunu görünür hale getirir. Owner, hedef query, beklenen kazanç ve gerçek kazanç kayıt altına alınır. Storage ve write maliyeti değerlendirilir. Belirli tarihte yeniden review yapılır. Böylece schema yıllar içinde kimsenin silmeye cesaret edemediği index mezarlığına dönüşmez.
İndeksin Owner'ı
Her index ilgili feature veya platform ekibine bağlanabilir. Performance incident'ta sorumlu kişi bulunur. Owner feature deprecate olduğunda index'i de gözden geçirir. Shared index birden fazla query'ye hizmet ediyorsa platform owner atanabilir. Ownership documentation schema migration ile birlikte tutulmalıdır.
Hangi Query İçin Oluşturuldu?
Index creation ticket hedef query ID veya normalized SQL'i kaydetmelidir. Execution plan before-after attachment yararlı olur. Birden fazla query family listelenebilir. Gelecekte index usage count düşerse business purpose anlaşılır. “Performans için eklendi” gibi belirsiz açıklama yeterli değildir.
Beklenen Kazanç
Change öncesi ölçülebilir hedef tanımlanmalıdır. Örneğin p95 800 ms'den 150 ms altına veya logical reads yüzde 80 aşağı hedeflenebilir. Write regression limiti de belirlenir. Storage budget eklenir. Başarı criteria deployment sonrası otomatik değerlendirilebilir.
Gerçek Kazanç
Production metric baseline ile karşılaştırılır. Cache warm-up dönemi ayrı tutulabilir. Query traffic dağılımı değişmişse normalize edilir. Hedef karşılanmadıysa index yeniden tasarlanır veya kaldırılır. Bu kayıt sonraki tuning kararlarına veri sağlar.
Storage/Write Maliyeti
Index GB boyutu ve günlük growth kaydedilir. DML latency delta takip edilir. WAL veya redo artışı ölçülebilir. Replica lag etkisi not edilir. High-cost index daha sık review alabilir.
Review Tarihi
Index sonsuza kadar kalıcı kabul edilmemelidir. Altı ay veya bir yıl sonra usage tekrar kontrol edilebilir. Feature lifecycle daha kısa ise review ona göre planlanır. Automated reminder governance backlog oluşturur. Review sonucu retain, redesign veya remove olabilir.
Remove/Retain Kararı
Karar usage, performance ve cost verilerine dayanmalıdır. Constraint index'leri yalnızca read usage üzerinden değerlendirilmemelidir. Removal observation window ve rollback planı taşır. Retain edilen index'in gerekçesi güncellenir. Böylece aynı tartışma her bakım döneminde baştan yapılmaz.
İndeks Değişiklikleri CI/CD ile Yönetilebilir mi?
Evet, index definition schema migration olarak version control içinde yönetilebilir. Ancak büyük production index build normal column migration'dan daha fazla operasyon planı gerektirir. Staging performance test ve production explain review yapılmalıdır. Online build capability kullanılır. Monitoring ve rollback migration'ın tamamlayıcı parçalarıdır.
Migration Olarak Index Definition
DDL repository içinde source-controlled olmalıdır. Index name standardı purpose ve columns hakkında ipucu verebilir. Idempotent migration behavior deployment tooling'e göre tasarlanır. Büyük index otomatik transaction içinde yanlışlıkla build edilmemelidir. PostgreSQL concurrent create transaction block kısıtı gibi engine detayları dikkate alınmalıdır.
Staging Testi
Staging production'a yakın data volume olmadan build süresi hakkında yanıltıcı olabilir. Representative dataset kullanılır. Query plans before-after karşılaştırılır. DML benchmark yapılır. Disk temporary space ihtiyacı ölçülür.
Production Execution Plan
Index oluşmadan önce target query plan kaydedilir. Build sonrası planın gerçekten yeni index'i kullandığı kontrol edilir. Unrelated top query plan'ları da karşılaştırılır. Statistics generation tamamlanmış olmalıdır. Plan history change ticket'a bağlanabilir.
Online Build
Production traffic devam ediyorsa online veya concurrent option tercih edilebilir. Capability database version ve edition'a göre validation almalıdır. Long lock finalization riski izlenir. Resource throttling uygulanabilir. Deployment automation operation timeout'u gerçek build süresine uygun ayarlamalıdır.
Monitoring
Build sırasında CPU, I/O, disk, locks ve replication lag izlenir. Sonrasında target latency ve write throughput ölçülür. Error rate değişikliği takip edilir. Alert threshold change window boyunca daha hassas olabilir. Observability olmadan online DDL güvenli sayılmamalıdır.
Rollback / Index Removal
Performance kötüleşirse index invisible veya drop edilebilir. Drop'ın locking behavior'ı ayrıca bilinmelidir. Migration rollback script önceden hazırlanır. Dev index'i yeniden oluşturmak uzun sürebileceği için removal kararı kontrollü verilir. Rollback sonrası plan ve latency yeniden doğrulanır.
AI veya Otomatik Index Önerileri Körlemesine Uygulanmalı mı?
Hayır, automated advisor yalnızca aday üretmelidir. Sistem belirli query'nin read benefit'ini görürken write cost veya başka index'lerle redundancy'yi eksik değerlendirebilir. Cloud recommendation kısa monitoring window'a dayanabilir. AI-generated suggestion schema ve workload context'i yanlış yorumlayabilir. İnsan onayı execution plan, storage ve DML benchmark ile yapılmalıdır.
Missing Index Advisors
SQL Server gibi sistemler missing index önerileri üretebilir. Bu öneriler query optimizer'ın belirli plan sırasında gördüğü fırsatlardır. Birbirine çok benzeyen birçok candidate oluşabilir. Öneriler composite consolidation yapılmadan uygulanırsa over-indexing doğar. Read benefit skorunun yanında write cost incelenmelidir.
Cloud Recommendations
Managed database platformları workload telemetry üzerinden index önerisi sunabilir. Monitoring scope ve sampling period bilinmelidir. Recommendation seasonal query'yi kaçırabilir. Automatic create özelliği varsa rollback ve validation politikası gerekir. Enterprise governance insan review'u koruyabilir.
AI-Generated Index Suggestions
AI SQL ve schema üzerinden mantıklı candidate üretebilir. Ancak gerçek row distribution ve production concurrency bilgisi yoksa confidence sınırlıdır. Generated DDL doğrudan production'a uygulanmamalıdır. EXPLAIN, hypothetical index ve benchmark ile doğrulanmalıdır. Security açısından schema veya query data dış sisteme gönderiliyorsa veri politikası dikkate alınmalıdır.
Read Benefit
Advisor çoğunlukla target SELECT'in estimated cost azalmasına odaklanır. Query frequency ile çarpıldığında gerçek fayda daha anlamlıdır. Covering include önerileri index'i çok genişletebilir. Sadece estimated percent improvement güvenilir ROI değildir. Production actual metrics şarttır.
Write Cost
Her öneri table DML rate ile birlikte değerlendirilmelidir. Update-heavy column key veya include olarak ekleniyorsa maintenance artar. Bulk import süresi uzayabilir. Log ve replica bandwidth yükselir. Advisor bu maliyeti tam workload context olmadan doğru modelleyemeyebilir.
Redundancy Kontrolü
Yeni candidate mevcut index prefix'iyle büyük ölçüde örtüşebilir. Existing index küçük bir order değişikliğiyle iki query'yi de destekleyebilir. Duplicate öneriler consolidate edilmelidir. Unique constraint ve INCLUDE farkı korunur. Schema-wide index catalog analizi recommendation pipeline'a eklenmelidir.
İnsan Onayı
DBA veya performance engineer öneriyi query purpose ve workload bağlamında değerlendirir. Execution plan ve data distribution incelenir. Hypothetical veya staging test sonucu kaydedilir. Production rollout safety planı hazırlanır. Automation karar desteği verir, sorumluluğu ortadan kaldırmaz.
Açık Kaynak İndeksleme ve Performans Ekosistemi
Açık kaynak veritabanı ekosistemi query tuning için çok sayıda araç ve ortak bilgi birikimi sunar. PostgreSQL ve MySQL kendi native statistics ve explain sistemlerine sahiptir. Percona gibi topluluk projeleri monitoring ve operational tooling sağlar. Hypothetical index araçları physical build yapmadan plan etkisini tahmin etmeye yardım edebilir. Ancak tool çıktısı yine gerçek production benchmark ile doğrulanmalıdır.
PostgreSQL
PostgreSQL B-tree, hash, GiST, SP-GiST, GIN ve BRIN gibi farklı index access method'ları sunar. Partial ve expression index yetenekleri query-specific tasarım için güçlüdür. pg_stat_statements workload görünürlüğü sağlar. Extended statistics correlated predicate tahminlerini geliştirebilir. Güncel planner davranışı sürüm yükseltmelerinde yeniden test edilmelidir.
MySQL / MariaDB
MySQL InnoDB clustered primary key ve secondary index modeli index tasarımını belirgin biçimde etkiler. Composite index leading prefix behavior önemlidir. Invisible index removal testing için faydalıdır. Performance Schema workload telemetry sağlar. MariaDB ile MySQL feature set'leri ayrışabildiği için dokümantasyon ürün ve sürüme göre kontrol edilmelidir.
Percona
Percona ekosistemi MySQL ve PostgreSQL operasyonları için açık kaynak tooling ve dokümantasyon sunar. Query analysis ve monitoring ürünleri workload görünürlüğünü artırabilir. Tool çıktıları engine native metrics ile birlikte değerlendirilmelidir. Production access least privilege ile verilmelidir. Community tool version compatibility'si upgrade sürecinde test edilmelidir.
pg_stat_statements
pg_stat_statements PostgreSQL workload analysis'in temel araçlarından biridir. Query normalization aynı statement family'yi aggregate eder. Calls, total execution time ve block metrics tuning priority'si sağlar. Extension history reset ve configuration behavior bilinmelidir. High-value query listesi düzenli raporlanabilir.
Percona Monitoring and Management
PMM database metrics ve query analytics'i merkezi dashboard'da gösterebilir. Slow query ve system resource correlation tuning'i kolaylaştırır. Birden fazla instance trend'i karşılaştırılabilir. Monitoring server capacity ve retention ayrıca planlanmalıdır. Tool recommendation'ları yine insan review'undan geçmelidir.
Hypothetical Index Araçları
Hypothetical index gerçek structure build etmeden optimizer'a candidate metadata sunmayı amaçlar. Büyük table'da saatler süren yanlış index denemesini azaltabilir. PostgreSQL ekosisteminde HypoPG benzeri araçlar kullanılabilir. Estimated plan gerçek runtime ve write cost'u göstermez. Bu nedenle yalnızca erken filtreleme aracı olarak görülmelidir.
Açık Kaynak Query Profiling Araçları
Profiling araçları statement frequency, wait ve resource tüketimini analiz eder. Native explain çıktısını visualization ile daha okunur hale getiren projeler bulunur. Sensitive SQL text'in üçüncü taraf servise gönderilip gönderilmediği kontrol edilmelidir. Self-hosted seçenekler kurumsal security requirement'larına uyabilir. Tool choice veri kaynağının doğruluğundan daha önemli değildir.
Community-Driven Performance Tuning
Veritabanı toplulukları gerçek execution plan örnekleri üzerinden büyük bilgi birikimi üretir. Ancak başka sistemde çalışan index reçetesi kendi workload'unuza doğrudan uygulanmamalıdır. Engine version ve data distribution farkları sonuçları değiştirir. Öğrenme amacıyla open source issue ve benchmark'ları incelemek değerlidir. Topluluk çalışmaları ve teknik proje örnekleri için https://www.diyarbakiryazilim.com.tr/projects adresindeki içerikler de incelenebilir.
Büyük Veritabanlarında İndeksleme İçin Adım Adım Yol Haritası
Sağlam bir indeksleme süreci rastgele DDL üretmek yerine ölçüm, tasarım, benchmark ve production doğrulaması aşamalarından geçer. İlk adım gerçek workload'u toplamaktır. Sonraki adımlar query plan, selectivity ve uygun index türünü değerlendirir. Build production operasyonu olarak ayrıca planlanır. Son aşamada duplicate ve unused index cleanup ile portföy sürekli güncel tutulur.
1. Production Query Workload'unu Toplayın
Query Store, pg_stat_statements, Performance Schema veya APM verisi kullanılabilir. En az bir business cycle kapsanmalıdır. Query text yanında execution count ve resource metrics tutulur. Background job'lar ayrı kategorize edilir. PII içeren parameter values monitoring sisteminde maskelenmelidir.
2. En Pahalı Sorguları Sıralayın
Total time, CPU, logical reads ve p99 ayrı listeler oluşturabilir. Tek metriğe göre önceliklendirme eksik kalır. Business-critical flow ağırlıklandırılır. N+1 query volume application fix adayı olarak ayrılır. Tuning backlog ölçülebilir hedef taşır.
3. EXPLAIN / Execution Plan Analizi Yapın
Current access path kaydedilir. Estimated row, actual row ve scan type incelenir. Sort, lookup ve join operator'ları analiz edilir. SARGability problemi bulunur. Index eklemeden önce query rewrite ihtimali değerlendirilir.
4. Selectivity ve Distribution'ı Ölçün
Distinct count ve actual predicate frequency hesaplanır. Popular ve rare values ayrılır. Tenant skew gibi correlation incelenir. Histogram freshness kontrol edilir. Candidate index gerçek parameter set üzerinde test edilir.
5. Uygun Index Türünü Seçin
Equality veya range için B-tree düşünülebilir. JSON için GIN veya extracted-field B-tree değerlendirilebilir. Time-series büyük history için BRIN aday olabilir. Analytics columnstore, vector search ANN structure isteyebilir. Engine feature support doğrulanır.
6. Composite Column Order'ı Query Pattern'e Göre Belirleyin
Equality, range ve order ihtiyaçları sıralanır. Leading prefix hangi query family'leri destekliyor kontrol edilir. Selectivity tek kural yapılmaz. Sort elimination ve join access birlikte değerlendirilir. Birkaç candidate hypothetical veya staging plan ile karşılaştırılır.
7. Covering/Partial Alternatiflerini Değerlendirin
Key lookup yüksekse narrow INCLUDE veya covering candidate test edilir. Hot subset küçükse partial index full structure'dan daha iyi olabilir. Wide payload eklemekten kaçınılır. Predicate query ile uyumlu tutulur. Storage size tahmin edilir.
8. Read Kazancı ile Write Maliyetini Benchmark Edin
SELECT latency ve reads ölçülür. INSERT, UPDATE ve DELETE throughput tekrar çalıştırılır. WAL veya redo delta kaydedilir. CPU ve cache footprint incelenir. Net ROI olmadan index production'a çıkmaz.
9. Büyük Tabloda Online/Concurrent Build Planlayın
Engine'in desteklediği build mode seçilir. Lock behavior staging'de test edilir. Long transaction kontrol edilir. Disk headroom hazırlanır. Change window ve abort criteria belirlenir.
10. Replication ve Disk Kapasitesini İzleyin
Build log volume replica lag yaratabilir. Temporary disk usage canlı takip edilir. Storage throughput application query'leriyle yarışabilir. Alert threshold önceden ayarlanır. Failover readiness operation boyunca değerlendirilir.
11. Production Sonrası Query Plan'ları Kontrol Edin
Target query yeni index'i gerçekten kullanıyor mu doğrulanır. Plan regression başka query'lerde aranır. p95 ve logical reads baseline ile karşılaştırılır. Statistics hazır değilse güncellenir. Beklenen kazanç yoksa rollback değerlendirilir.
12. Duplicate ve Unused Index'leri Bulun
Index catalog key prefix ve INCLUDE metadata'yla analiz edilir. Usage history uzun window üzerinden alınır. Constraint structures hariç tutulur. Similar index'ler consolidate candidate olur. Storage saving hesaplanır.
13. Güvenli Index Removal Süreci Uygulayın
Engine destekliyorsa invisible test yapılır. Rare jobs manual çalıştırılır. Performance monitoring window tamamlanır. Problem yoksa physical drop yapılır. Migration repository temizlenir.
14. Statistics ve Bloat Monitoring Kurun
Statistics freshness dashboard'a eklenir. PostgreSQL bloat ve autovacuum health izlenir. SQL Server page density ve fragmentation workload context'iyle takip edilir. Index size growth alarmı tanımlanır. Maintenance outcome ölçülür.
15. Index Setini Periyodik Olarak Yeniden Değerlendirin
Feature ve data dağılımı zaman içinde değişir. Yeni query'ler eski index'i redundant hale getirebilir. Tenant büyümesi plan sensitivity oluşturabilir. Quarterly veya release-based review yapılabilir. Index governance sürekli süreç olarak yaşatılır.
En Sık Yapılan İndeksleme Hataları
İndeksleme hatalarının çoğu iyi niyetli fakat ölçümsüz optimizasyondan doğar. Her predicate için yeni index eklemek kısa sürede over-indexing yaratır. Composite order ve selectivity basit sloganlarla yönetildiğinde yanlış planlar oluşabilir. Statistics ve write amplification görmezden gelindiğinde read kazancı production stability pahasına gelir. En iyi koruma, her değişikliği execution plan ve gerçek workload verisiyle doğrulamaktır.
Her Kolona Index Eklemek
Kolonun schema'da bulunması index gerekçesi değildir. Query frequency ve selectivity bilinmelidir. Her index DML ve storage maliyeti getirir. Low-use index cache footprint oluşturur. Index adayları workload telemetry'den çıkmalıdır.
WHERE İçinde Geçen Her Kolonu Tek Başına İndekslemek
Bir query üç kolonu birlikte kullanıyorsa üç single index ideal olmayabilir. Composite index filter ve sort'u tek path içinde çözebilir. Bitmap veya Index Merge her durumda en ucuz plan değildir. Column order query pattern'e göre seçilir. Ayrı index'ler başka query'lere hizmet ediyorsa korunabilir.
Production Query Pattern'lerini İncelemeden Index Tasarlamak
Development varsayımları gerçek workload'dan farklıdır. Sık query'ler APM veya statement statistics ile bulunmalıdır. Business-critical scheduled query'ler ayrıca eklenir. Data distribution production'a benzer olmalıdır. Index tasarımı önce plan sonra DDL yaklaşımını izlemelidir.
Selectivity'yi Tek Başına Karar Kriteri Yapmak
Selective kolon sort veya join behavior'ını bozabilir. Equality ve range sırası önemlidir. Query frequency başka prefix'i daha değerli hale getirebilir. Covering ve partial seçenekler equation'ı değiştirir. Gerçek plan son kararı verir.
Composite Index Kolon Sırasını Rastgele Belirlemek
Key order B-tree'nin logical sıralamasını tanımlar. Equality ve range predicate analizi yapılmalıdır. ORDER BY ihtiyacı düşünülmelidir. Birden fazla query family coverage'ı ölçülür. Rastgele order genellikle yalnızca bir kısmı işe yarayan geniş index üretir.
Leftmost Prefix Kuralını Bütün Database'lere Aynı Şekilde Uygulamak
Leading prefix temel B-tree kavramıdır fakat optimizer feature'ları engine'e göre farklıdır. PostgreSQL güncel sürümlerde skip scan uygulayabilir. MySQL de belirli skip-scan range access davranışları sunabilir. GIN veya BRIN multicolumn behavior B-tree'den farklıdır. Plan doğrulaması platform bazında yapılmalıdır.
Düşük Cardinality Kolonu Körlemesine İndekslemek
Boolean veya status kolon full-table index'te çok az satır eleyebilir. Nadir value partial index için çok iyi olabilir. Tenant ile composite yapılınca selectivity artabilir. Analytics bitmap strategy farklıdır. Cardinality tek başına evet veya hayır cevabı vermez.
Çok Geniş Covering Index Oluşturmak
Her projection column'u INCLUDE etmek index'i table kopyasına dönüştürebilir. Leaf page density düşer. Cache ve write cost artar. Önce query projection daraltılmalıdır. Yalnızca yüksek-value lookup'lar cover edilmelidir.
N+1 Problemini Sadece Index Ekleyerek Çözmeye Çalışmak
N+1 application'ın gereksiz çok query üretmesidir. Her query hızlı olsa bile toplam round-trip maliyeti yüksek kalır. Batch query veya eager loading daha büyük kazanç sağlar. Index sadece tek query latency'sini azaltır. APM trace root cause'u gösterir.
Index Kullanılmıyorsa Zorla Hint Vermek
Optimizer index'i kullanmıyorsa önce nedenini araştırmak gerekir. Full scan gerçekten daha ucuz olabilir. Statistics stale veya predicate non-SARGable olabilir. Hint data distribution değişiminde kötüleşir. Son çare ve belgeli exception olmalıdır.
Statistics Güncellememek
Data distribution değiştikçe optimizer eski dünya resmiyle plan üretir. Index seçimi yanlış olabilir. Bulk import sonrası problem daha belirginleşir. Auto statistics health monitoring gerekir. Manual update gerektiğinde kontrollü yapılır.
Kullanılmayan Index'leri Yıllarca Tutmak
Eski feature index'i schema'da unutulabilir. DML her gün gereksiz structure'ı günceller. Storage ve backup büyür. Usage telemetry review sürecine bağlanmalıdır. Safe removal playbook uygulanmalıdır.
Index Boyutunun RAM Etkisini Görmezden Gelmek
Dev index hot cache page'lerini dışarı itebilir. Query kendi index'iyle hızlanırken sistem genelinde I/O artabilir. Working set ölçülmelidir. Wide included columns dikkatle seçilmelidir. RAM sizing index portfolio ile birlikte yapılmalıdır.
Write Amplification'ı Ölçmemek
Read benchmark tek yönlü resim verir. Insert ve update latency yeniden test edilmelidir. Log volume ve replica lag ölçülür. High-write table'da index ROI kolayca negatife dönebilir. Production SLO iki yönü de kapsamalıdır.
Büyük Tabloda Blocking Index Build Yapmak
Offline build uzun write outage yaratabilir. Production table size büyüdükçe risk artar. Online veya concurrent option değerlendirilmelidir. Yine de resource consumption göz ardı edilmemelidir. Change plan locking test içermelidir.
Index Silmeden Önce Production Etkisini Test Etmemek
Usage count sıfır görünüyor diye dev index hemen silinmemelidir. Rare reporting query veya failover workload olabilir. Invisible index veya representative replay güvenlik sağlar. Monitoring window business cycle'ı kapsar. Rollback path hazır tutulur.
Partitioning Gereken Problemi Yüzlerce Index ile Çözmeye Çalışmak
Her tarih veya tenant subset için ayrı partial index uzun vadede yönetilemez olabilir. Data lifecycle partition boundary gerektiriyorsa gerçek partitioning daha uygun olabilir. Planner candidate sayısı ve maintenance yükü büyür. Retention row delete yerine partition drop ile kolaylaşabilir. Index ve partitioning farklı araçlardır.
Sık Sorulan Sorular
Büyük veritabanlarında indeksleme konusunda en sık sorulan sorular hangi kolona index eklenmesi gerektiğinden çok, mevcut index'in gerçekten değer üretip üretmediği etrafında toplanır. Composite order, covering, partial index ve execution plan konuları bu kararların merkezindedir. Her database motorunun optimizer ve storage davranışı farklı olduğu için tek cümlelik kurallar dikkatli kullanılmalıdır. Doğru yaklaşım üretim workload'unu ölçmek, aday tasarımı test etmek ve write maliyetini birlikte değerlendirmektir. Aşağıdaki yanıtlar temel karar noktalarını özetler.
Veritabanı indeksi nedir?
Veritabanı indeksi belirli key'lere göre satırlara daha az veri okuyarak erişmeyi sağlayan yardımcı veri yapısıdır. B-tree en yaygın örnektir. Index equality, range ve sıralama sorgularını hızlandırabilir. Bunun karşılığında disk alanı ve yazma maintenance maliyeti getirir. Bu nedenle index yalnızca ölçülen query ihtiyacı için oluşturulmalıdır.
Büyük tablolarda hangi kolonlar indekslenmelidir?
En sık kullanılan filter, join ve order kolonları adaydır. Ancak kolon adı tek başına yeterli değildir. Query frequency, selectivity ve data distribution ölçülmelidir. Composite veya partial index standalone index'ten daha iyi olabilir. Execution plan final doğrulamayı sağlar.
Composite index nedir?
Composite index birden fazla kolonu aynı ordered index key içinde tutar. Örneğin (tenant_id,status,created_at) üç-column composite index'tir. Leading key order hangi query'lerin efficient access alabileceğini etkiler. Filter ve sort birlikte desteklenebilir. Wide key write ve cache cost'u artırır.
Composite index kolon sırası nasıl belirlenir?
Equality predicate, range, ORDER BY ve query frequency birlikte incelenmelidir. En selective kolonun her zaman ilk olması gerekmez. Equality prefix ardından range veya sort key yaygın pattern'dir. Bir index'in birden fazla query family'yi desteklemesi değerlidir. Gerçek plan ve benchmark son kararı verir.
Leftmost prefix rule nedir?
Composite B-tree index'in leading kolon prefix'leri üzerinden en doğal biçimde kullanılmasını ifade eder. (a,b,c) index'i klasik olarak a, a+b ve a+b+c query'lerini destekler. Leading a olmadan behavior daha sınırlı olabilir. Modern optimizer skip scan gibi exception'lar uygulayabilir. Bu nedenle rule tasarım rehberidir, bütün engine'lerde mutlak davranış değildir.
Covering index nedir?
Covering index query'nin ihtiyaç duyduğu bütün kolonları index içinde sağlar. Base table lookup ihtiyacını azaltabilir. SQL Server ve PostgreSQL INCLUDE payload kolonları bu amaçla kullanılabilir. MySQL'de required columns secondary index entry'de bulunuyorsa covering davranışı oluşabilir. Index'i gereksiz genişletmemek gerekir.
Clustered ve nonclustered index arasındaki fark nedir?
Clustered index data row storage'ıyla doğrudan ilişkilidir. SQL Server ve InnoDB bu modeli farklı ayrıntılarla kullanır. Nonclustered veya secondary index ayrı search structure'dır ve row locator taşır. PostgreSQL heap storage nedeniyle farklı bir model kullanır. Bu yüzden terimler engine context'iyle açıklanmalıdır.
Cardinality ve selectivity arasındaki fark nedir?
Cardinality distinct value sayısını ifade eder. Selectivity belirli predicate'in kaç satırı ayırabildiğiyle ilgilidir. Yüksek cardinality çoğu equality sorgusunda iyi selectivity sağlayabilir. Skewed distribution bu ilişkiyi bozabilir. Histogram ve actual query frequency daha doğru değerlendirme sağlar.
Düşük cardinality kolon indexlenir mi?
Bazen evet. Status veya boolean kolon tek başına zayıf index olabilir. Nadir value sık sorgulanıyorsa partial index çok etkili hale gelebilir. Tenant veya time kolonuyla composite kullanım da değer sağlar. Mutlak kural yerine query pattern ölçülmelidir.
Partial index nedir?
Partial index tablonun yalnızca belirli predicate'e uyan satırlarını taşır. PostgreSQL bu özelliği doğrudan sunar. SQL Server benzer yaklaşımı filtered index olarak adlandırır. Hot subset küçükse index size ve write cost düşer. Query predicate index predicate'iyle uyumlu olmalıdır.
BRIN index ne zaman kullanılmalıdır?
BRIN çok büyük ve physical row order ile indexed value arasında korelasyon bulunan PostgreSQL tablolarında güçlüdür. Append-only timestamp event table klasik adaydır. Index çok küçük olabilir. Buna karşılık false positive block range'leri okuyabilir. Point lookup için genellikle B-tree daha uygundur.
Index neden kullanılmıyor?
Optimizer full scan'i daha ucuz hesaplamış olabilir. Düşük selectivity, stale statistics veya non-SARGable predicate sebep olabilir. Composite key order query ile uyuşmuyor olabilir. Type conversion index seek'i engelleyebilir. Hint vermeden önce plan ve statistics incelenmelidir.
EXPLAIN ANALYZE nasıl kullanılır?
EXPLAIN ANALYZE query'yi gerçekten çalıştırıp actual execution metrics gösterir. Estimated ve actual row farkları incelenir. Buffer ve I/O bilgileri access path maliyetini açıklar. Ağır query production'da kaynak tüketebilir. DML için side effect oluşacağı unutulmamalıdır.
Çok fazla index performansı düşürür mü?
Evet, özellikle write-heavy sistemlerde düşürebilir. Her DML ek index structure'larını günceller. Cache footprint ve storage artar. Optimizer candidate sayısı büyür. Kullanılmayan ve redundant index'ler düzenli temizlenmelidir.
Kullanılmayan index nasıl bulunur?
Database usage statistics ilk sinyali sağlar. Uzun monitoring window kullanılmalıdır. Scheduled ve seasonal query'ler ayrıca kontrol edilir. Constraint index'leri yalnızca scan count'a göre değerlendirilmemelidir. Invisible test veya staged removal daha güvenlidir.
Index silmek güvenli midir?
Doğru süreçle güvenli hale getirilebilir. Önce usage ve query dependency analiz edilir. Engine destekliyorsa invisible state denenir. Monitoring window'da regression yoksa drop yapılır. Rollback veya recreate planı önceden hazırlanmalıdır.
Partitioning ile indexing arasındaki fark nedir?
Partitioning table data'yı büyük logical bölümlere ayırır. Index partition içinde veya tüm table üzerinde row access'i hızlandırır. Partition pruning irrelevant bölümleri tamamen atlar. Index kalan bölüm içinde dar lookup sağlar. Büyük sistemlerde çoğu zaman birlikte kullanılırlar.
Milyarlarca satırlık tablo nasıl indekslenmelidir?
Önce workload ve data lifecycle ölçülmelidir. Time-correlated data için BRIN veya partitioning, point lookup için dar B-tree, hot subset için partial index düşünülebilir. Build online veya concurrent yöntemle planlanmalıdır. Index footprint RAM ve replica kapasitesiyle birlikte değerlendirilmelidir. Milyarlarca satırda her gereksiz index operasyon maliyetini büyük ölçüde artırır.
Büyük veritabanlarında doğru indeksleme (Indexing) stratejisi nasıl belirlenir?
Büyük veritabanlarında doğru indeksleme nasıl yapılır sorusunun ilk cevabı, tablo kolonlarına bakarak tahmin yürütmek değil production query workload'unu ölçmektir. En pahalı ve en sık sorgular belirlenir, execution plan üzerinden scanned rows, estimated rows ve actual rows karşılaştırılır. Ardından selectivity, data distribution, filter, join ve sort pattern'lerine göre candidate index tasarlanır. Read kazancı INSERT, UPDATE ve DELETE maliyetiyle birlikte benchmark edilir. Büyük Veritabanlarında Doğru İndeksleme (Indexing) Yaklaşımları bu ölçüm döngüsünü tek seferlik optimizasyon yerine sürekli bir performans süreci olarak ele almalıdır.
B-tree hash composite ve partial index türleri hangi sorgu senaryolarında kullanılmalıdır?
B-tree equality, range ve ordered scan için güçlü genel amaçlı seçimdir. Hash index yalnızca equality odaklı özel engine senaryolarında anlamlı olabilir. Composite index birden fazla filter veya sort kolonunun sürekli birlikte kullanıldığı query'lerde öne çıkar. Partial index ise tablonun küçük ve sık sorgulanan subset'ini indekslemek istediğinizde ciddi storage ve write avantajı sağlayabilir. Composite index covering index ve partial index ne zaman kullanılmalı sorusunun cevabı query family, data distribution ve engine capability birlikte incelenerek verilmelidir.
Fazla veya yanlış indeks kullanımı INSERT UPDATE DELETE performansını nasıl etkiler?
Her ek index INSERT sırasında yeni entry, DELETE sırasında cleanup ve bazı UPDATE işlemlerinde key değişikliği gerektirir. Bu işlemler daha fazla page modification ve transaction log üretir. Wide index'ler daha fazla byte yazılmasına, random key'ler daha fazla page churn oluşmasına neden olabilir. Replica bandwidth ve lag de etkilenebilir. Yüksek trafikli veritabanlarında index performansı nasıl optimize edilir sorusunun önemli bir bölümü gereksiz index'leri kaldırıp write amplification'ı kontrol etmektir.
Execution Plan ve slow query analizleriyle eksik ya da gereksiz indeksler nasıl tespit edilir?
Slow query log veya statement statistics ile toplam latency ve I/O açısından pahalı SQL'ler bulunur. Execution plan query'nin scan, seek, lookup, sort ve join behavior'ını gösterir. Estimated ve actual rows arasında büyük fark varsa önce statistics problemi çözülmelidir. Usage catalog uzun süredir hiç kullanılmayan index'leri removal adayı olarak gösterebilir. SQL query execution plan ile eksik ve gereksiz indeksler nasıl tespit edilir yaklaşımı, query plan bilgisini uzun dönem workload telemetry ile birleştirdiğinde daha güvenilir hale gelir.
Büyük veritabanlarında indeksleme ve sorgu optimizasyonu konusunda yakınımda danışmanlık veya eğitim nerede bulabilirim?
Veritabanı indeksleme ve DBA danışmanlığı yakınımda şeklinde araştırma yaparken yalnızca yeni index ekleyen değil execution plan, statistics, write amplification ve production rollout konularını birlikte değerlendiren bir yaklaşım tercih etmek faydalıdır. Diyarbakır Yazılım Topluluğu'nun yaklaşımı ve topluluk hakkında bilgi için https://www.diyarbakiryazilim.com.tr/about adresi incelenebilir. Node.js tarafında yüksek hacimli veri işleme konularıyla bağlantılı teknik içerik için https://www.diyarbakiryazilim.com.tr/posts/node-js-sistemlerinde-asenkron-veri-isleme-stratejileri adresinden devam edilebilir. Kurumsal veritabanı indeksleme ve sorgu performans optimizasyonu hizmeti değerlendirilirken mevcut workload'un ölçülmesi, benchmark ve güvenli production değişiklik süreci mutlaka kapsamda bulunmalıdır. Eğitim tarafında ise gerçek execution plan örnekleriyle çalışmak teorik index kurallarını production kararlarına dönüştürmenin en etkili yollarından biridir.
Sonuç: Büyük Veritabanlarında İndeksleme Nasıl Sürdürülebilir Hale Getirilir?
İyi indeksleme sistemi en fazla index'e sahip olan sistem değildir. En değerli sorguları minimum I/O ile çalıştırırken write throughput, cache, storage ve bakım maliyetini kontrol altında tutan sistemdir. Büyük Veritabanlarında Doğru İndeksleme (Indexing) Yaklaşımları query-driven tasarım, execution plan analizi, güncel statistics, güvenli online değişiklik ve düzenli index cleanup süreçlerini birlikte gerektirir. Composite veya partial index gibi teknikler ancak gerçek workload üzerinden doğrulandığında kalıcı değer üretir. Veritabanı, backend ve ölçeklenebilir yazılım mimarileri üzerine proje çalışmalarını incelemek için https://www.diyarbakiryazilim.com.tr/projects adresini ziyaret edebilirsiniz.
share: