Lanjutan7 menit baca

Cara Sebuah GSI DynamoDB Disimpan Secara Internal

Sebuah Global Secondary Index bukanlah penunjuk kembali ke tabel Anda. Ia adalah tabel terpisah yang dikelola secara internal — partition-nya sendiri, key schema-nya sendiri, kapasitasnya sendiri — yang dijaga sinkron oleh DynamoDB dengan menyalin tulisan ke dalamnya secara asinkron.

Datang dari SQL, sebuah index adalah B-tree yang dibaut ke tabel fisik yang sama, diperbarui di dalam transaction yang sama. Sebuah GSI mematahkan kedua asumsi tersebut, dan hampir setiap kejutan GSI berakar pada satu fakta itu.

Bagaimana sebuah GSI DynamoDB disimpan?

Sebuah GSI DynamoDB disimpan sebagai tabel terpisah yang dikelola secara internal — dengan partition, key schema, dan kapasitasnya sendiri — bukan sebagai penunjuk ke dalam tabel basis. DynamoDB menyalin setiap tulisan ke dalam index secara asinkron, dan hanya menyimpan key GSI, key tabel basis, serta atribut apa pun yang diproyeksikan.

  • Sebuah GSI adalah tabelnya sendiri. Ia punya ruang partition yang sepenuhnya independen yang di-key oleh partition key GSI, bukan tabel basis.
  • Tulisan direplikasi secara asinkron. Tulisan Anda di-commit ke tabel basis dulu, lalu DynamoDB menyebarkannya ke setiap GSI di jalur latar.
  • Hanya atribut yang diproyeksikan yang disimpan. Index menampung key GSI, key basis, ditambah atribut apa pun yang Anda proyeksikan — tak ada yang lain.
  • Key GSI tak perlu unik. Banyak Item basis bisa berbagi satu partition/sort key GSI; primary key basis adalah pemecah-seri yang menjaga mereka tetap berbeda.

Mulai dengan satu Item basis

Ambil sebuah audit log SaaS. Setiap aksi privileged dalam sebuah workspace menjadi event yang immutable. Tabel basis, WorkspaceEvents, di-key sehingga semua event sebuah workspace tinggal dalam satu item collection, diurutkan berdasarkan waktu:

WorkspaceEvents (tabel basis)
EventPKEventSKactorIdverbtargetRef
WS#orbit-9TS#2026-06-23T14:02:11ZUSR#kpROLE_GRANTEDUSR#mara

EventPK = "WS#orbit-9" mem-partition berdasarkan workspace; EventSK adalah timestamp ISO sehingga sebuah Query mengembalikan event satu workspace dalam urutan kronologis. Itu melayani "tunjukkan saya timeline workspace ini" dengan sempurna.

Ia tidak melayani yang lain. Anda tidak bisa bertanya "apa yang dilakukan USR#kp di setiap workspace?" — actorId bukan key, jadi satu-satunya cara menjawabnya pada tabel basis adalah sebuah Scan penuh. Itulah pola akses yang ada untuk ditambahkan oleh sebuah GSI.

Tambahkan sebuah GSI dan saksikan tabel kedua muncul

Definisikan sebuah GSI, ByActor, yang mem-partition ulang event yang sama berdasarkan siapa yang melakukannya:

ByActor (GSI)
GSI1PK = actorId   ("USR#kp")
GSI1SK = EventSK   ("TS#2026-06-23T14:02:11Z")

DynamoDB kini memelihara sebuah struktur fisik kedua. Event logis yang sama disimpan dua kali — sekali di partition WS#orbit-9 tabel basis, dan lagi di partition USR#kp GSI:

ByActor (GSI) — ruang partition-nya sendiri
GSI1PKGSI1SKEventPKEventSKverb
USR#kpTS#2026-06-23T14:02:11ZWS#orbit-9TS#2026-06-23T14:02:11ZROLE_GRANTED

Perhatikan apa yang ikut serta: key tabel basis (EventPK, EventSK) disimpan di setiap Item GSI secara otomatis. Begitulah sebuah hit GSI bisa mengarahkan Anda kembali ke Item lengkap — dan mengapa sebuah index KEYS_ONLY tetap memakan penyimpanan.

Apa yang sebenarnya tinggal di GSI

Index tidak menyalin seluruh Item. Setiap entri GSI menampung tepat tiga hal, dan Anda hanya mengontrol yang ketiga:

Disimpan di GSIDari mana asalnyaOpsional?
Partition + sort key GSIAtribut yang Anda namai sebagai key GSITidak
Key tabel basisDisalin dari setiap Item basisTidak
Atribut yang diproyeksikanPilihan Projection AndaYa

Projection adalah KEYS_ONLY, INCLUDE (sebuah daftar bernama), atau ALL. Sebuah Query pada GSI hanya bisa mengembalikan atribut yang ada di index.

Minta satu yang tidak diproyeksikan dan DynamoDB tidak mengambilnya secara transparan — Anda tidak mendapat apa pun untuk field itu. (dokumentasi GSI AWS)

Itulah jebakan relasional yang terbalik: SQL akan join kembali ke heap untuk kolom yang hilang. Sebuah GSI tidak pernah melakukannya. Proyeksi adalah seluruh kontrak.

Bagaimana sebuah tulisan mencapai index

Replikasi adalah bagian yang paling keras mematahkan intuisi SQL. Sebuah tulisan basis dan pembaruan index-nya bukan satu operasi atomik.

Saat Anda PutItem, DynamoDB meng-commit secara durabel ke tabel basis, mengonfirmasi tulisan Anda, dan lalu menyebarkan perubahan ke jalur latar yang memperbarui setiap GSI. Konfirmasi tidak menunggu index.

Berikut urutan peristiwa untuk tulisan audit kita, dari atas ke bawah:

PutItemevent WS#orbit-9Commit kepartition basis200 OKke pemanggilJalur async:ekstrak key GSIRutekan ke partitionByActor USR#kpTulis atributyang diproyeksikan

Pemanggil mendapat 200 OK-nya di langkah tiga, sebelum langkah empat hingga enam selesai — sehingga sebuah Query pada ByActor di sela itu bisa melewatkan event yang baru saja masuk.

Asinkronisitas itu adalah desain, bukan cacat: ia adalah garis keturunan dari paper Amazon Dynamo 2007, yang memilih ketersediaan di atas konsistensi sinkron. Konsekuensi penuhnya ada di mengapa sebuah GSI eventually consistent.

Key GSI bukan key unik

Di SQL, index sekunder non-unik adalah default dan yang unik adalah constraint yang Anda pilih. Sebuah GSI sebaliknya: ia tidak memiliki jaminan keunikan, sama sekali.

Dua event audit dari aktor yang sama pada timestamp yang berbenturan akan berbagi GSI1PK dan GSI1SK yang sama. DynamoDB menyimpan keduanya — ia membedakannya secara internal melalui primary key tabel basis, yang selalu ikut terbawa.

Jadi sebuah Query GSI untuk satu aktor pada satu instan bisa secara sah mengembalikan beberapa Item. Jika Anda berasumsi satu-baris-per-key seperti yang akan diberikan index unik SQL, itu footgun-nya.

Saat Anda melakukan query index, DynamoDB Expression Builder menulis KeyConditionExpression dengan names dan values yang di-escape dengan benar — mis. mencocokkan satu aktor sejak sebuah cutoff:

KeyConditionExpression: "#a = :actor AND #ts > :since"
ExpressionAttributeNames:  { "#a": "actorId", "#ts": "EventSK" }
ExpressionAttributeValues: {
  ":actor": { "S": "USR#kp" },
  ":since": { "S": "TS#2026-06-01T00:00:00Z" }
}

Kapasitas tinggal bersama index, bukan tabel

Karena GSI adalah tabelnya sendiri, ia memiliki read dan write capacity-nya sendiri, ditagih dan di-throttle terpisah dari tabel basis. Sebuah pembacaan dari ByActor mengonsumsi read unit GSI, tak pernah milik tabel.

Kopling terbalik adalah yang menggigit: setiap tulisan tabel-basis juga menulis index, dan jika GSI tak bisa menyerapnya, ia memberi tekanan-balik pada tulisan basis. Mekanisme itu mendapat panduannya sendiri — saat sebuah GSI men-throttle tulisan tabel-basis.

Inilah juga alasan partition key GSI sama pentingnya dengan tabel basis. Sebuah key GSI ber-cardinality-rendah menggumpalkan tulisan ke satu partition index bahkan saat tulisan basis tersebar sempurna — sebuah hot partition yang Anda ciptakan dengan me-re-key.

Jebakan dan langkah berikutnya

  • Jangan harapkan atribut yang tak-diproyeksikan kembali. Sebuah Query GSI hanya mengembalikan apa yang disimpan index. Jika Anda butuh Item lengkap, proyeksikan atau ambil dari tabel basis melalui key yang ikut terbawa.
  • Jangan perlakukan key GSI sebagai unik. Rencanakan agar sebuah Query mengembalikan lebih dari satu Item per key; primary key basis adalah satu-satunya identitas nyata.
  • Jangan baca sebuah GSI tepat setelah tulisan yang memberinya makan. Jalur async berarti index mungkin belum menampilkan tulisan Anda — baca tabel basis saat Anda butuh read-your-own-writes.
  • Ukur kapasitas GSI secara sengaja. Ia independen pada pembacaan dan dependensi tersembunyi pada tulisan.

Seluruh permainannya adalah memilih bentuk key yang melayani pola Anda — single-table design meng-overload satu GSI di banyak darinya; GSI vs LSI membahas kapan index lokal pas sebaliknya.

Bangun dan pratinjau KeyConditionExpression GSI Anda di DynamoDB Expression Builder, lalu coba DynoTable untuk memeriksa atribut yang diproyeksikan sebuah index dan menyaksikan tulisan direplikasi ke GSI pada tabel Anda sendiri.

Diperbarui