Orta6 dakikalık okuma

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:

Sparse GSI (yalnızca açık)Temel tablo (tüm öğeler)anahtar kaldırıldıanahtar kaldırıldıAçık: anahtar varAçık: anahtar varKapalı: anahtar yokKapalı: anahtar yokAçıkAçık

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:

PKSKattributes
TICKET#a91fDETAILsubject, body, priority, openState
CUSTOMER#88TICKET#a91fsubject, 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.

PKSKopenBucketopenedAt
TICKET#a91fDETAILOPEN2026-06-23T09:14:00Z← açık: index'te
TICKET#b02cDETAILOPEN2026-06-22T16:40:00Z← açık: index'te
TICKET#77deDETAIL(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.

Destek-talebi tablosu, DynoTable'da açık-talepler sparse GSI'si üzerinden görüntülenir, yalnızca openBucket anahtarını taşıyan öğeleri gösterir.
Destek-talebi tablosu, DynoTable'da açık-talepler sparse GSI'si üzerinden görüntülenir, yalnızca openBucket anahtarını taşıyan öğeleri gösterir.

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'u REMOVE etmelisin — 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 Query yalnı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 bir GetItem ö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.

Güncellendi