Cara COUNT, SUM dan Agregasi di DynamoDB
DynamoDB punya tepat satu agregat bawaan: menghitung item yang cocok dengan Select=COUNT. Tidak ada SUM, AVG, MIN, atau MAX native. Dan bahkan count yang
bisa Anda dapat membaca (dan menagih) setiap item yang ia hitung. Panduan ini membahas
apa yang sebenarnya didukung, aproksimasi yang orang jangkau, dan bagaimana menjalankan
COUNT/SUM/AVG nyata atas sebuah tabel saat Anda membutuhkannya.
Bisakah DynamoDB melakukan SUM, COUNT, dan fungsi agregat?
Kebanyakan tidak. Satu-satunya agregat bawaan DynamoDB adalah Select=COUNT, yang mengembalikan hitungan item-yang-cocok tapi tetap membaca (dan menagih) setiap item. Tak ada SUM, AVG, MIN, atau MAX native, dan PartiQL pun tak menambahkan apa pun. Untuk agregat nyata dengan GROUP BY, lipat ia di aplikasi Anda, pelihara sebuah counter, atau jalankan SQL di Workbench DynoTable.
Select=COUNTmengembalikan jumlah item yang cocok, tapi DynamoDB tetap membaca setiap item untuk menghasilkannya — Anda membayar biaya bacaScan/Querypenuh, bukan sebuah biaya "hitung" yang murah.- Tak ada
SUM,AVG,MIN, atauMAXnative. Operasi baca DynamoDB mengembalikan item; mereka tak melipatnya menjadi sebuah angka. PartiQL pun tak menambahkan agregat. DescribeTable.ItemCountgratis tapi aproksimatif dan diperbarui hanya "kira-kira setiap enam jam" — cukup untuk sebuah petak dasbor, salah untuk apa pun yang eksak.- Untuk
COUNT/SUM/AVG/MIN/MAXeksak (denganGROUP BY), agregasi di aplikasi Anda, pelihara sebuah counter, atau jalankan ia di SQL Workbench DynoTable (di bawah).
Menghitung item: Select=COUNT
Baik Query maupun Scan menerima sebuah parameter Select. Setel ia ke COUNT dan
responsnya membawa hitungannya alih-alih item-item:
aws dynamodb scan \
--table-name Orders \
--select COUNT \
--filter-expression "#s = :open" \
--expression-attribute-names '{"#s":"status"}' \
--expression-attribute-values '{":open":{"S":"OPEN"}}'Responsnya memberi Anda dua angka (AWS: Counting the items in the results):
Count— "jumlah item yang tersisa, setelah sebuah filter expression (jika ada) diterapkan."ScannedCount— "jumlah item yang dievaluasi, sebelumScanFiltermana pun diterapkan." Tanpa filter,ScannedCountsama denganCount.
Jika Anda hanya punya dan perlu menghitung duplikat di
dalamnya, kondisi + filter yang Anda berikan persis apa yang dihasilkan
DynamoDB Expression Builder — peta
FilterExpression dan ExpressionAttributeNames/Values di atas, plus
KeyConditionExpression saat Anda menghitung di dalam satu partisi via Query — tanpa
meng-escape JSON dengan tangan.
Dua jebakan lagi yang menggigit orang yang menghitung tabel besar:
- Batas halaman 1 MB tetap berlaku. "Jika ukuran set hasil
Scanlebih besar dari 1 MB,ScannedCountdanCounthanya merepresentasikan hitungan sebagian dari total item" (dokumen AWS Scan). Anda harus mempaginasi dengan memberi umpan balikLastEvaluatedKeysetiap respons sebagaiExclusiveStartKeypermintaan berikutnya, menjaga total berjalan untuk mendapatkan angka sebenarnya — loop yang sama yang dibahas di pagination DynamoDB. - Sebuah
Queryyang sempit mengalahkan sebuahScan.Select=COUNTpada sebuahQuerymemeter hanya item di partisi yang ditargetkan, bukan seluruh tabel. Jika Anda bisa menyematkan sebuah partition key (tabel dasar atau sebuah GSI), hitung di sana — itu adalah celah biaya Query-vs-Scan yang diterapkan pada penghitungan.
Select=COUNT vs ItemCount (dan mengapa ia basi)
DescribeTable mengembalikan sebuah ItemCount (dan TableSizeBytes) secara gratis, tanpa
biaya baca. Jebakannya ada di
referensi API itu sendiri:
"DynamoDB memperbarui nilai ini kira-kira setiap enam jam. Perubahan terbaru mungkin tidak
tercermin dalam nilai ini." Jadi ia bisa tertinggal jauh di belakang keadaan aktual tabel
Anda.
Select=COUNT | DescribeTable.ItemCount | |
|---|---|---|
| Keeksakan | Eksak (untuk set yang cocok) | Aproksimatif |
| Kesegaran | Live | Diperbarui ~setiap 6 jam |
| Biaya | Membaca + menagih setiap item yang dihitung | Gratis (metadata) |
| Bisa memfilter / menghitung subset | Ya (filter expression) | Tidak — seluruh tabel saja |
Gunakan ItemCount untuk sebuah cek kasar "seberapa besar tabel ini" atau sebuah petak
dasbor. Gunakan Select=COUNT saat Anda butuh sebuah angka yang eksak, terfilter, atau
terkini — dan terima biaya bacanya. Untuk apa pun yang benar-benar live dan gratis, lacak
sebuah counter sendiri (lihat Pola agregasi di bawah).
Mengapa tak ada SUM/AVG/MIN/MAX native
Operasi baca DynamoDB mengembalikan item. Tak ada query planner untuk melipat sebuah set
hasil menjadi sebuah skalar, jadi tak ada apa pun untuk menghitung sebuah SUM atau AVG.
Penghitungan adalah satu-satunya lipatan yang ditawarkan API, via Select=COUNT.
PartiQL tak mengubah ini. Tata bahasa SELECT PartiQL
adalah SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …],
di mana ekspresinya adalah "sebuah proyeksi yang dibentuk dari wildcard * atau sebuah daftar
proyeksi berisi satu atau lebih nama atribut atau path dokumen." Tak ada fungsi agregat dan
tak ada klausa GROUP BY di tata bahasa itu — dan ORDER BY mengambil sebuah {{key}},
didokumentasikan sebagai "sebuah hash key atau sebuah sort key untuk digunakan mengurutkan
hasil yang dikembalikan." Setiap SELECT PartiQL tetap dikompilasi menjadi sebuah GetItem,
Query, atau Scan, jadi SELECT SUM(total) FROM "Orders" sekadar tak bisa diekspresikan.
(Lebih lanjut tentang batas PartiQL di PartiQL vs SQL.)
Pola agregasi (counter, stream, sisi-aplikasi)
Karena DynamoDB tak akan mengagregasi untuk Anda, pola-pola yang mapan mendorong pekerjaannya ke tempat lain:
- Item counter yang dipelihara. Simpan sebuah item khusus (mis.
PK = "STATS#orders") danADDke sebuah atribut numerik pada setiap penulisan dengan sebuahUpdateItem. Membaca agregatnya lalu menjadi satuGetItem— eksak dan murah, tapi Anda memiliki logika penambahannya, konsistensinya, dan kontensi jika satu counter dihajar. - memberi umpan sebuah aggregator. Aktifkan sebuah stream dan sambungkan ia ke sebuah
Lambda yang memperbarui total berjalan (hitungan, sum) saat item berubah. Menurut
dokumen AWS Streams,
Anda bisa mengonfigurasi
StreamViewTypestream-nya sehingga setiap rekaman membawaNEW_AND_OLD_IMAGES— "baik image baru maupun lama dari item" — cukup untuk menjaga agregat gaya-SUMtetap terkini tanpa memindai ulang. Rekaman stream tunduk pada masa hidup 24 jam ("rekaman stream di dalam sebuah shard dihapus secara otomatis setelah 24 jam"), jadi konsumernya harus mengikuti. - Lipat sisi-aplikasi. Halaman demi halaman melalui item yang cocok dan akumulasikan
SUM/AVG/MIN/MAXdi kode Anda sendiri. Benar, tapi ia membaca (dan menagih) setiap item setiap kali — profil biaya yang sama denganSelect=COUNT, plus transfer datanya. - Alihkan ke analitik. Untuk agregasi analitik yang berat atau ad-hoc, ekspor tabelnya ke S3 dan query ia dengan Athena, atau alirkan ia ke sebuah warehouse. Menurut dokumen AWS ekspor-ke-S3, mengekspor "tidak menghabiskan read capacity unit" dan membiarkan Anda "melakukan analitik dan query kompleks menggunakan layanan AWS seperti Athena" — jalur yang direkomendasikan AWS begitu Anda melampaui agregasi per-permintaan.
Masing-masing menukar kesederhanaan dengan entah pembukuan waktu-tulis (counter, stream) atau
biaya waktu-baca (scan sisi-aplikasi). Tak ada pola yang membuat DynamoDB sendiri menghitung
sebuah SUM secara gratis. Versi pengelompokan dari tradeoff ini — mengagregasi per key
alih-alih atas seluruh tabel — adalah panduannya sendiri:
DynamoDB GROUP BY.
Menjalankan COUNT/SUM/AVG di SQL Workbench DynoTable
Saat Anda hanya butuh jawabannya — "berapa banyak order OPEN, dan berapa totalnya" — tanpa
menulis sebuah loop scan yang mempaginasi atau sebuah Lambda, SQL Workbench DynoTable
menjalankan agregat nyata. Ia mematerialisasi tabel Anda melalui runtime Query/Scan aktual
DynamoDB, lalu menjalankan satu SELECT di atasnya — agregat, GROUP BY,
HAVING, DISTINCT: SQL di dalam aturan pola-akses DynamoDB.
-- Runs in the DynoTable Workbench (NOT in PartiQL):
SELECT status,
COUNT(*) AS orders,
SUM(total) AS revenue,
AVG(total) AS avg_order,
MIN(total) AS smallest,
MAX(total) AS largest
FROM orders
GROUP BY status
ORDER BY revenue DESCItu COUNT, SUM, AVG, MIN, MAX, GROUP BY, dan ORDER BY pada sebuah agregat
terhitung — tak satu pun yang bisa diekspresikan DynamoDB atau PartiQL (ORDER BY PartiQL
terbatas pada atribut key) — dalam satu pernyataan. Ini adalah wedge analitik yang sama
seperti SQL untuk DynamoDB; untuk cerita pengelompokan lengkap
lihat DynamoDB GROUP BY.
Workbench jujur tentang model akses di bawahnya, bukan sebuah pura-pura-Postgres:
- Baris-barisnya tetap datang melalui Query/Scan nyata DynamoDB. Sebuah
GROUP BYatas seluruh tabel tetap sebuahScandi bawahnya — Workbench memunculkan biaya itu alih-alih menyembunyikannya, tradeoff Query-vs-Scan yang sama. - Agregat berjalan pada atribut skalar yang dimaterialisasi setelah baris-barisnya mendarat.
FAQ
Bisakah saya menghitung item di DynamoDB tanpa memindai?
Tak persis. Untuk sebuah hitungan yang eksak dan terkini Anda harus membaca item-nya —
Select=COUNT tetap memeter setiap item yang dihitung. Satu-satunya opsi tanpa-scan adalah
DescribeTable.ItemCount yang aproksimatif (diperbarui ~setiap 6 jam) atau sebuah item
counter yang Anda pelihara sendiri pada setiap penulisan.
Bagaimana saya menghitung item menurut sebuah GSI?
Jalankan Query (atau Scan) terhadap index dengan Select=COUNT. Menghitung via sebuah
partisi GSI yang sempit jauh lebih murah daripada memindai tabel dasar, karena Anda hanya
membaca item di partisi index itu — modelkan index-nya di sekitar hitungan yang Anda butuhkan.
Apakah DescribeTable.ItemCount akurat?
Ia aproksimatif. Referensi API
menyatakan DynamoDB memperbarui ItemCount dan TableSizeBytes "kira-kira setiap enam jam,"
dan "perubahan terbaru mungkin tidak tercermin dalam nilai ini." Jangan gunakan ia di mana
sebuah angka eksak atau live penting.
Bisakah DynamoDB melakukan SUM atau AVG?
Tidak secara native, dan tidak di PartiQL — tata bahasa SELECT PartiQL
tak punya fungsi agregat. Agregasi di aplikasi Anda, pelihara sebuah counter (opsional via
DynamoDB Streams), atau jalankan SUM/AVG di SQL Workbench DynoTable.
Apa perbedaan antara Count dan ScannedCount?
ScannedCount adalah berapa banyak item yang dievaluasi DynamoDB sebelum filter Anda; Count
adalah berapa banyak yang tersisa setelahnya. Keduanya sama saat tak ada filter expression.
Sebuah celah besar di antaranya berarti sebuah hitungan yang tidak efisien.
Perlu menjumlah, merata-rata, atau mengelompokkan data DynamoDB Anda tanpa menulis sebuah loop scan? Unduh DynoTable dan jalankan ia di sebuah tab Workbench. Membandingkan klien dulu? Lihat di mana ia berdiri terhadap sebuah GUI DynamoDB biasa.