Veritabanı indekslerinin sorgu sürelerini nasıl kısalttığını, hangi durumlarda yardımcı (ve zararlı) olduğunu ve gerçek uygulamalar için indeksleri tasarlama, test etme ve bakım adımlarını öğrenin.

Veritabanı indeksi, veritabanının satırları daha hızlı bulmasına yardımcı olan ayrı bir arama yapısıdır. Tablonuzun ikinci bir kopyası değildir. Bir kitabın dizin sayfalarını düşünün: dizini kullanarak doğru yere yakın atlayıp, ardından ihtiyacınız olan sayfayı (satırı) okuyorsunuz.
İndeks yoksa veritabanının genellikle yalnızca güvenli bir seçeneği vardır: hangi satırların sorgunuza uyduğunu kontrol etmek için birçok satırı okumak. Küçük tablolar için bu sorun olmaz. Tablo milyonlarca satıra ulaştıkça “daha çok satır kontrol etme” daha fazla disk okuması, daha fazla bellek baskısı ve daha fazla CPU işi demektir—aynı sorgu aniden yavaşlamaya başlar.
İndeksler, veritabanının cevaplamak için incelemek zorunda olduğu veri miktarını azaltır; örneğin “ID 123 olan siparişi bul” veya “bu e-postaya sahip kullanıcıları getir” gibi. Her şeyi taramak yerine veritabanı aramayı hızla daraltan sıkıştırılmış bir yapıya bakar.
Ama indeks her sorunu çözmez. Bazı sorgular yine de çok sayıda satır işlemek zorunda kalır (geniş raporlar, düşük seçicilik filtreleri, ağır agregasyonlar). Ayrıca indekslerin gerçek maliyetleri vardır: ek depolama ve daha yavaş yazmalar; çünkü insert ve update işlemleri indeksi de güncellemek zorundadır.
Şunları göreceksiniz:
Veritabanı bir sorgu çalıştırırken iki geniş seçeneğe sahiptir: tabloyu satır satır taramak ya da doğrudan eşleşen satırlara atlamak. Çoğu indeks kazancı gereksiz okumaları önlemekten gelir.
Bir tam tablo taraması (full table scan) tam olarak adının söylediği gibidir: veritabanı her satırı okur, WHERE koşuluna uyup uymadığına bakar ve sonra sonuçları döndürür. Küçük tablolar için kabul edilebilir ama tablo büyüdükçe daha yavaşlar—daha fazla satır, daha fazla iş demektir.
Bir indeks kullanıldığında veritabanı çoğu satırı okumaktan kaçınabilir. Bunun yerine öncelikle arama için oluşturulmuş sıkıştırılmış yapıya bakar, eşleşen satırların nerede olduğunu bulur ve sadece o satırları okur.
Bir kitabı düşünün. “Fotosentez” geçen her sayfayı istiyorsanız kitabı baştan sona okuyabilirsiniz (tam tarama). Ya da kitabın dizinini kullanıp listelenen sayfalara atlayıp sadece o bölümleri okuyabilirsiniz (indeks araması). İkinci yöntem çok daha hızlıdır çünkü neredeyse tüm sayfaları atlamış olursunuz.
Veritabanları özellikle veriler bellekte değilse okumaları beklemekle çok zaman harcar. Okunması gereken satır (ve sayfa) sayısını azaltmak tipik olarak şunları küçültür:
İndeksleme en çok veri büyük olduğunda ve sorgu kalıbı seçiciyse görünür (örneğin 10 milyon kayıttan 20 eşleşen satır çekmek gibi). Sorgunuz zaten tablonun çoğunu döndürüyor veya tablo rahatça belleğe sığıyorsa tam tarama aynı hızda ya da daha hızlı olabilir.
İndeksler, veritabanının her satırı kontrol etmek yerine istediğiniz değere yakın bir yere atlamasını sağlar çünkü değerleri düzenlerler.
SQL veritabanlarında en yaygın indeks yapısı B-treedir (çoğunlukla "B-tree" veya "B+tree" şeklinde yazılır). Kavramsal olarak:
Sıralı olduğu için B-tree hem eşitlik aramaları (WHERE email = ...) hem de aralık sorguları (WHERE created_at >= ... AND created_at < ...) için iyidir. Veritabanı doğru mahalli bulup sonra sırayla ileri tarama yapabilir.
İnsanlar B-tree aramalarının “logaritmik” olduğunu söyler. Pratikte bunun anlamı şudur: tablonuz binlerden milyona çıktığında, bir değeri bulmak için gereken adım sayısı yavaşça artar, orantılı olarak artmaz.
"Verinin iki katı, işi iki katına çıkarır" yerine, "çok daha fazla veri sadece birkaç ekstra navigasyon adımı ekler" gibi düşünün; çünkü veritabanı ağacın birkaç seviyesinden pointer takip eder.
Bazı motorlar ayrıca hash indeksleri sunar. Bunlar tam eşleşmeler için çok hızlı olabilir çünkü değer bir hash'e dönüştürülür ve doğrudan giriş bulunur.
Takas: hash indeksleri genellikle aralıklar veya sıralı taramalarda yardımcı olmaz ve kullanılabilirlik/ver davranışı veritabanına göre değişir.
PostgreSQL, MySQL/InnoDB, SQL Server ve diğerleri indeksleri farklı şekilde depolar ve kullanır (sayfa boyutu, clustering, included sütunlar, görünürlük kontrolleri). Ama temel fikir aynıdır: indeksler veritabanının eşleşen satırları bulmasını taramaya kıyasla çok daha az iş ile sağlayan sıkıştırılmış, gezinilebilir bir yapı oluşturur.
İndeksler genel olarak "SQL'i hızlandırır" demek yerine belirli erişim kalıplarını hızlandırır. İndeks, sorgunuzun filtreleme, join veya sıralama şekliyle eşleştiğinde veritabanı doğrudan ilgili satırlara atlayabilir.
1) WHERE filtreleri (özellikle seçici sütunlarda)
Sorgunuz büyük bir tabloyu küçük bir satır kümesine sık sık daraltıyorsa indeks genellikle ilk bakılacak yerdir. Klasik örnek bir kullanıcıyı tanımlayıcıyla aramaktır.
users.email üzerinde indeks yoksa veritabanı her satırı taramak zorunda kalabilir:
SELECT * FROM users WHERE email = '[email protected]';
email üzerinde indeks olduğunda eşleşen satırı(ları) hızla bulup durabilir.
2) JOIN anahtarları (foreign key ve referanslanan anahtarlar)
Join'ler küçük verimsizliklerin büyük maliyetlere dönüştüğü yerlerdir. orders.user_id ile users.id join'i yaparken join sütunlarını indekslemek (genellikle orders.user_id ve users.id gibi) veritabanının satırları tekrar tekrar taramadan eşleştirmesine yardımcı olur.
3) ORDER BY (sonuçları zaten sıralı istiyorsanız)
Sıralama, veritabanının çok sayıda satırı toplayıp sonra sıralaması gerektiğinde pahalıdır. Sıklıkla çalıştırdığınız:
SELECT * FROM orders WHERE user_id = 42 ORDER BY created_at DESC;
gibi sorgular için user_id ve sıralama sütunu ile uyumlu bir indeks motorun gerekli sırada okumasına izin vererek büyük bir kazanç sağlayabilir.
4) GROUP BY (gruplama indeksle hizalandığında)
Grouplama, veritabanı veriyi gruplanmış sırada okuyabildiğinde fayda sağlar. Kesin garanti yok, ama sıkça grup yapılan bir sütun filtreyle birlikte kullanılıyorsa veya indeks doğal olarak grupla uyumluysa motor daha az iş yapabilir.
B-tree indeksleri aralık koşullarında özellikle iyidir—tarihler, fiyatlar ve "between" sorguları gibi:
SELECT * FROM orders
WHERE created_at >= '2025-01-01' AND created_at < '2025-02-01';
Dashboardlar, raporlar ve "son etkinlik" ekranları için bu desen çok yaygındır ve aralık sütunu üzerinde bir indeks genelde hemen iyileşme getirir.
Tema basit: indeksler arama ve sıralama şeklinizle uyumlu olduğunda en çok yardımcı olur. Sorgularınız bu erişim kalıplarıyla eşleşirse veritabanı geniş taramalar yerine hedeflenmiş okumalar yapabilir.
İndeksler en fazla, veritabanının kaç satırı işlemesi gerektiğini keskin şekilde azaltıyorsa yardımcı olur. Bu özellik seçicilik olarak adlandırılır.
Seçicilik temelde: belirli bir değer kaç satırla eşleşiyor? Çok sayıda farklı değere sahip olan bir sütun yüksek seçiciliğe sahiptir, böylece her arama az sayıda satır döndürür.
email, user_id, order_number (genellikle benzersiz veya ona yakın)is_active, is_deleted, birkaç yaygın değeri olan statusYüksek seçicilikte indeks bir aramayı küçük bir satır kümesine daraltır. Düşük seçicilikte indeks tabloyun büyük bir kısmına işaret eder—veritabanının yine de çok okuyup filtrelemesi gerekir.
10 milyon satırlık bir tabloda is_deleted sütununun %98'i false ise is_deleted üzerinde bir indeks şu sorgu için çok da fayda sağlamaz:
SELECT * FROM orders WHERE is_deleted = false;
Eşleşen küme hâlâ tablonun neredeyse tamamıdır. İndeks kullanmak, motorun indeks girdileri ile tablo sayfaları arasında ekstra atlamalar yapması gerektiği için sıralı taramadan daha yavaş olabilir.
Sorgu planlayıcı maliyetleri tahmin eder. Eğer indeks işi yeterince azaltmayacaksa—örneğin çok fazla satır eşleniyorsa veya sorgu çoğu sütunu da gerektiriyorsa—planlayıcı tam tablo taramasını seçebilir.
Veri dağılımı sabit değildir. Bir status sütunu başlangıçta eşit dağılabilir, sonra bir değerin hakim olduğu bir duruma kayabilir. İstatistikler güncel değilse planlayıcı kötü tahminlerde bulunur ve eskiden fayda sağlayan bir indeks artık işe yaramayabilir.
Tek sütunlu indeksler iyi bir başlangıçtır, ama birçok gerçek sorgu bir sütuna göre filtreler ve diğerine göre sıralar veya filtreler. İşte bileşik (çok sütunlu) indeksler devreye girer: tek bir indeks sorgunun birden çok parçasına hizmet edebilir.
Çoğu veritabanı (özellikle B-tree ile) bileşik bir indeksi soldan başlayarak verimli kullanabilir. İndeksi önce A'ya, sonra B'ye göre sıralanmış gibi düşünün.
Bu demektir ki:
account_id ile filtreleyip sonra created_at ile sıralayan sorgular için harikadırcreated_at ile filtreleyen bir sorgu için yararlı değildir (çünkü created_at soldaki ilk sütun değildir)Sık görülen bir iş yükü “bu hesabın en son etkinliklerini göster” tipindedir. Bu sorgu kalıbı:
SELECT id, created_at, type
FROM events
WHERE account_id = ?
ORDER BY created_at DESC
LIMIT 50;
çoğunlukla şu indeksten büyük fayda görür:
CREATE INDEX events_account_created_at
ON events (account_id, created_at);
Veritabanı indeksi kullanarak bir hesabın bölümüne atlayıp zaman sırasıyla satırları okuyabilir; büyük bir küme tarayıp sıralamak zorunda kalmaz.
Kapsayan indeks, sorgunun ihtiyaç duyduğu tüm sütunları içerir; böylece veritabanı tablo satırlarını okumadan sadece indeksten sonuç döndürebilir (daha az okuma, daha az rastgele I/O).
Dikkat: ek sütunlar indeksin boyutunu büyütür ve masraflı hale getirir.
Geniş bileşik indeksler yazmaları yavaşlatır ve çok yer tutar. Sadece belirli, yüksek değerli sorgular için ekleyin ve EXPLAIN plan ile gerçek ölçümlerle doğrulamadan önce geniş indeksler oluşturmayın.
İndeksler sıklıkla "bedava hız" olarak tanımlanır, ama bedava değildir. İndeks yapıları, altta yatan tablo her değiştiğinde korunmalı ve gerçek kaynaklar tüketir.
Yeni bir satır INSERT ettiğinizde veritabanı sadece satırı yazmaz—aynı zamanda her indeks için de ilgili girdileri ekler. DELETE ve birçok UPDATE için de durum aynıdır.
Bu yüzden "daha fazla indeks" yazma ağırlıklı iş yüklerinde belirgin şekilde yavaşlama getirebilir. İndeksli bir sütunu değiştiren bir UPDATE özellikle pahalı olabilir: veritabanı eski indeks girdisini kaldırıp yenisini eklemek zorunda kalabilir (ve bazı motorlarda bu ekstra page split veya yeniden dengeleme tetikleyebilir). Eğer uygulamanız çok yazma yapıyorsa—örneğin sipariş olayları, sensör verisi, audit log'lar—her şeye indeks koymak veritabanını yavaş hissettirebilir.
Her indeks disk alanı kaplar. Büyük tablolarda indeksler tablo boyutuna yakın veya daha büyük olabilir, özellikle birden fazla örtüşen indeks varsa.
Bu aynı zamanda bellek kullanımını etkiler. Veritabanları önbelleğe çok güvenir; çalışma setiniz büyük indeksleri de içeriyorsa önbellek daha fazla sayfa tutmak zorunda kalır. Aksi halde daha fazla disk I/O ve daha az öngörülebilir performans görürsünüz.
İndeksleme, hangi işleri hızlandıracağını seçmektir. İş yükünüz okuma ağırlıklıysa daha fazla indeks değerli olabilir. Yazma ağırlıklıysa en önemli sorguları destekleyen indekslere öncelik verin ve kopyaları/örtüşmeleri önleyin. Faydalı bir kural: bir indeksi sadece ona fayda sağlayacak sorguyu adlandırabildiğinizde ekleyin—ve okuma kazancının yazma ve bakım maliyetini aşıp aşmadığını doğrulayın.
Bir indeks eklemek yardımcı olmalı diye görünebilir—ama bunu doğrulamalısınız. Bunu somut yapan iki araç sorgu planı (EXPLAIN) ve gerçek öncesi/sonrası ölçümlerdir.
Tam olarak ilgilendiğiniz sorguda EXPLAIN (veya EXPLAIN ANALYZE) çalıştırın.
EXPLAIN ANALYZE ile özellikle): Eğer plan 100 satır tahmin etti ama gerçekte 100.000 satır okuduysa optimizer yanlış tahminde bulunmuş demektir—genellikle istatistikler güncel değilse veya filtre beklenenden daha az seçiciyse.ORDER BY ile eşleşirse o sort kaybolabilir ve bu büyük bir kazançtır.Sorguyu aynı parametrelerle, temsilî veri hacminde benchmark edin ve hem gecikme hem de işlenen satır sayısını kaydedin.
Önbellekleme tuzağına dikkat: ilk çalışma daha yavaş olabilir çünkü veri henüz bellekte değildir; tekrar eden çalışmalarda indeks olmasa bile sonuçlar "hızlanmış" görünebilir. Kendinizi kandırmamak için birden çok çalışma karşılaştırın ve planın değişip değişmediğine (indeks kullanımı, daha az satır okunması) odaklanın, sadece ham zamana bakmayın.
Eğer EXPLAIN ANALYZE daha az satır okunduğunu ve daha az pahalı adım (ör. sort) gösteriyorsa indeksi kanıtlamış olursunuz—sadece ummak yerine görgül olarak doğrulamış olursunuz.
"Doğru" indeksi ekleyip yine de hızlanma görmemenizin nedeni sorgunun indeksi kullanmasını engelleyen yazım biçimleri olabilir. Bu sorunlar genellikle ince detaylardır; sorgu hâlâ doğru sonuç döndürür—sadece daha yavaş bir plan seçilir.
1) Önde joker karakter kullanımı
Aşağıdaki gibi yazdığınızda:
WHERE name LIKE '%term'
normal bir B-tree indeksi verimli şekilde kullanılamaz; çünkü sıralı düzende "%term" ifadesinin nerede başladığını bilmek mümkün değildir. Motor genellikle geniş bir taramaya geri döner.
Alternatifler:
WHERE name LIKE 'term%'.2) İndeksli sütunlarda fonksiyon kullanmak
Bu görünüşte zararsızdır:
WHERE LOWER(email) = '[email protected]'
Ama LOWER(email) ifadesi sütunu değiştirir, bu yüzden email üzerindeki indeks doğrudan kullanılamaz.
Alternatifler:
WHERE email = ... ile sorgulayın.LOWER(email) için ifade-tabancı (expression/function-based) bir indeks oluşturun (veritabanına bağlıdır).Dolaylı tip dönüşümleri: Farklı veri tiplerini karşılaştırmak bir tarafın implicit olarak dönüştürülmesine yol açabilir ve bu indeksin kullanılmasını engelleyebilir. Örnek: bir integer sütunu string literal ile karşılaştırmak.
Uygun olmayan collation/encoding: Karşılaştırma indeksi oluşturulduğu collation ile uyuşmuyorsa optimizer indeksi kullanmaktan kaçınabilir.
LIKE '%x')?LOWER(col), DATE(col), CAST(col)) ?EXPLAIN ile kontrol ettiniz mi?İndeksler "kur ve unut" değildir. Zamanla veri değişir, sorgu desenleri kayar ve fiziksel yapı bozulur. İyi seçilmiş bir indeks zamanla etkinliğini kaybedebilir ya da zararlı hale gelebilir eğer bakım yapılmazsa.
Çoğu veritabanı sorgu planını seçmek için istatistiklere (değer dağılımları, satır sayıları, data skew özetleri) güvenir.
İstatistikler eskidiğinde planlayıcının satır tahminleri vahim derecede yanlış olabilir. Bu da yanlış plan seçimlerine yol açar: çok fazla satır döndüren bir indeksi seçmek ya da hızlı bir indeksi atlamak gibi.
Rutinde yapılacak: düzenli istatistik güncellemeleri (genelde "ANALYZE" veya benzeri). Büyük yüklemeler, büyük silmeler veya yoğun churn sonrası istatistikleri daha erken güncelleyin.
Satırlar eklendikçe, güncellendikçe ve silindikçe indeksler bloat (artık işe yaramayan boş sayfalar) ve fragmentasyon biriktirebilir. Sonuç daha büyük indeksler, daha fazla okuma ve daha yavaş taramalar olabilir—özellikle aralık sorguları için.
Rutinde yapılacak: yoğun kullanılan ve orantısız büyümüş indeksleri periyodik olarak yeniden oluşturun veya yeniden düzenleyin. Tam araçlar ve etkiler veritabanına göre değişir; bu yüzden ölçümlere dayalı şekilde, her zaman dikkatle uygulayın.
Aşağıyı izleyin:
Bu geri besleme döngüsü hangi bakımın gerektiğini ve hangi indeksin ayarlanması veya kaldırılması gerektiğini yakalamanıza yardımcı olur. Daha fazla doğrulama için /blog/how-to-prove-an-index-helps-explain-and-measurements metnine bakabilirsiniz.
İndeks eklemek kasıtlı bir değişiklik olmalı, tahmin değil. Hafif iş akışı sizi ölçülebilir kazanımlara odaklar ve "indeks yayılması"nı engeller.
Kanıtla başlayın: yavaş sorgu günlükleri, APM izleri veya kullanıcı şikayetleri. Sık ve yavaş olan bir sorgu seçin—nadir 10 saniyelik bir rapor, sık görülen 200 ms'lik bir aramadan daha az önemlidir.
Tam SQL'i ve parametre kalıbını yakalayın (ör. WHERE user_id = ? AND status = ? ORDER BY created_at DESC LIMIT 50). Küçük farklar hangi indeksin yardımcı olacağını değiştirir.
Mevcut p50/p95 gecikmeyi, taranan satır sayısını ve CPU/IO etkisini kaydedin. Karşılaştırmak için mevcut plan çıktısını (EXPLAIN / EXPLAIN ANALYZE) saklayın.
Sorgunun filtreleme ve sıralama şekline uyan sütunları seçin. Planın büyük aralıkları taramayı bırakmasını sağlayacak minimal indeksi tercih edin.
Üretime benzer veri hacmine sahip bir staging ortamında test edin. İndeksler küçük veri kümelerinde iyi görünebilir ama ölçeklendiğinde hayal kırıklığı yaratabilir.
Büyük tablolarda destekleniyorsa online seçenekleri kullanın (ör. PostgreSQL CREATE INDEX CONCURRENTLY). Veri tabanı yazmaları kilitleyecekse değişiklikleri daha düşük trafikli zamanlara planlayın.
Aynı sorguyu yeniden çalıştırıp karşılaştırın:
İndeks yazma maliyetini veya bellek/dep olasılığını artırırsa temizce kaldırın (örn. DROP INDEX CONCURRENTLY kullanılabiliyorsa). Migration'ı tersine çevrilebilir tutun.
Migration veya şema notlarında indeksi hangi sorgunun amaçladığını ve hangi metriğin iyileştiğini yazın. Gelecekte neden var olduğunu ve ne zaman silinebileceğini bilmek faydalıdır.
Yeni bir servis inşa ediyorsanız ve erken dönemde "indeks yayılmasını" önlemek istiyorsanız, Koder.ai tam döngüde hızlı iterasyon yapmanıza yardımcı olabilir: sohbetten React + Go + PostgreSQL uygulaması üretin, şema/indeks migration'larını gereksinimler değiştikçe ayarlayın ve sonra kaynak kodu dışa aktarın. Pratikte bu, “bu endpoint yavaş”tan “işte EXPLAIN planı, minimal indeks ve geri alınabilir migration”a daha hızlı geçmenizi sağlar.
İndeksler büyük bir kaldıraçtır ama sihirli bir "her şeyi hızlandır" düğmesi değildir. Bazen sorgunun yavaş kısmı veritabanı doğru satırları bulduktan sonra olur—veya sorgu kalıbı indekslemeyi ilk adım olarak yanlış kılar.
Eğer sorgu iyi bir indeksi kullanmasına rağmen hâlâ yavaşsa şu nedenlere bakın:
OFFSET 999000 gibi büyük ofsetlerle sayfa çekmek indeks olsa bile yavaş olabilir. Anahtarset (keyset) sayfalamayı tercih edin (ör. son görülen id/timestamp sonrası satırlar).SELECT * veya on binlerce kayıt döndürmek ağ, JSON serileştirme veya uygulama tarafı işleme üzerinde darboğaz yaratabilir.Daha derin bir darboğaz teşhisi istiyorsanız, bunu /blog/how-to-prove-an-index-helps ile eşleştirerek ölçümlü bir yaklaşım uygulayın.
Tahmin etmeyin. Zamanın nerede harcandığını ölçün (veritabanı yürütmesi vs. döndürülen satırlar vs. uygulama kodu). Eğer veritabanı hızlıysa ama API yavaşsa daha fazla indeks işe yaramayacaktır.
Bir veritabanı indeksi, seçili sütun değerlerini aramayı kolaylaştıran, sıralı ve işaretleyiciler (pointer) içeren ayrı bir veri yapısıdır (çoğunlukla bir B-tree). Veritabanı, seçici sorgularda tablonun çoğunu okumaktan kaçınmak için indeksi kullanır.
İndeks tabloyun ikinci tam kopyası değildir; ancak bazı sütun verilerini ve metadata'yı çoğaltır, bu yüzden ekstra depolama tüketir.
İndeks yoksa veritabanı genellikle tam tablo taraması yapmak zorunda kalır: birçok (veya tüm) satırı okuyup WHERE koşulunu her biri için kontrol eder.
Bir indeks ile veritabanı çoğu zaman doğrudan eşleşen satırların yerini bulup sadece o satırları okuyabilir; böylece disk I/O, CPU filtreleme işi ve önbellek baskısı azalır.
B-tree indeksi değerleri sıralı tutar ve eşleşen değerin bulunduğu “mahalli” bölümüne hızla gitmeyi sağlayan sayfa (page) yapıları içerir.
Bu yüzden B-tree hem aşağıdakiler için iyidir:
WHERE email = ...)WHERE created_at >= ... AND created_at < ...)Hash indeksleri eşitlik (=) için çok hızlı olabilir çünkü değer bir hash'e dönüştürülür ve doğrudan ilgili kovaya (bucket) atlanır.
Takaslar:
Gerçek iş yüklerinde B-tree'ler daha geniş bir sorgu yelpazesini desteklediği için sıklıkla varsayılandır.
İndeksler genellikle şu durumlarda en fazla yardımı sağlar:
WHERE filtreleri (az sayıda satır eşleşir)JOIN anahtarları (foreign key ve referanslanan anahtarlar)ORDER BY ifadesinin indeks sırasına uyması (ek bir sıralamayı önleyebilir)Seçicilik, belirli bir değerin kaç satırla eşleştiğini ifade eder. İndeksler, bir koşul tablonun büyük bir bölümünü küçük bir sonuç kümesine daraltıyorsa işe yarar.
Düşük seçiciliğe sahip sütunlar (ör. is_deleted, is_active, birkaç değerli status) genelde tablonun büyük kısmını eşlediğinden indeks beklenen faydayı sağlamaz. Bu durumlarda indeks kullanmak, motorun indeks girdileri ve tablo sayfaları arasında çokça atlamasına neden olarak daha yavaş olabilir.
Optimizer, indeks kullanmanın işi yeterince azaltmayacağını tahmin ederse indeks var olsa bile onu görmezden gelebilir.
Bunun yaygın sebepleri:
Çoğu B-tree uygulamasında indeks, önce ilk sütuna göre, sonra onun içindeki ikinci sütuna göre vb. sıralanmıştır. Bu yüzden veritabanı indeksi en verimli şekilde soldan sağa kullanabilir.
Örnek:
(account_id, created_at) indeksi WHERE account_id = ? ve zaman filtreleme/sıralaması için mükemmeldir.created_at ile filtreleyen bir sorgu için genellikle yardımcı olmaz (çünkü o soldaki sütun değildir).Kapsayan (covering) indeks, sorgunun ihtiyaç duyduğu tüm sütunları içerir; dolayısıyla veritabanı tablo satırlarını okumadan sadece indeksten sonuç döndürebilir.
Faydaları:
Maliyetleri:
Kapsayan indeksleri spesifik, yüksek değerli sorgular için kullanın; "ihtimal" için geniş indeksler oluşturmayın.
İki şeyi kontrol edin:
EXPLAIN / EXPLAIN ANALYZE ile planın değişip değişmediğini doğrulayın (ör. Seq Scan → Index Scan/Seek, daha az okunan satır, sort adımının kaybolması).Ayrıca yeni indeksin // üzerindeki etkisini de izleyin; çünkü indeksler yazma maliyetini artırabilir.
GROUP BYBir sorgu tabloyun büyük bir kısmını döndürüyorsa, indeksin faydası genellikle sınırlıdır.
INSERTUPDATEDELETE