Pemula6 menit baca

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 Scan membaca seluruh tabel, setiap kali. Ukuran, bukan jumlah hasil Anda, yang menentukan apa yang Anda bayar dan berapa lama.
  • FilterExpression adalah kebohongan tentang biaya. Ia berjalan setelah pembacaan dimeter, jadi mengembalikan 12 Item bisa menagih pembacaan 12 juta.
  • Sebuah Scan makin lambat saat Anda bertumbuh. Sebuah Query berkey tetap datar — ia menyentuh satu partition tak peduli sebesar apa tabelnya.
  • Solusinya hampir selalu pemodelan, bukan tuning. Jika Anda Scan untuk 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, payloadBytes

Misalkan 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 + filterQuery berkey
MembacaSetiap Item dalam tabelSatu partition, dipersempit SK
Kapasitas tertagihSeluruh tabel, sebelum filterHanya Item dalam irisan Anda
Contoh kita~250.000 RCU (~500 MB)beberapa ratus RCU (~2 MB)
LatensiTumbuh dengan ukuran tabelDatar saat tabel bertumbuh
Jumlah hasilTak menentukan apa pun soal biayaCocok 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.

YaTidakYaTidakPerlu membaca ItemTahu partition key-nya?Query satu partitionBisakah GSI me-key-nya?Tambah GSI, lalu QueryScan pilihan terakhir

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.

Diperbarui