Mengapa Scan DynamoDB Lambat dan Mahal
Sebuah Scan membaca setiap Item dalam tabel dan baru memfilter sesudahnya. Ia
adalah operasi yang Anda raih dari memori otot SQL, dan yang diam-diam membengkakkan
tagihan Anda sembari membuat latensi Anda lebih buruk daripada box RDS yang Anda
tinggalkan.
Mengapa Scan DynamoDB saya lambat dan mahal?
Sebuah Scan membaca setiap Item dalam tabel sebelum FilterExpression berjalan, sehingga Anda membayar untuk membaca seluruh tabel tak peduli seberapa sedikit baris yang dikembalikan, dan makin lambat seiring tabel bertumbuh. Solusinya hampir selalu Query berkey — modelkan pola akses di sekitar sebuah key agar DynamoDB hanya menyentuh satu partition, bukan segalanya.
- Sebuah
Scanmembaca seluruh tabel, setiap kali. Ukuran, bukan jumlah hasil Anda, yang menentukan apa yang Anda bayar dan berapa lama. FilterExpressionadalah kebohongan tentang biaya. Ia berjalan setelah pembacaan dimeter, jadi mengembalikan 12 Item bisa menagih pembacaan 12 juta.- Sebuah
Scanmakin lambat saat Anda bertumbuh. SebuahQueryberkey tetap datar — ia menyentuh satu partition tak peduli sebesar apa tabelnya. - Solusinya hampir selalu pemodelan, bukan tuning. Jika Anda
Scanuntuk menjawab pertanyaan rutin, Anda kehilangan sebuah key.
Apa yang sebenarnya dilakukan sebuah Scan
Datang dari SQL, SELECT * FROM events WHERE type = 'checkout' terasa gratis —
mesinnya punya index, atau tidak, tetapi entah bagaimana Anda mendapat baris balik.
Di DynamoDB tak ada query planner yang memutuskan itu untuk Anda.
Sebuah Scan menjelajahi seluruh tabel secara berurutan, 1 MB sekali waktu, dan
menyerahkan setiap halaman ke FilterExpression Anda. Apa pun yang ditolak filter
tetap dibaca, tetap dimeter, dan tetap ada di tagihan Anda. (AWS: Scanning tables)
Itulah jebakannya. Filter tampak seperti klausa WHERE, tetapi ia mengubah himpunan
hasil, tak pernah biayanya. Sebuah Scan mengonsumsi read capacity yang sama
terlepas ada atau tidaknya filter. (AWS: Scanning tables)
Hitung read unit-nya
DynamoDB memeter pembacaan dalam read capacity unit (RCU). Satu RCU membeli satu pembacaan strongly consistent dari Item hingga 4 KB; pembacaan eventually consistent berbiaya setengahnya. Item lebih besar membulat ke atas ke 4 KB berikutnya. (AWS: Read/write capacity mode)
Ambil tabel analitik, ProductEvents. Setiap baris adalah satu event yang dilacak:
PK = "TENANT#acme"
SK = "TS#2026-06-23T14:08:55Z#evt_9f3a"
attrs: eventType, sessionId, userId, payloadBytesMisalkan ia menampung 2.000.000 event, masing-masing ~1 KB, semua di bawah satu tenant sibuk. Anda ingin checkout hari ini. Langkah refleksifnya:
Scan ProductEvents
FilterExpression: eventType = "checkout"
Filter itu mungkin mengembalikan 40 baris. Tetapi Scan membaca seluruh 2.000.000
Item dulu. Pada ~1 KB masing-masing (1 RCU per 4 KB, eventually consistent ≈ 0,5 RCU
per 4 KB), Anda memeter sekitar 250.000 RCU — dan mem-page ~500 MB data — untuk
menyerahkan 40 Item.
Kini modelkan pola akses sebagai key dan Query ia sebagai gantinya:
Query ProductEvents
PK = "TENANT#acme"
AND SK begins_with "TS#2026-06-23"
Ini membaca hanya irisan yang cocok dari satu partition. Jika 40 baris checkout itu plus event hari itu lainnya berjumlah ~2 MB, Anda membayar ~2 MB pembacaan, bukan 500 MB. Jawaban sama, sepersekian kecil dari biayanya — dan latensi tetap datar saat tabel bertumbuh.
Scan vs Query, dimeter
| Scan + filter | Query berkey | |
|---|---|---|
| Membaca | Setiap Item dalam tabel | Satu partition, dipersempit SK |
| Kapasitas tertagih | Seluruh tabel, sebelum filter | Hanya Item dalam irisan Anda |
| Contoh kita | ~250.000 RCU (~500 MB) | beberapa ratus RCU (~2 MB) |
| Latensi | Tumbuh dengan ukuran tabel | Datar saat tabel bertumbuh |
| Jumlah hasil | Tak menentukan apa pun soal biaya | Cocok dengan yang Anda bayar |
Pelajaran yang dikodekan tabel: pada sebuah Scan, jumlah hasil Anda dan tagihan
Anda tak berkaitan. Pada sebuah Query, mereka saling melacak.
Putuskan sebelum Anda Scan
Sebagian besar Scan tak sengaja datang dari satu pertanyaan: bisakah saya menyebut
partition yang saya butuh? Jika ya, itu sebuah Query. Jika tidak, solusinya adalah
key, bukan filter yang lebih besar.
Ini keputusannya dalam bentuk alur.
Jalurnya hampir selalu berakhir di Query; Anda hanya jatuh ke Scan saat tak ada
key — yang ada maupun yang bisa ditambah — yang cocok dengan pola akses.
Jika polanya nyata dan berulang tetapi tabel dasar tak bisa me-key-nya, itu sinyal
untuk menambah Global Secondary Index agar pertanyaannya
menjadi sebuah Query. Memodelkan key Anda di sekitar pola akses Anda sejak awal
adalah seluruh permainannya — lihat
single-table design.
Tulis query berkey, bukan filter
Saat Anda memang butuh kondisi melampaui key, bangun ia dengan sengaja alih-alih
membuang segalanya ke dalam FilterExpression.
DynamoDB Expression Builder menghasilkan
KeyConditionExpression dan placeholder atribut untuk Anda, jadi partition dan sort
key yang melakukan penyempitan — sebelum DynamoDB memeter pembacaan, bukan sesudah.
KeyConditionExpression: PK = :tenant AND begins_with(SK, :day)
Kapan sebuah Scan sebenarnya baik-baik saja
Sebuah Scan tak dilarang — ia hanya default yang salah. Ia adalah alat yang tepat
saat Anda benar-benar bermaksud "baca semuanya":
- Ekspor sekali-pakai atau backfill yang dijalankan manual.
- Tabel config / lookup mungil yang seluruh tabelnya beberapa KB.
- Background job yang mem-page seluruh tabel dengan sengaja. Pecah itu lintas
worker dengan
Segment/TotalSegments— sebuah parallel scan — alih-alih satu crawl berurutan panjang. (AWS: Scanning tables)
Dan perhatikan PartiQL tak menyelamatkan Anda: SELECT * FROM ProductEvents WHERE eventType = 'checkout' tanpa predikat key dikompilasi langsung menjadi Scan. Ia
footgun yang sama dalam pakaian SQL. (Lihat Query vs Scan
untuk uraian lengkapnya.)
Saat Anda benar-benar butuh analitik lintas-Item — sebuah GROUP BY, JOIN,
agregat yang tak bisa diekspresikan DynamoDB — SQL Workbench DynoTable menjalankannya
di sisi-klien atas himpunan hasil yang terbatas, alih-alih menghantam tabel dengan
Scan penuh.
Langkah berikutnya
Perkirakan biaya kedua pola dengan kalkulator kapasitas, baca Query vs Scan untuk kontras tingkat-API, dan unduh DynoTable untuk menjalankan ini terhadap tabel Anda sendiri dan menyaksikan consumed capacity sendiri.