Menengah7 menit baca

Sparse index DynamoDB

Sparse index adalah secondary index yang hanya menampung item yang membawa atribut key-nya — sehingga subset kecil dan panas dari tabel besar menjadi koleksi sendiri yang sudah terfilter dan siap di-Query.

Anda punya jutaan baris, tetapi query yang dijalankan sepanjang hari hanya menyentuh irisan tipis: tiket support terbuka, invoice belum dibayar, akun yang ditandai untuk review.

Memfilter irisan itu tetap men-Scan seluruh tabel dan menagih setiap baca. Sparse index membuat indeksnya sendiri yang kecil.

Apa itu sparse index di DynamoDB?

Sparse index adalah secondary index yang hanya menampung item yang membawa atribut key-nya. Karena DynamoDB melewatkan item yang tidak punya key itu, Anda menciptakan key yang hanya ditulis item yang diinginkan — tiket terbuka, invoice belum dibayar — dan indeks menjadi tepat subset itu. Query lalu hanya membacanya, tanpa filter, tanpa kapasitas baca terbuang.

  • Secondary index hanya mengindeks item yang punya key-nya. Hilangkan key pada item dan item itu tidak pernah masuk indeks — tanpa placeholder, tanpa baris null.
  • Jadi Anda menciptakan key yang hanya dibawa item yang diinginkan. Tulis pada item yang Anda Query, hapus pada sisanya. Indeks menjadi tepat subset itu.
  • Query hanya membaca subset, tanpa filter. Ukurannya mengikuti set panas yang kecil, bukan total tabel.
  • REMOVE adalah tuasnya, bukan mengosongkan. String kosong bukan key indeks yang valid — DynamoDB menolak seluruh write dengan ValidationException — jadi Anda harus menghapus atributnya.

Masalahnya: filter tidak menghemat baca

Datang dari SQL, Anda menganggap klausa WHERE mempersempit kerja. FilterExpression DynamoDB tidak. Ia berjalan setelah item dibaca, bukan sebelum.

Menurut AWS Developer Guide, "sebuah Query memakan jumlah kapasitas baca yang sama, terlepas dari ada atau tidaknya filter expression" — Anda membayar setiap item yang diperiksa, lalu membuang yang tidak cocok.

Jadi jika 50 dari 5 juta tiket Anda terbuka, Query/Scan berfilter membaca jutaan untuk menyerahkan 50 itu.

Itulah jebakan di balik setiap thread "kenapa scan saya mahal"; query vs. scan punya gambaran biaya lengkapnya.

Sparse index menghindarinya dengan membuat indeksnya sendiri yang kecil.

Cara kerja sparsitas

Secondary index hanya mengindeks item yang benar-benar punya atribut key indeksnya.

Dokumen AWS tentang sparse index menjelaskannya: DynamoDB menulis item ke secondary index hanya ketika item itu membawa atribut key indeks, jadi indeks atas atribut yang jarang di-set tetap kecil secara alami.

Hilangkan partition key (atau sort key) GSI pada item dan DynamoDB tidak menulisnya ke indeks. Tanpa placeholder, tanpa baris null — item absen.

"Absen secara default" itulah seluruh tipunya. Jangan indeks atribut status yang dibawa setiap item. Ciptakan atribut yang hanya dibawa item yang ingin Anda Query.

Indeks lalu menjadi daftar bersih tepat item-item itu, dan Query terhadapnya hanya membaca mereka — tanpa filter, tanpa kapasitas terbuang.

Bayangkan tabel dasar mengisi indeks, di mana hanya item yang membawa key yang menyeberang:

key dihapuskey dihapusGSI sparse (hanya open)OpenOpenTabel dasar (semua item)Open: punya keyOpen: punya keyClosed: tanpa keyClosed: tanpa key

Hanya item ber-key (open) yang mereplikasi ke indeks; item closed tidak pernah masuk.

Ini mindset pembentukan key yang sama dengan single-table design: key adalah alat yang Anda bangun untuk access pattern spesifik, bukan cermin setia data Anda.

Contoh kerja: "hanya tiket terbuka"

Ambil tabel tiket support. Tabel dasar di-key untuk mengambil tiket by id dan mendaftar tiket pelanggan:

PKSKattributes
TICKET#a91fDETAILsubject, body, priority, openState
CUSTOMER#88TICKET#a91fsubject, priority, openState

Sepanjang umur tabel, sebagian besar tiket berakhir closed. Tetapi query dashboard yang di-hit agen sepanjang hari adalah "tampilkan setiap tiket terbuka, tertua dulu" — beberapa ratus baris tersembunyi di dalam jutaan.

Definisikan dengan partition key openBucket dan sort key openedAt, dan hanya tulis openBucket pada tiket terbuka. Set saat tiket dibuat; REMOVE saat tiket selesai.

PKSKopenBucketopenedAt
TICKET#a91fDETAILOPEN2026-06-23T09:14:00Z← open: in the index
TICKET#b02cDETAILOPEN2026-06-22T16:40:00Z← open: in the index
TICKET#77deDETAIL(absent)2026-05-30T11:02:00Z← closed: NOT in the index

Tiket a91f dan b02c membawa openBucket, jadi mereka hidup di GSI. Tiket 77de sudah resolved dan openBucket-nya dihapus, jadi diam-diam keluar. Dashboard sekarang satu query murah:

Query  IndexName = "open-tickets-index"
KeyConditionExpression: openBucket = "OPEN"
ScanIndexForward: true        # oldest first

Ini hanya membaca tiket terbuka. Saat tiket close, indeks menyusut sendiri — ukurannya mengikuti populasi open, bukan total.

Satu nilai partisi statis ("OPEN") cocok di sini justru karena set-nya tetap kecil. Set open yang besar butuh partition key ter-shard, tetapi indeks "subset kecil" tepat di mana satu nilai adalah pilihan yang benar.

Transisi yang membuatnya bekerja adalah satu — menghapus atribut saat tiket selesai.

Prototype klausa REMOVE itu dan key condition bertipe untuk sisi baca di DynamoDB Expression Builder, alih-alih merakit sendiri ExpressionAttributeNames dan placeholder :val.

Lakukan di DynoTable

Bagagian sulit sparse index adalah melihat item mana yang masuk indeks versus mana yang diam-diam keluar.

DynoTable membiarkan Anda mengalihkan tampilan tabel ke secondary index dan melihat tepat subset yang terisi. Jadi Anda bisa memastikan tiket yang resolved benar-benar meninggalkan open-tickets-index, bukan tertinggal dengan key basi.

Tabel tiket support dilihat lewat GSI sparse open-tickets di DynoTable, menampilkan hanya item yang membawa key openBucket.
Tabel tiket support dilihat lewat GSI sparse open-tickets di DynoTable, menampilkan hanya item yang membawa key openBucket.

Jebakan dan langkah selanjutnya

Beberapa hal yang perlu diwaspadai:

  • Hapus key-nya, jangan dikosongkan. String kosong bukan key indeks yang valid — menulis openBucket = "" gagal dengan ValidationException, jadi item tidak pernah terindeks dengannya. Untuk mengeluarkan item dari indeks Anda harus REMOVE atributnya.
  • Indeks bersifat . GSI di-update secara asinkron, jadi tiket yang baru resolved bisa sebentar masih muncul — baca GSI hanya mendukung eventual consistency. Jangan andalkan untuk "apakah tiket ini open sekarang".
  • Perhatikan atribut yang di-. Query pada indeks hanya mengembalikan atribut yang diproyeksikan ke dalamnya. Jika dashboard butuh subject dan priority, project mereka — atau bayar GetItem ekstra untuk item dasar penuh.
  • GSI dan LSI bisa sparse — tuasnya sama: hilangkan sort key indeks pada item yang tidak ingin diindeks. GSI biasanya lebih cocok: Anda bisa menambahkannya setelah tabel dibuat dan memberinya skema key serta kapasitas sendiri. GSI vs. LSI merinci trade-off-nya.

Sparse index adalah salah satu ide tertua dalam model. Paper Amazon Dynamo 2007 membangun store di sekitar melayani access pattern ber-volume tinggi yang diketahui dengan murah.

Sparse index tepat itu: bentuk key sehingga query umum tidak membaca apa pun yang tidak dibutuhkannya.

Untuk membangun dan memeriksanya secara nyata, unduh DynoTable, arahkan ke tabel Anda, dan alihkan tampilan data ke GSI sparse Anda — saksikan subset berubah saat item mendapat dan kehilangan key indeks.

Diperbarui