Kunci Sortir Tanpa Bantalan di DynamoDB
String DynamoDB diurutkan secara leksikografis — satu karakter pada a
waktu, kiri ke kanan — bukan secara numerik. Jadi "10" mendarat sebelum "2", karena
"1" hadir sebelum "2". Zero-padding dengan lebar tetap adalah cara Anda membuat string
pesanan cocok dengan urutan numerik.
Mengapa "10" mengurutkan sebelum "2" di kunci pengurutan DynamoDB?
Karena string DynamoDB dibandingkan secara leksikografis berdasarkan urutan byte UTF-8, bukan secara numerik. Byte untuk "1" mendahului "2", jadi "10" mendarat sebelum "2". Padukan setiap angka ke lebar tetap dengan angka nol di depannya — "2" menjadi "0000000002" — dan urutan string kemudian cocok dengan urutan numerik dengan tepat.
- Urutan leksikografis: angka yang disimpan sebagai string diurutkan seperti kata.
"100","11","2"adalah perintah yang diberikan DynamoDB kepada Anda — bukan yang Anda maksudkan. - Perbaikannya: masukkan setiap angka ke lebar tetap dengan nol di depannya, jadi
"2"menjadi"0000000002". Sekarang urutan leksikografis dan numerik setuju. - Pilih lebar satu kali: sesuaikan dengan nilai terbesar yang pernah Anda simpan, lalu tambahkan beberapa digit. Mengubah lebarnya nanti berarti menulis ulang setiap kunci.
- Descending gratis: untuk mengurutkan tinggi ke rendah (kotak peringkat), simpan
maxValue - value, juga tanpa bantalan — DynamoDB tidak memiliki pengurutan per atribut arah.
Mengapa kunci pengurutan string mengkhianati Anda
Berasal dari SQL, ORDER BY score DESC pada kolom integer "berfungsi" -
mesin mengetahui kolomnya numerik. DynamoDB tidak memiliki kemewahan seperti itu
kunci yang bukan tipe Number.
DynamoDB membandingkan kunci pengurutan string (S) berdasarkan urutan byte UTF-8, sesuai dengan
Dokumentasi kunci pengurutan AWS.
Byte, bukan besaran. "9" (0x39) mengungguli "10" karena byte pertamanya mengalahkan
"1" (0x31). Panjangnya tidak relevan — hanya byte pertama yang berbeda yang menentukan.
Itulah langkahnya: saat sebuah angka berada di dalam kunci pengurutan string, semuanya
Query yang berjalan dalam rentang tersebut mengembalikan baris dalam urutan yang terlihat acak-acakan.
Buat kunci pengurutan papan peringkat
Ambil papan peringkat arcade musiman. Satu per musim berlaku setiap lari pemain, dan Anda ingin skor tertinggi terlebih dahulu.
Modelkan dengan dalam satu koleksi item:
leaderboardId(kunci partisi) — mis.SEASON#2026-SPRING.rankKey(kunci pengurutan) — skor dengan bantalan nol ditambah pemecah tiebreak.
Upaya pertama yang naif menyimpan skor mentah sebagai string:
| leaderboardId | rankKey | playerHandle |
|---|---|---|
| SEASON#2026-SPRING | "9" | quickdraw |
| SEASON#2026-SPRING | "10" | ace_pilot |
| SEASON#2026-SPRING | "1500" | nightowl |
| SEASON#2026-SPRING | "240" | bytecrash |
Query di SEASON#2026-SPRING mengembalikannya dalam urutan byte ini:
"10", "1500", "240", "9". Lari 9 poin berada di posisi terakhir dan
Lari 1500 poin terkubur di tengah. Tidak berguna untuk papan peringkat.
Bantalan dengan lebar tetap
Pilih lebar yang cukup lebar untuk skor terbesar yang pernah Anda rekam, lalu pad kiri dengan angka nol. Katakanlah skor dibatasi hingga sepuluh juta — itu berarti delapan digit, jadi gunakan sepuluh digit untuk ruang kepala:
| leaderboardId | rankKey | playerHandle |
|---|---|---|
| SEASON#2026-SPRING | "0000000009" | quickdraw |
| SEASON#2026-SPRING | "0000000010" | ace_pilot |
| SEASON#2026-SPRING | "0000000240" | bytecrash |
| SEASON#2026-SPRING | "0000001500" | nightowl |
Sekarang setiap kunci memiliki panjang yang sama, jadi perbandingan byte demi byte dan numerik
perbandingan menghasilkan urutan yang sama. Query menaik menghasilkan 9, 10, 240, 1500. Perhitungannya akhirnya cocok dengan byte.
Lebarnya adalah pintu satu arah. Jika Anda menambahkan hingga sepuluh digit dan skor kemudian melebihi
itu, nilai 11 digit mengurutkan sebelum menjadi 10 digit — memecah ulang semuanya —
dan memperbaikinya berarti menulis ulang setiap rankKey yang ada. Penyediaan lebar yang berlebihan;
biayanya hanya beberapa byte.
Sortir descending: simpan selisihnya
Papan peringkat menginginkan skor tertinggi terlebih dahulu. DynamoDB dapat membaca kunci pengurutan
maju atau mundur dengan ScanIndexForward: false, jadi descending biasanya a
tanda waktu baca — raihlah itu terlebih dahulu.
Namun ketika satu koleksi item harus melayani arah pengurutan campuran, atau Anda menginginkannya
skor teratas secara fisik terlebih dahulu terlepas dari bendera yang dibaca, balikkan nomor itu sendiri.
Simpan maxValue - score, dengan bantalan nol dengan lebar yang sama:
| score | inverted (9999999999 - score) | rankKey |
|---|---|---|
| 1500 | 9999998499 | "9999998499" |
| 240 | 9999999759 | "9999999759" |
| 10 | 9999999989 | "9999999989" |
| 9 | 9999999990 | "9999999990" |
Menaikkan urutan byte di atas nilai yang dibalik sekarang menghasilkan skor asli
tinggi ke rendah: 1500, 240, 10, 9. Caranya ada di
Makalah Amazon Dynamo 2007's
spirit - kunci adalah byte buram, jadi Anda mengkodekan maksud ke dalam byte.
Tambahkan pemecah dasi
Dua pemain bisa seri. Skor yang empuk bertabrakan dengan tombol pengurutan, dan yang kedua write akan menimpa yang pertama (PK + SK yang sama). Tambahkan akhiran unik untuk masing-masingnya run adalah item yang berbeda dan ikatannya diselesaikan secara deterministik:
rankKey = "<paddedScore>#<paddedTimestamp>#<playerId>"Misalnya "0000001500#0000001719100800#p_8842". Skor yang sama, sebelumnya
stempel waktu memenangkan slot yang lebih tinggi — masukkan stempel waktu juga, atau stempel waktu tersebut akan diperkenalkan kembali
bug sebenarnya yang baru saja Anda perbaiki.
Di DynoTable, Anda dapat menelusuri papan peringkat musim yang diurutkan berdasarkan rankKey dengan bantalan nol
dan lihat nilai yang diisi menyejajarkan baris dengan benar — buktikan bahwa lebarnya tepat
sebelum Anda mengirimkannya.
Merakit kunci komposit itu dengan tangan, mudah untuk mengetahui lebarnya. Menghasilkan
KeyConditionExpression untuk Query "musim terbaik" di
pembuat ekspresi mempertahankan begins_with /
Sintaks between jujur saat Anda bereksperimen dengan lebar.
<gambar kelas="doc-media-placeholder" jenis data="tangkapan layar" data-src="docs/guide-dynamodb-zero-padding-sort-leaderboard.png"
Jebakan yang harus dihindari
- Padding terlalu sempit. Seluruh skema akan diciutkan saat nilai pertama kali dimasukkan melebihi lebarnya. Ukuran untuk kasus terburuk, lalu tambahkan angka.
- Lupa tanda baca. Jika Anda hanya membaca descending,
ScanIndexForward: falsemungkin yang Anda butuhkan — jangan menggunakan kunci terbalik ketika sebuah bendera melakukannya. - Lebar campuran dalam satu koleksi. Setiap kunci yang berbagi rentang pengurutan harus menggunakan lebar yang sama. Migrasi yang memasukkan baris-baris baru tetapi bukan baris-baris lama akan menyisipkannya salah.
- Mengisi segmen yang salah. Di kunci komposit, mengisi setiap segmen numerik yang berpartisipasi dalam pengurutan — skor dan stempel waktu keduanya, bukan hanya skor.
Langkah selanjutnya
Zero-padding adalah salah satu alat yang lebih luas
desain tombol sortir toolkit; pasangkan dengan
koleksi item ketika Anda membebani kunci secara berlebihan untuk menyajikan beberapa
pola, dan bersandar pada Query yang tepat, bukan a
Scan setelah urutannya benar.
Coba DynoTable untuk menelusuri tabel sebenarnya dan melihat pengurutan tanpa bantalan Anda kunci disusun dalam urutan numerik sebelum Anda mengirimkan skema.