Menengah5 menit baca

Denormalisasi di DynamoDB

Datang dari SQL, denormalisasi terdengar seperti dosa — data terduplikasi, tanpa satu sumber kebenaran. Di DynamoDB itulah inti seluruhnya. Tidak ada join, jadi Anda menyalin data terkait ke item yang membutuhkannya dan membacanya kembali sekali jalan.

Apa itu denormalisasi di DynamoDB?

Denormalisasi di DynamoDB berarti menyalin data terkait ke item yang membacanya, sehingga sebuah query tunggal mengembalikan semuanya sekali jalan. Karena DynamoDB tidak punya join, Anda melakukan pre-join saat penulisan alih-alih menjahit tabel bersama saat pembacaan. Trade-off-nya adalah kebasian — hanya duplikasi nilai yang jarang berubah.

  • Tidak ada join berarti Anda pre-join saat penulisan. Simpan nilai terkait pada item yang membacanya, sehingga sebuah query tak pernah perlu lookup kedua.
  • Dua rasa. Embed data bersarang dalam sebuah complex attribute pada satu item, atau duplikasi sebuah nilai di banyak item.
  • Jebakannya adalah kebasian. Saat sumbernya berubah, setiap salinan salah sampai Anda menyebar pembaruannya. Hanya duplikasi nilai yang jarang berubah.
  • Ia membeli baca, bukan tulis. Anda menukar lebih banyak (dan lebih hati-hati) penulisan demi pembacaan single-request yang murah.

Mengapa tidak ada join untuk diandalkan

Sebuah JOIN relasional merakit ulang baris yang dinormalisasi saat baca. DynamoDB tidak punya join — sebuah Query membaca satu item collection dan mengembalikan persis apa yang tersimpan di sana. Tidak ada yang menjahit dua tabel bersama untuk Anda.

Jadi data harus sudah terbentuk untuk pembacaannya. Jika sebuah layar butuh sebuah post dan nama penulisnya, nama itu harus tinggal di suatu tempat yang sudah disentuh pembacaan post. Paper Amazon Dynamo 2007 membuat trade ini eksplisit: lepaskan fitur relasional demi pembacaan yang dapat diprediksi, single-digit-millisecond pada skala.

Pola 1 — embed dengan complex attribute

Atribut DynamoDB bisa menampung map dan list bersarang, bukan hanya skalar. Jadi satu bentuk umum denormalisasi adalah menyumpalkan sebuah objek anak langsung di dalam item induknya alih-alih memberinya item sendiri.

Sebuah post dengan tag-nya dan sebuah snapshot penulis kecil, semua dalam satu item:

PKSKauthortags
POST#9f3META{id: U#12, name: "Mara Vance"}["dynamodb","aws"]

Satu GetItem mengembalikan post, tag, dan blok penulis bersama. Tanpa pembacaan kedua. Ini bagus untuk data yang dimiliki oleh induk dan terbatas ukurannya — segenggam tag, satu snapshot penulis.

Batas yang harus dihormati: satu item DynamoDB maksimal 400 KB, nama dan nilai atribut termasuk (Service Quotas). Embed sebuah list tak terbatas (setiap komentar pada post viral) dan Anda akan melampauinya.

Pola 2 — duplikasi sebuah nilai di banyak item

Kasus blog adalah contoh buku teks. Anda mendaftarkan post dan ingin setiap baris menampilkan nama tampilan penulis — tapi Anda tidak mau pembacaan kedua per post untuk mengambilnya.

Jadi Anda menulis nama penulis ke setiap item post saat post dibuat:

PKSKauthorIdauthorNametitle
POST#9f3METAU#12"Mara Vance""Modeling 1:N"
POST#a71METAU#12"Mara Vance""Sparse GSIs"
POST#b04METAU#88"Lio Tan""Query vs Scan"

Kini Query PK begins_with "POST#" (atau sebuah GSI atas post) merender seluruh daftarnya — judul dan penulis — tanpa lookup per-baris. Nama penulis didenormalisasi: salinan kanonik tinggal di USER#12, dan setiap post membawa salinannya sendiri.

Trade-nya tepat di sana. Anda mengubah pembacaan N+1 menjadi satu pembacaan, dengan biaya menyimpan "Mara Vance" di N+1 tempat.

Embed vs. duplikasi — yang mana

Embed (complex attribute)Duplikasi (salin di banyak item)
Bentukanak bersarang dalam induknilai sama di banyak item
Terbaik untukdata terbatas, dimiliki-induknilai bersama yang banyak item tampilkan
Bacasatu GetItemsatu Query
Biaya updatetulis ulang satu item induksebar ke setiap salinan
Risiko ukuranbatas item 400 KBtidak ada per item

Jangkau embed saat anaknya hanya pernah muncul bersama induknya. Jangkau duplikasi saat banyak item independen perlu menampilkan nilai bersama yang sama.

Jebakannya: salinan basi

Inilah bagian yang menggigit. Mara mengganti nama dirinya menjadi "Mara V." Anda memperbarui USER#12. Setiap item post masih mengatakan "Mara Vance" sampai Anda pergi memperbaikinya.

Jadi memperbarui sebuah nilai terduplikasi adalah penulisan fan-out, bukan satu baris. Anda meng-query setiap item terdampak lalu menulis ulang masing-masing — idealnya dijaga agar Anda hanya menyentuh baris yang masih memegang nilai lama:

UPDATE POST#9f3
SET authorName = "Mara V."
WHERE authorName = "Mara Vance"

Anda bisa menyusun SET kondisional terhadap authorName itu di Expression Builder dan menyalin UpdateExpression dan ConditionExpression yang dihasilkan langsung ke kode Anda.

Fan-out itu sendiri adalah satu penulisan per item: query post penulis, lalu keluarkan pembaruannya. Urutannya:

"DynamoDB"App"DynamoDB"App"Update nama USER"Query post penulis""POST"Update tiap authorName"

Biaya menduplikasi data: setiap perubahan pada sumber adalah sebuah query plus satu penulisan per salinan.

Inilah mengapa aturannya adalah hanya duplikasi nilai yang jarang berubah. Sebuah nama tampilan, tingkat paket, label kategori — boleh. Sebuah penghitung langsung atau field yang sering disunting — jangan; fan-out-nya akan melahapmu hidup-hidup.

Kapan normalisasi tetap menang

Jika sebuah nilai sering berubah, atau satu item dibaca oleh pola yang benar-benar tak terprediksi, biarkan ia ternormalisasi dan terima pembacaan ekstra. Denormalisasi adalah optimasi untuk pola akses yang diketahui, read-heavy — bukan default untuk diterapkan di mana-mana. Pre-join pembacaan yang sungguh Anda jalankan, dan biarkan sisanya.

Untuk memutuskan di mana atribut terduplikasi ini tinggal, modelkan pola akses lebih dulu — lihat single-table design dan, untuk sisi baca dari trade-nya, Query vs Scan.

Unduh DynoTable untuk memeriksa tabel terdenormalisasi, mendeteksi salinan mana yang telah menyimpang, dan menjalankan pembaruan fan-out terhadap data Anda sendiri.

Diperbarui