Bir DynamoDB GSI Dahili Olarak Nasıl Saklanır
Bir Global Secondary Index, tablona geri dönen bir işaretçi değildir. O, DynamoDB'nin yazmaları içine asenkron olarak kopyalayarak senkronize tuttuğu ayrı, dahili olarak yönetilen bir tablodur — kendi partition'ları, kendi key şeması, kendi kapasitesi.
SQL'den geliyorsan, bir index aynı fiziksel tabloya cıvatalanmış, aynı transaction içinde güncellenen bir B-tree'dir. Bir GSI bu varsayımların ikisini de kırar ve neredeyse her GSI sürprizi tam da bu tek gerçeğe dayanır.
Bir DynamoDB GSI nasıl saklanır?
Bir DynamoDB GSI, base tabloya geri dönen bir işaretçi olarak değil, ayrı, dahili olarak yönetilen bir tablo olarak saklanır — kendi partition'ları, kendi key şeması ve kendi kapasitesiyle. DynamoDB her yazmayı index'e asenkron olarak kopyalar ve yalnızca GSI key'lerini, base tablo key'lerini ve varsa project edilen attribute'ları saklar.
- Bir GSI kendi tablosudur. Base tablonunkiyle değil, GSI'nin partition key'iyle key'lenmiş, tamamen bağımsız bir partition uzayına sahiptir.
- Yazmalar asenkron replike olur. Yazman önce base tabloya commit edilir, sonra DynamoDB onu bir arka plan yolu üzerinde her GSI'ye yelpazeler.
- Yalnızca project edilen attribute'lar saklanır. Index, GSI key'lerini, base key'leri, artı project ettiğin attribute'ları tutar — başka bir şey değil.
- GSI key'inin benzersiz olması gerekmez. Birden çok base item bir GSI partition/sort key'ini paylaşabilir; base birincil key, onları ayrı tutan belirleyicidir.
Tek bir base item'la başla
Bir SaaS denetim günlüğü ele al. Bir workspace'teki her ayrıcalıklı eylem,
değişmez bir olay olur. Base tablo, WorkspaceEvents, bir workspace'in tüm
olayları tek bir item koleksiyonunda, zamana göre sıralı yaşayacak şekilde
key'lenmiştir:
| EventPK | EventSK | actorId | verb | targetRef |
|---|---|---|---|---|
| WS#orbit-9 | TS#2026-06-23T14:02:11Z | USR#kp | ROLE_GRANTED | USR#mara |
EventPK = "WS#orbit-9" workspace'e göre partition'lar; EventSK bir ISO
timestamp'tir, böylece bir Query bir workspace'in olaylarını kronolojik sırada
döndürür. Bu, "bana bu workspace'in zaman çizelgesini göster"e mükemmel hizmet eder.
Başka hiçbir şeye hizmet etmez. "USR#kp her workspace'te ne yaptı?" diye
soramazsın — actorId bir key değil, dolayısıyla onu base tabloda cevaplamanın
tek yolu tam bir Scan'dir. Bir GSI'nin eklemek için var
olduğu erişim deseni budur.
Bir GSI ekle ve ikinci bir tablonun belirmesini izle
Aynı olayları onları kimin gerçekleştirdiğine göre yeniden partition'layan bir GSI,
ByActor, tanımla:
ByActor (GSI)
GSI1PK = actorId ("USR#kp")
GSI1SK = EventSK ("TS#2026-06-23T14:02:11Z")
DynamoDB artık ikinci bir fiziksel yapı tutar. Aynı mantıksal olay iki kez
saklanır — bir kez base tablonun WS#orbit-9 partition'ında ve bir kez daha GSI'nin
USR#kp partition'ında:
| GSI1PK | GSI1SK | EventPK | EventSK | verb |
|---|---|---|---|---|
| USR#kp | TS#2026-06-23T14:02:11Z | WS#orbit-9 | TS#2026-06-23T14:02:11Z | ROLE_GRANTED |
Neyin birlikte geldiğine dikkat et: base tablonun key'leri (EventPK, EventSK)
her GSI item'ında otomatik olarak saklanır. Bir GSI isabetinin seni tam item'a geri
işaret edebilmesinin — ve bir KEYS_ONLY
index'in bile neden depolamaya mal olduğunun — nedeni budur.
GSI'de gerçekte ne yaşar
Index tüm item'ı kopyalamaz. Her GSI girdisi tam olarak üç şey tutar ve yalnızca üçüncüsünü kontrol edersin:
| GSI'de saklanan | Nereden gelir | İsteğe bağlı? |
|---|---|---|
| GSI partition + sort key | GSI key'leri olarak adlandırdığın attribute'lar | Hayır |
| Base tablo key('leri) | Her base item'dan kopyalanır | Hayır |
| Project edilen attribute'lar | Projection seçimin | Evet |
Projection, KEYS_ONLY, INCLUDE (adlandırılmış bir liste) ya da ALL'dur.
GSI üzerindeki bir Query yalnızca index'te olan attribute'ları döndürebilir.
Project edilmemiş birini iste ve DynamoDB onu şeffaf olarak getirmez — o alan için geriye hiçbir şey almazsın. (AWS GSI dokümanları)
İşte tersine çevrilmiş ilişkisel tuzak: SQL, eksik sütun için heap'e geri birleştirirdi. Bir GSI asla yapmaz. Projection tüm sözleşmedir.
Bir yazma index'e nasıl ulaşır
Replikasyon, SQL sezgisini en sert kıran kısımdır. Bir base yazması ve onun index güncellemesi tek bir atomik operasyon değildir.
PutItem yaptığında, DynamoDB dayanıklı olarak base tabloya commit eder, yazmanı
onaylar ve sonra değişikliği her GSI'yi güncelleyen bir arka plan yoluna
yayar. Onay, index'i beklemez.
İşte denetim yazmamız için olayların sırası, yukarıdan aşağıya:
Çağıran, üçüncü adımda, dört ila altı adım bitmeden 200 OK'ini alır — dolayısıyla
o aradaki ByActor üzerindeki bir Query, yepyeni bir olayı kaçırabilir.
O asenkronluk bir kusur değil, tasarım gereğidir: 2007 Amazon Dynamo makalesinin soyudur, ki o makale erişilebilirliği senkron tutarlılığa tercih etti. Tüm sonuçlar bir GSI'nin neden nihai tutarlı olduğunda yaşar.
GSI key'i benzersiz bir key değildir
SQL'de, benzersiz olmayan bir ikincil index varsayılandır ve benzersiz olan, kabul ettiğin bir kısıttır. Bir GSI bunun tersidir: hiçbir benzersizlik garantisi yoktur, asla.
Aynı aktörden, çakışan timestamp'lerdeki iki denetim olayı aynı GSI1PK ve
GSI1SK'yı paylaşır. DynamoDB ikisini de saklar — onları her zaman taşınan base
tablonun birincil key'iyle dahili olarak ayırt eder.
Yani bir aktör için bir anda bir GSI Query'si meşru olarak birkaç item
döndürebilir. Bir SQL benzersiz index'inin sana vereceği şekilde key başına tek
satır varsaydıysan, ayak kapanı budur.
Index'i sorguladığında,
DynamoDB Expression Builder,
KeyConditionExpression'ı name'ler ve value'lar doğru escape edilmiş olarak yazar —
örn. bir kesim tarihinden beri bir aktörü eşleştirme:
KeyConditionExpression: "#a = :actor AND #ts > :since"
ExpressionAttributeNames: { "#a": "actorId", "#ts": "EventSK" }
ExpressionAttributeValues: {
":actor": { "S": "USR#kp" },
":since": { "S": "TS#2026-06-01T00:00:00Z" }
}Kapasite tabloyla değil, index'le yaşar
GSI kendi tablosu olduğundan, kendi okuma ve yazma kapasitesine sahiptir, base
tablodan ayrı faturalandırılır ve kısıtlanır (throttle). ByActor'dan bir okuma,
GSI'nin okuma birimlerini tüketir, asla tablonunkileri değil.
Isıran ters bağlantı şudur: her base-tablo yazması index'i de yazar ve GSI bunu ememezse, base yazmaya geri-basınç yapar. O mekanizma kendi kılavuzunu alır — bir GSI base-tablo yazmalarını ne zaman kısıtlar (throttle).
Bu ayrıca bir GSI'nin partition key'inin neden base tablonunki kadar önemli olduğudur. Düşük-kardinaliteli bir GSI key'i, base yazmalar mükemmel yayılmış olsa bile yazmaları tek bir index partition'ına kümeler — yeniden key'leyerek oluşturduğun bir hot partition.
Tuzaklar ve sonraki adımlar
- Project edilmemiş attribute'ları geri bekleme. Bir GSI
Query'si yalnızca index'in sakladığını döndürür. Tam item'a ihtiyacın varsa, onu project et ya da taşınan key'lerle base tablodan getir. - Bir GSI key'ini benzersiz olarak ele alma. Bir
Query'nin key başına birden fazla item döndürmesini planla; base birincil key tek gerçek kimliktir. - Bir GSI'yi onu besleyen yazmadan hemen sonra okuma. Async yol, index'in yazmanı henüz göstermeyebileceği anlamına gelir — kendi yazmanı okumaya ihtiyacın olduğunda base tabloyu oku.
- GSI'nin kapasitesini kasıtlı boyutlandır. Okumalarda bağımsız ve yazmalarda gizli bir bağımlılıktır.
Tüm oyun, desenlerine hizmet eden key şekilleri seçmektir — single-table design tek bir GSI'yi bunların birçoğu arasında aşırı yükler; GSI vs LSI ise yerel bir index'in bunun yerine ne zaman uyduğunu kapsar.
GSI KeyConditionExpression'ını
DynamoDB Expression Builder içinde oluştur ve
önizle, sonra bir index'in project edilen attribute'larını incelemek ve yazmaların
kendi tablolarında GSI'ye replike olmasını izlemek için DynoTable'ı dene.