DynamoDB Sparse Index'leri
Bir sparse index (seyrek index), yalnızca anahtar attribute'unu taşıyan öğeleri tutan bir secondary index'tir — böylece devasa bir tablonun küçük, sıcak bir alt kümesi, kendi önceden filtrelenmiş, sorgulamaya hazır collection'ı haline gelir.
Milyonlarca satırın var ama gün boyu çalıştırdığın sorgu küçük bir dilime dokunuyor: açık destek talepleri, ödenmemiş faturalar, inceleme için işaretlenmiş hesaplar.
O dilimi filtrelemek yine de tüm tabloyu tarar ve her okuma için sana fatura keser. Bir sparse index, bunun yerine index'in kendisini küçük yapar.
DynamoDB'de sparse index nedir?
Sparse index, yalnızca anahtar attribute'unu taşıyan öğeleri tutan bir secondary index'tir. DynamoDB bu anahtarı olmayan öğeleri atladığı için, yalnızca istenen öğelerin yazdığı bir anahtar icat edersin — açık destek talepleri, ödenmemiş faturalar — ve index tam olarak o alt küme haline gelir. Sorgular artık yalnızca onu okur; filtre yok, boşa harcanan okuma kapasitesi yok.
- Bir secondary index yalnızca anahtarına sahip öğeleri indeksler. Bir öğede anahtarı atla, asla index'e girmez — placeholder yok, null satır yok.
- Yani yalnızca istenen öğelerin taşıdığı bir anahtar icat edersin. Onu sorguladığın öğelere yaz, geri kalanda kaldır. Index tam olarak o alt küme olur.
- Sorgu yalnızca alt kümeyi okur, filtre yok. Boyutu tablo toplamını değil, küçük sıcak kümeyi takip eder.
- Kaldıraç
REMOVE'dur, boşaltma değil. Boş bir string yine de bir değerdir ve yine de indekslenir — attribute'u silmen gerekir.
Sorun: filtreleme okumalardan tasarruf ettirmez
SQL'den gelince, bir WHERE cümlesinin işi daralttığını varsayarsın. DynamoDB'nin
FilterExpression'ı bunu yapmaz. Öğeler okunmadan önce değil, sonra çalışır.
AWS Developer Guide'a göre, filtreleme "tüketilen okuma kapasitesi miktarını azaltmaz" — incelenen her öğe için ödeme yaparsın, sonra eşleşmeyenleri atarsın.
Yani 5 milyon talebinin 50'si açıksa, filtreli bir Query/Scan sana o 50'yi vermek
için milyonlarcasını okur.
Bu, her "taramam neden bu kadar pahalı" konusunun arkasındaki ayak tuzağıdır (footgun); query ve scan tam maliyet resmini içerir.
Bir sparse index, index'in kendisini küçük yaparak bunu atlatır.
Seyreklik nasıl çalışır
Bir secondary index yalnızca index'in anahtar attribute'larına gerçekten sahip öğeleri indeksler.
Global secondary index'ler üzerine AWS dokümanları bunu açıkça söyler: "bir global secondary index yalnızca o index için tanımlanan anahtar attribute'lara sahip öğeleri içerir."
Bir öğede GSI'nin partition key'ini (veya sort key'ini) atla, DynamoDB onu index'e yazmaz. Placeholder yok, null satır yok — öğe yoktur.
Bu "varsayılan olarak yokluk", tüm püf noktasıdır. Her öğenin taşıdığı bir status
attribute'unu indeksleme. Yalnızca sorgulamak istediğin öğelerin sahip olduğu bir
attribute icat et.
Index böylece tam olarak o öğelerin temiz bir listesi olur ve ona karşı bir Query
yalnızca onları okur — filtre yok, boşa harcanan kapasite yok.
Temel tablonun index'i beslediğini, yalnızca anahtarı taşıyan öğelerin karşıya geçtiğini hayal et:
Yalnızca anahtarlanmış (açık) öğeler index'e kopyalanır; kapalı öğeler ona asla girmez.
Bu, single-table tasarımdaki aynı anahtar-şekillendirme zihniyetidir: anahtarlar, verinin sadık aynaları değil, belirli bir erişim deseni için oluşturduğun araçlardır.
İşlenmiş bir örnek: "yalnızca açık talepler"
Bir destek-talebi tablosu al. Temel tablo, bir talebi id ile getirmek ve bir müşterinin taleplerini listelemek için anahtarlanmıştır:
| PK | SK | attributes |
|---|---|---|
| TICKET#a91f | DETAIL | subject, body, priority, openState |
| CUSTOMER#88 | TICKET#a91f | subject, priority, openState |
Tablonun ömrü boyunca, çoğu talep sonunda kapanır. Ama temsilcilerinin gün boyu çalıştırdığı dashboard sorgusu "bana her açık talebi göster, en eski ilk"tir — milyonlarcasının içinde gizlenen birkaç yüz satır.
Sparse-index hamlesi: partition key openBucket ve sort key openedAt olan bir GSI
tanımla ve openBucket'ı yalnızca açık taleplere yaz. Talep oluşturulduğunda
ayarla; talep çözüldüğünde REMOVE et.
| PK | SK | openBucket | openedAt | |
|---|---|---|---|---|
| TICKET#a91f | DETAIL | OPEN | 2026-06-23T09:14:00Z | ← açık: index'te |
| TICKET#b02c | DETAIL | OPEN | 2026-06-22T16:40:00Z | ← açık: index'te |
| TICKET#77de | DETAIL | (yok) | 2026-05-30T11:02:00Z | ← kapalı: index'te DEĞİL |
a91f ve b02c talepleri openBucket'ı taşır, bu yüzden GSI'de yaşarlar. 77de
talebi çözüldü ve openBucket'ı kaldırıldı, bu yüzden sessizce düştü. Dashboard artık
tek bir ucuz sorgu:
Query IndexName = "open-tickets-index"
KeyConditionExpression: openBucket = "OPEN"
ScanIndexForward: true # oldest first
Bu yalnızca açık talepleri okur. Talepler kapandıkça, index kendi kendine küçülür — boyutu, toplamı değil, açık popülasyonu takip eder.
Tek bir statik partition değeri ("OPEN") burada tam olarak küme küçük kaldığı için
uygundur. Devasa bir açık küme parçalanmış bir partition key gerektirir, ancak "küçük
alt küme" index'i, tam olarak tek bir değerin doğru tercih olduğu yerdir.
İşe yaramasını sağlayan geçiş, tek bir update ifadesidir — talep çözüldüğünde attribute'u kaldırmak.
ExpressionAttributeNames'i ve :val placeholder'larını kendin elle birleştirmek
yerine, o REMOVE cümlesini ve okuma tarafı için tipli anahtar koşulunu
DynamoDB Expression Builder'da prototiple.
DynoTable'da yap
Bir sparse index'in zor kısmı okuma değil — hangi öğelerin index'e girdiğini, hangi öğelerin sessizce düştüğünü görmektir.
DynoTable bir tablo görünümünü bir secondary index'e geçirmene ve tam olarak
doldurulmuş alt kümeyi görmene izin verir. Böylece çözülen bir talebin gerçekten
open-tickets-index'ten ayrıldığını, eski bir anahtarla oyalanmadığını
doğrulayabilirsin.

Tuzaklar ve sonraki adımlar
Dikkat edilecek birkaç şey:
- Anahtarı kaldır, boşaltma. Boş bir string yine de bir değerdir ve DynamoDB,
openBucket'ı""olan bir öğeyi indeksler. Bir öğeyi index'ten çıkarmak için attribute'uREMOVEetmelisin — onu sahte (falsy) bir değere ayarlamak onu içeride tutar. - Index nihai tutarlıdır. GSI'ler asenkron olarak güncellenir, bu yüzden yeni çözülmüş bir talep kısa süreliğine hâlâ görünebilir — GSI okumaları yalnızca nihai tutarlılığı destekler. "Bu talep şu anda açık mı" için ona güvenme.
- Yansıtılan attribute'lara dikkat et. Index üzerinde bir
Queryyalnızca ona yansıtılan attribute'ları döndürür. Dashboard'un konu ve önceliğe ihtiyacı varsa, onları yansıt — ya da tam temel öğe için fazladan birGetItemöde. - Bu bir GSI gücüdür, bir LSI gücü değil. Local secondary index'ler temel tablonun partition key'ini paylaşır ve öğeleri bu şekilde seçici olarak düşüremez. GSI ve LSI ödünleşimi ayrıştırır.
Sparse index'ler, modeldeki en eski fikirlerden biridir. Orijinal 2007 Amazon Dynamo makalesi depoyu, bilinen, yüksek hacimli erişim desenlerine ucuza hizmet etmek etrafında kurdu.
Bir sparse index tam olarak budur: anahtarları, yaygın sorgu ihtiyacı olmayan hiçbir şeyi okumayacak şekilde şekillendir.
Bunu gerçekten oluşturup incelemek için, DynoTable'ı indir, tablona yönelt ve veri görünümünü sparse GSI'ne çevir — öğeler index anahtarını kazanıp kaybettikçe alt kümenin güncellendiğini izle.


