Projection Expression DynamoDB
Sebuah projection expression adalah SELECT col1, col2-nya DynamoDB: daftar
nama atribut yang dipisah koma yang memberi tahu GetItem, Query, atau Scan
untuk mengembalikan hanya atribut itu alih-alih seluruh Item.
Apakah projection expression DynamoDB mengurangi biaya baca?
Tidak. ProjectionExpression memangkas payload respons, bukan read capacity yang ditagihkan. DynamoDB membaca item penuh dari penyimpanan, menghitung berdasarkan ukuran item di disk, lalu membuang atribut yang tidak Anda sebut sebelum dikirim keluar. Untuk benar-benar memangkas biaya baca, gunakan covering sebagai gantinya.
- Ia memangkas payload, bukan biaya baca. DynamoDB membaca (dan menagih) Item
penuh dari penyimpanan, lalu menjatuhkan atribut yang tak Anda sebut dalam
perjalanan keluar.
ProjectionExpressionadalah optimasi jaringan, bukan optimasi kapasitas. - Ia adalah cara Anda mengambil subset publik. Sebut beberapa atribut yang boleh dilihat caller; sisanya tak pernah meninggalkan tabel.
- Gunakan placeholder
#nameuntuk apa pun yang mungkin reserved. Nama atribut polos dalam expression bentrok dengan ~570 reserved word DynamoDB dan menggagalkan request. - Untuk penghematan baca nyata, gunakan covering index. Sebuah GSI yang memproyeksikan hanya kolom yang Anda butuh dibaca pada ukurannya (yang lebih kecil) sendiri.
Apa yang sebenarnya ia hemat
Datang dari SQL, Anda berasumsi SELECT a, b men-scan lebih sedikit daripada
SELECT *. Di DynamoDB intuisi itu salah.
Capacity unit untuk sebuah pembacaan dihitung
dari ukuran Item pada disk, dibulatkan ke atas ke 4 KB berikutnya — sebelum
projeksi diterapkan. AWS eksplisit: sebuah ProjectionExpression tak mengubah read
capacity yang dikonsumsi sebuah request.1
Jadi sebuah projeksi menghemat dua hal, keduanya nyata tetapi keduanya di hilir pembacaan:
- Byte melintasi kabel. Item 6 KB yang dikembalikan sebagai dua atribut kecil
adalah respons mungil. Pada sebuah
Queryyang mengembalikan ratusan Item, itu menumpuk cepat. - Pekerjaan sisi-klien. Lebih sedikit untuk dideserialisasi, lebih sedikit ditahan di memori, lebih sedikit bocor ke log atau respons API secara tak sengaja.
Yang tidak ia hemat adalah RCU. Itulah footgun-nya: orang meraih projeksi untuk memangkas tagihan, tak melihat perubahan, dan menyimpulkan DynamoDB rusak. Ia tidak — Anda mengukur tuas yang salah.
Proyeksikan profil user publik
Misalkan Anda menjalankan direktori user. Setiap profil adalah satu Item, berkey agar Anda bisa mengambil seseorang berdasarkan handle:
PK = "PROFILE#ada" (partition key)
SK = "PROFILE#ada" (sort key — collection ber-Item-tunggal)
Item-nya gemuk. Ia membawa wajah publik akun plus tumpukan atribut privat dan operasional:
{
"PK": "PROFILE#ada",
"SK": "PROFILE#ada",
"displayName": "Ada L.",
"avatarUrl": "https://cdn.example.com/u/ada.png",
"bio": "Builds things.",
"emailAddress": "ada@example.com",
"passwordResetToken": "…",
"billingCustomerId": "cus_…",
"lastLoginIp": "…",
"internalRiskScore": 0.02
}Kartu profil publik butuh tiga field. Mengambil seluruh Item berarti emailAddress,
lastLoginIp, dan internalRiskScore berkelana ke konteks yang seharusnya tak
pernah melihatnya. Sebut hanya subset publiknya:
GetItem PK = "PROFILE#ada" SK = "PROFILE#ada"
ProjectionExpression: displayName, avatarUrl, bio
Responsnya membawa tiga atribut. Yang privat tetap di tabel — tidak difilter keluar oleh aplikasi Anda setelah tiba, melainkan tak pernah diserialisasi ke dalam respons sama sekali. Itulah kemenangan keamanannya, dan itu yang sulit dibatalkan begitu sebuah rahasia telah menyeberangi batas.
Anda bisa merakit dan menyalin request persisnya — nama, placeholder, dan panggilan
SDK — di DynamoDB Expression Builder, yang
memancarkan ProjectionExpression dan peta ExpressionAttributeNames untuk Anda.
Escape reserved word dengan placeholder #
Di sinilah projeksi yang bersih meledak. DynamoDB memesan daftar panjang kata —
name, status, comment, size, timestamp, dan ratusan lainnya.2
Jika atribut yang Anda proyeksikan salah satunya, nama mentah dalam expression
ditolak.
Misalkan profil juga punya atribut status ("active", "suspended"). Ini gagal:
ProjectionExpression displayName, status
status adalah reserved. Solusinya adalah expression attribute name —
placeholder ber-prefiks # yang dipetakan ke nama nyata:
ProjectionExpression displayName, #s
ExpressionAttributeNames { "#s": "status" }
Mekanisme yang sama menjangkau atribut bersarang. Untuk menarik satu field dari sebuah map, atau satu elemen dari list, gunakan sintaks document-path — dan placeholder-kan setiap segmen, karena salah satunya bisa reserved:
ProjectionExpression #addr.#city, tags[0]
ExpressionAttributeNames { "#addr": "address", "#city": "city" }
Aturan praktis: placeholder-kan segalanya. Anda tak pernah harus mengingat reserved word ~570 mana yang sedang Anda injak, dan expression-nya terbaca sama entah bagaimana.
Kapan covering index mengalahkan projeksi
Jika Anda benar-benar perlu memangkas biaya baca — bukan hanya payload — tuasnya
adalah Global Secondary Index yang memproyeksikan hanya atribut yang Anda baca.
Sebuah GSI adalah salinan data terpisah; Anda memilih KEYS_ONLY, INCLUDE, atau
ALL untuk projeksinya.3 Index KEYS_ONLY atau INCLUDE yang sempit
secara fisik lebih kecil per Item, jadi sebuah Query terhadapnya dimeter pada
ukuran yang lebih kecil itu.
Itulah covering index: query dijawab sepenuhnya dari index, tanpa perjalanan balik ke tabel dasar. Gunakan ia saat pola baca yang hot hanya pernah butuh beberapa atribut dari Item besar.
ProjectionExpression | Covering GSI | |
|---|---|---|
| Memangkas payload | Ya | Ya |
| Memangkas biaya baca | Tidak | Ya — dibaca pada ukuran index |
| Penyimpanan ekstra | Tidak ada | Salinan kedua field yang diproyeksikan |
| Biaya tulis ekstra | Tidak ada | Penulisan berpropagasi ke index |
| Terbaik untuk | Menyembunyikan field privat; kemenangan kecil | Pembacaan hot beberapa field dari Item besar |
Trade-off-nya jujur: index membebani Anda penyimpanan dan write capacity untuk
menghemat read capacity. Layak untuk pembacaan sering atas irisan tipis dari Item
berat; tak layak untuk memangkas GetItem sekali-pakai. Lihat
GSI vs LSI untuk memilih tipe index, dan
kapan pembacaan GSI bisa basi sebelum
Anda menaruh satu di jalur hot.
Jebakan dan langkah berikutnya
- Jangan harapkan tagihan lebih kecil. Projeksi sendiri tak pernah mengubah RCU. Jika angkanya tak bergerak, itu perilaku yang terdokumentasi, bukan bug.
- Placeholder-kan reserved word.
nameataustatustelanjang dalam expression menggagalkan request —#-petakan ia. - Memproyeksikan atribut key itu gratis dan sering berguna — DynamoDB mengembalikannya murah, dan mereka membiarkan Anda mem-page atau mengambil ulang.
- Raih covering index hanya saat pola hot membaca beberapa field dari Item besar; timbang biaya tulis/penyimpanan dulu.
Bangun ProjectionExpression dan peta attribute-name-nya di
Expression Builder, dan
coba DynoTable untuk menjalankan projeksi ini terhadap tabel Anda
sendiri dan menyaksikan respons menyusut.
- AWS DynamoDB Developer Guide, Working with Read and Write Operations — read capacity didasarkan pada ukuran Item sebelum
ProjectionExpressionmana pun diterapkan. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ ↩ - AWS DynamoDB Developer Guide, Reserved Words in DynamoDB. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html ↩
- AWS DynamoDB Developer Guide, Attribute Projections (
KEYS_ONLY/INCLUDE/ALL). https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html ↩