Pemula5 menit baca

Projection expression DynamoDB

Projection expression adalah SELECT col1, col2 DynamoDB: daftar nama dipisahkan koma yang memberitahu 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 kapasitas baca yang ditagih. DynamoDB membaca item penuh dari storage, mengukur pada ukuran on-disk-nya, lalu menjatuhkan atribut yang tidak Anda namai di jalan keluar. Untuk benar-benar memotong biaya baca, pakai covering sebagai gantinya.

  • Ia memangkas payload, bukan biaya baca. DynamoDB membaca (dan menagih) item penuh dari storage, lalu menjatuhkan atribut yang tidak Anda namai di jalan keluar. ProjectionExpression adalah optimasi jaringan, bukan kapasitas.
  • Itulah cara Anda mengambil subset publik. Namai sedikit atribut yang boleh dilihat pemanggil; sisanya tidak pernah meninggalkan tabel.
  • Pakai placeholder #name untuk apa pun yang mungkin reserved. Nama atribut polos di expression bertabrakan dengan ~570 reserved word DynamoDB dan gagal request.
  • Untuk penghematan baca nyata, pakai covering index. yang memproyeksikan hanya kolom yang Anda butuhkan dibaca pada ukuran (lebih kecil) sendiri.

Apa yang sebenarnya dihemat

Datang dari SQL, Anda menganggap SELECT a, b men-scan lebih sedikit daripada SELECT *. Di DynamoDB intuisi itu salah. Capacity unit untuk baca dihitung dari ukuran item di disk, dibulatkan ke 4 KB berikutnya — sebelum proyeksi diterapkan. AWS eksplisit: ProjectionExpression tidak mengubah kapasitas baca yang dikonsumsi request.1

Jadi proyeksi menghemat dua hal, keduanya nyata tetapi keduanya di hilir baca:

  • Byte di wire. Item 6 KB yang dikembalikan sebagai dua atribut kecil adalah respons kecil. Pada Query yang mengembalikan ratusan item, itu cepat menumpuk.
  • Kerja sisi klien. Lebih sedikit untuk di-deserialize, lebih sedikit di memori, lebih sedikit untuk bocor ke log atau respons API secara tidak sengaja.

Apa yang tidak dihemat adalah RCU. Itulah jebakannya: orang menjangkau proyeksi untuk memotong tagihan, tidak melihat perubahan, dan menyimpulkan DynamoDB rusak. Tidak — Anda mengukur tuas yang salah.

Project profil pengguna publik

Katakan Anda menjalankan direktori pengguna. Tiap profil adalah satu item, di-key agar Anda bisa mengambil orang by handle:

PK = "PROFILE#ada"      (partition key)
SK = "PROFILE#ada"      (sort key — single-item collection)

Itemnya 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 pergi ke konteks yang tidak boleh melihatnya. Namai hanya subset publik:

GetItem  PK = "PROFILE#ada"  SK = "PROFILE#ada"
ProjectionExpression: displayName, avatarUrl, bio

Respons membawa tiga atribut. Yang privat tetap di tabel — bukan difilter app Anda setelah tiba, tetapi tidak pernah di-serialize ke respons sama sekali. Itulah kemenangan keamanan, dan yang sulit di-undo setelah secret sudah menyeberangi batas.

Anda bisa menyusun dan menyalin request exact ini — name, placeholder, dan panggilan SDK — di DynamoDB Expression Builder, yang mengeluarkan map ProjectionExpression dan ExpressionAttributeNames untuk Anda.

Tambah atau hapus field di preset di bawah untuk menyaksikan ProjectionExpression berubah — hanya atribut yang didaftar yang kembali:

Bangun request Anda
Kode yang dihasilkan
new QueryCommand({
  "TableName": "AuditLog",
  "KeyConditionExpression": "#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)",
  "ProjectionExpression": "#proj0, #proj1, #proj2",
  "ExpressionAttributeNames": {
    "#hashKey": "pk",
    "#rangeKey": "sk",
    "#proj0": "action",
    "#proj1": "actor",
    "#proj2": "createdAt"
  },
  "ExpressionAttributeValues": {
    ":hashKeyValue": {
      "S": "TENANT#acme"
    },
    ":rangeKeyValue": {
      "S": "EVENT#"
    }
  }
})

Escape reserved word dengan placeholder #

Proyeksi bersih meledak pada reserved word. DynamoDB mereservasi daftar panjang kata — name, status, comment, size, timestamp, dan ratusan lagi.2 Jika atribut yang Anda project adalah salah satunya, nama mentah di expression ditolak.

Misalkan profil juga punya atribut status ("active", "suspended"). Ini gagal:

ProjectionExpression   displayName, status

status reserved. Perbaikannya adalah expression attribute name — placeholder berawalan # yang dipetakan ke nama nyata:

ProjectionExpression       displayName, #s
ExpressionAttributeNames   { "#s": "status" }

Mekanisme yang sama menjangkau atribut nested. Untuk menarik satu field dari map, atau satu elemen list, pakai sintaks document-path — dan placeholder setiap segmen, karena mana pun bisa reserved:

ProjectionExpression       #addr.#city, tags[0]
ExpressionAttributeNames   { "#addr": "address", "#city": "city" }

Aturan praktis: placeholder semuanya. Anda tidak pernah harus mengingat mana dari ~570 reserved word yang Anda injak, dan expression dibaca sama bagaimanapun. Dan jika Anda lebih suka tahu nama mana yang benar-benar masalah, tempel ke reserved-words checker — ia menandai tabrakan dan mengeluarkan map alias ExpressionAttributeNames.

Kapan covering index mengalahkan proyeksi

Jika Anda benar-benar perlu memotong biaya baca — bukan sekadar payload — tuasnya adalah Global Secondary Index yang memproyeksikan hanya atribut yang Anda baca. GSI adalah salinan data terpisah; Anda memilih KEYS_ONLY, INCLUDE, atau ALL untuk proyeksinya.3 Indeks KEYS_ONLY atau INCLUDE sempit secara fisik lebih kecil per item, jadi Query terhadapnya diukur pada ukuran lebih kecil itu.

Itulah covering index: query dijawab sepenuhnya dari indeks, tanpa trip kembali ke tabel dasar. Pakai saat pattern baca panas hanya pernah butuh sedikit atribut dari item besar.

ProjectionExpressionCovering GSI
Potong payloadYaYa
Potong biaya bacaTidakYa — baca pada ukuran indeks
Storage ekstraTidak adaSalinan kedua field yang diproyeksikan
Biaya tulis ekstraTidak adaWrite menyebar ke indeks
Terbaik untukMenyembunyikan field privat; kemenangan kecilBaca panas sedikit field dari item besar

Indeks menelan storage dan kapasitas tulis untuk menghemat kapasitas baca. Sebanding untuk baca sering irisan tipis dari item berat; tidak sebanding untuk mengurangi GetItem sekali. Lihat GSI vs LSI untuk memilih tipe indeks, dan saat baca GSI bisa basi sebelum Anda menaruhnya di hot path.

Jebakan dan langkah selanjutnya

  • Jangan harapkan tagihan lebih kecil. Proyeksi saja tidak pernah mengubah RCU. Jika angkanya tidak bergerak, itu perilaku terdokumentasi, bukan bug.
  • Placeholder reserved word. name atau status telanjang di expression gagal request — #-map.
  • Selalu sertakan atribut key — mereka menambah payload diabaikan dan membiarkan Anda memaginasi atau re-fetch item.
  • Jangkau covering index hanya saat pattern panas membaca sedikit field dari item besar; timbang biaya tulis/storage dulu.

Bangun ProjectionExpression dan map attribute-name-nya di Expression Builder, dan coba DynoTable untuk menjalankan proyeksi ini terhadap tabel Anda sendiri dan menyaksikan respons menyusut.


  1. Panduan Pengembang AWS DynamoDB, Using projection expressions in DynamoDB — kapasitas baca dihitung dari ukuran item sebelum ProjectionExpression apa pun diterapkan. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.ProjectionExpressions.html
  2. Panduan Pengembang AWS DynamoDB, Reserved Words in DynamoDB. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
  3. Panduan Pengembang AWS DynamoDB, Attribute Projections (KEYS_ONLY / INCLUDE / ALL). https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html

Diperbarui