Cara Memodelkan Data di DynamoDB
Di SQL Anda memodelkan entitas dan relasi dulu, lalu mempercayakan pada query planner untuk merakit apa pun yang Anda minta belakangan. DynamoDB membalik itu. Anda memodelkan pembacaan yang sudah Anda tahu akan Anda lakukan, dan key ada untuk melayaninya.
Tidak ada engine join dan tidak ada planner yang memilih strategi saat runtime. Sebuah Query membaca satu partisi sepanjang satu key, dan itulah seluruh kontrak performanya. Jadi Anda mendesain key untuk pola akses yang diketahui, bukan untuk skema yang rapi.
AWS mengatakannya secara terus terang di panduan best-practices-nya: "you shouldn't start designing your schema until you know the questions it will need to answer."
Panduan ini menelusuri seluruh proses pada satu domain: sebuah leaderboard game multiplayer yang melacak pemain, match yang mereka mainkan, dan peringkat per-musim mereka. Kita bergerak dari sebuah daftar pertanyaan menuju sebuah skema key yang bekerja.
Bagaimana Anda memodelkan data di DynamoDB?
Modelkan pembacaan dulu, bukan tabel. Daftarkan setiap query yang aplikasi lakukan, lalu desain sebuah dan sehingga setiap pertanyaan teratasi menjadi satu Query atau GetItem. Ko-lokasikan item yang dibaca bersama, rentangi nilai di sort key, dan tambahkan sebuah GSI untuk pola akses apa pun yang tak bisa dilayani tabel dasar.
- Daftarkan pembacaan dulu, bukan tabel. Pertanyaan adalah spesifikasinya; kata bendanya adalah pengalih perhatian.
- Setiap pertanyaan harus satu
QueryatauGetItem. Jika sebuah pertanyaan butuh sebuahScan, modelnya salah. - Item yang ter-ko-lokasi berbagi sebuah ; apa pun yang Anda rentangi masuk ke .
- Sebuah pertanyaan yang tak bisa dijawab tabel dasar mendapat sebuah — jangan pernah sebuah
Scandengan filter.
Langkah 1 — Bingkai masalah sebagai pertanyaan, bukan tabel
Tahan dorongan untuk menggambar tabel players, matches, dan scores. Naluri itu adalah kebiasaan SQL, dan di sini itu salah. Alih-alih, tuliskan setiap pembacaan yang aplikasi benar-benar lakukan. Untuk leaderboard kita:
- Ambil profil satu pemain berdasarkan id.
- Daftarkan match terbaru seorang pemain, terbaru dulu.
- Tampilkan N pemain teratas untuk sebuah musim tertentu, diperingkat berdasarkan rating.
- Cari seorang pemain berdasarkan handle publiknya (mis. untuk URL profil).
Keempat pertanyaan ini — bukan kata bendanya — adalah spesifikasinya. Masing-masing harus teratasi menjadi satu Query (atau GetItem), karena itulah satu-satunya bentuk akses yang DynamoDB layani dengan murah pada skala.
Jika sebuah pertanyaan hanya bisa dijawab dengan men-scan tabel, modelnya salah, dan Anda akan merasakannya dalam latensi dan biaya — lihat Query vs Scan untuk mengapa sebuah Scan adalah jebakan yang harus dihindari.
Seluruh metodenya adalah sebuah pipeline pendek dan berurutan yang Anda jalankan sekali per domain:
Setiap langkah di bawah memetakan ke satu kotak: daftar, enumerasi, desain key, tambahkan index untuk sisanya, lalu validasi.
Langkah 2 — Pahami primitif yang Anda gunakan untuk memodelkan
Sebuah tabel punya sebuah partition key (PK) yang memilih partisi fisik mana yang item tinggali, dan sebuah sort key (SK) opsional yang mengurutkan item di dalam partisi itu.
Dokumen core-components AWS menyebut pasangan itu sebagai primary key item. Sebuah Query selalu menargetkan tepat satu nilai PK dan bisa me-range-scan atau memfilter SK — itulah seluruh perkakasnya.
Desain satu-partisi inilah yang memungkinkan DynamoDB menghantarkan pembacaan yang dapat diprediksi, latensi-rendah, dan terpartisi horizontal yang pertama dideskripsikan dalam paper Amazon Dynamo 2007.
Dua konsekuensi menggerakkan setiap keputusan di bawah:
- Item yang dibaca bersama harus berbagi sebuah partition key sehingga satu
Querymengembalikannya dalam satu request berbayar. - Apa pun yang ingin Anda rentangi (match terbaru, rating teratas) harus hidup di sort key, karena itulah satu-satunya atribut yang
Querybisa urutkan dan batasi.
Ketika sebuah pertanyaan butuh bentuk akses yang berbeda dari yang disediakan tabel dasar, Anda menambahkan sebuah Global Secondary Index — sebuah proyeksi-ulang tabel di bawah PK/SK berbeda.
(Untuk GSI versus Local Secondary Index, lihat GSI vs LSI.)
Langkah 3 — Desain key, satu pertanyaan pada satu waktu
Kita memakai satu tabel dengan atribut key generik yang di-overload — pendekatan single-table — karena seorang pemain dan match-nya dibaca bersama.
Ciptakan prefix Anda sendiri; di sini PLAYER#, MATCH#, dan SEASON# menandai tipe entitas di dalam key yang jika tidak akan generik.
Pertanyaan 1 dan 2 (profil + match terbaru) berbagi sebuah partisi, jadi keduanya menggantung dari PK yang sama:
| partitionId | rangeId | attributes |
|---|---|---|
| PLAYER#u8231 | PROFILE | handle, region, createdAt |
| PLAYER#u8231 | MATCH#2026-06-23T14 | result=win, ratingDelta=+18, mapId |
| PLAYER#u8231 | MATCH#2026-06-23T11 | result=loss, ratingDelta=-15, mapId |
Query partitionId = "PLAYER#u8231" mengembalikan profil dan setiap match dalam satu pembacaan. Untuk profil saja, GetItem.
Untuk match terbaru, rangeId begins_with "MATCH#" dengan ScanIndexForward = false menelusurinya terbaru-dulu — timestamp di sort key melakukan pengurutan secara cuma-cuma.
Pertanyaan 3 dan 4 tak bisa dijawab dari partisi itu — mereka berporos pada peringkat musim dan pada handle, tak satu pun yang merupakan PK dasar. Masing-masing mendapat sebuah GSI.
Kita menambahkan dua pasang atribut index generik — seasonPartition / seasonSort untuk index peringkat dan handlePartition / handleSort untuk index handle — diisi pada item profil yang sama (yang ditulis di Langkah 3, kini ditampilkan dengan atribut index-nya terisi):
| partitionId | rangeId | seasonPartition | seasonSort | handlePartition | handleSort |
|---|---|---|---|---|---|
| PLAYER#u8231 | PROFILE | SEASON#2026-Q2 | RATING#1842 | HANDLE#nighthawk | PLAYER#u8231 |
Kini Query index musim WHERE seasonPartition = "SEASON#2026-Q2" dengan ScanIndexForward = false mengembalikan pemain diperingkat berdasarkan rating — itulah leaderboard-nya.
Sebuah index kedua ber-key pada handlePartition = "HANDLE#…" menyelesaikan sebuah handle publik menjadi id pemain dalam satu pembacaan. Satu tabel fisik, empat pola akses satu-Query.
Sebuah catatan pada
RATING#1842: DynamoDB mengurutkan sort key secara leksikografis, bukan numerik, jadi sebuah rating harus di-zero-pad ke lebar tetap (RATING#01842) atau9akan terurut setelah1000. Ini adalah jebakan pemodelan klasik yang layak dibenahi sejak awal.
Langkah 4 — Validasi model di DynoTable
Sebuah skema key baru mendapat kepercayaan ketika Anda menyaksikan sebuah Query nyata mengembalikan tepat item yang Anda harapkan dan tidak lebih.
Buka tabel di DynoTable, jalankan query leaderboard terhadap index musim, dan konfirmasi partisi kembali diperingkat dan dibatasi — tanpa Scan, tanpa pengurutan di sisi klien.

Ketika Anda membangun condition expression untuk query-query ini — begins_with, seasonPartition = :p, binding placeholder :p — biarkan DynamoDB Expression Builder yang melakukannya.
Ia menghasilkan KeyConditionExpression, ExpressionAttributeNames, dan ExpressionAttributeValues, sehingga sebuah reserved word seperti result atau placeholder yang salah ketik tak pernah diam-diam merusak sebuah pembacaan.
Langkah 5 — Jebakan dan langkah berikutnya
Beberapa jebakan untuk diperiksa sebelum Anda mengirim model:
- Jangan memodelkan relasi yang tak pernah Anda baca bersama. Sebuah GSI per pertanyaan itu murah; sebuah GSI yang terbuang adalah biaya berulang. Tambahkan index dari daftar pertanyaan, bukan secara spekulatif.
- Awasi panas partisi. Jika satu PK (seorang pemain selebriti, satu musim panas) menyerap sebagian besar traffic, partisi itu bisa di-throttle. Sebar penulisan dengan sebuah suffix shard ketika sebuah key terbukti panas — AWS membahas ini di bawah desain partition-key.
- Zero-pad dan ISO-8601-kan segala yang numerik atau temporal di sebuah sort key, agar pengurutan leksikografis cocok dengan urutan yang Anda maksud.
- Pertanyaan baru = key atau index baru, jangan pernah
Scan. Ketika sebuah pola akses yang benar-benar baru muncul belakangan, perluas key-nya; jangan menutupinya dengan sebuah filter.
Modelkan pertanyaannya dulu, desain key sehingga masing-masing menjadi satu Query, lalu buktikan.
Untuk memulai lebih cepat pada langkah tengahnya, alat Single-Table Design gratis mengubah daftar pola akses seperti ini menjadi sebuah rencana PK/SK/GSI, dengan contoh item dan petunjuk biaya.
Coba DynoTable untuk menjelajahi tabel Anda, menjalankan query-query ini terhadap tabel dasar dan GSI berdampingan, dan menyaksikan pola akses yang Anda desain mengembalikan tepat apa yang Anda rencanakan. Dan untuk pertanyaan yang tidak Anda modelkan, SQL Workbench-nya menjalankan JOIN, GROUP BY, dan agregat sungguhan di sisi klien.


