DynamoDB GROUP BY: cara mengagregasi sebagai gantinya
Tidak ada GROUP BY di DynamoDB. Tidak ada COUNT, SUM, atau AVG juga —
tidak di API native, dan tidak di PartiQL. DynamoDB adalah store key-value /
document, bukan engine analitik, jadi agregasi adalah sesuatu yang Anda
bangun, bukan sesuatu yang dilakukan query planner untuk Anda.
Bisakah Anda GROUP BY di DynamoDB?
Tidak. DynamoDB tidak punya GROUP BY, HAVING, atau fungsi agregat seperti
COUNT, SUM, dan AVG — tidak di API native dan tidak di PartiQL, yang
SELECT-nya hanya menerima WHERE dan ORDER BY. Anda mengagregasi dengan
pre-compute total saat data berubah (atomic counter atau rollup
+ Lambda) atau dengan grouping di sisi app setelah membaca.
- Grammar
SELECTPartiQL DynamoDB adalahSELECT … FROM … [WHERE …] [ORDER BY …]— dan itu seluruh daftarnya. TanpaGROUP BY, tanpaHAVING, tanpa fungsi agregat, tanpaJOIN(referensiSELECTPartiQL AWS). - Karena DynamoDB "doesn't natively support aggregation operations like
SUMorCOUNTacross items," panduan AWS sendiri adalah pre-compute agregat saat data berubah dan menyimpan hasil sebagai item biasa (AWS: agregasi ter-materialisasi). - Alternatifnya — baca setiap item lalu agregasi di app — bekerja, tetapi Anda membayar untuk membaca seluruh tabel pada setiap query.
- Untuk eksplorasi sekali, SQL Workbench DynoTable menjalankan
GROUP BY/COUNT/SUM/AVGlangsung terhadap tabel live — SQL yang ditolak endpoint PartiQL DynamoDB.
Mengapa agregasi sulit di DynamoDB
DynamoDB tidak punya engine agregasi saat scan. Query dan Scan mengembalikan
item; mereka tidak melipatnya. Scan membaca seluruh tabel 1 MB per kali, dan
kapasitas yang dikonsumsi berdasarkan item yang dibaca, bukan baris yang Anda
simpan — FilterExpression diterapkan setelah scan tetapi sebelum hasil
kembali, jadi ia mempersempit result set tanpa menurunkan tagihan
(referensi API Scan AWS:
filter "does not consume any additional read capacity units"; kapasitas
berdasarkan ukuran item yang di-scan, bukan yang dikembalikan). Tidak ada
hook GROUP BY untuk menggantungkan sum atau count sejak awal.
PartiQL tidak mengubah ini. PartiQL adalah dialek SQL-compatible di atas
engine yang sama, jadi ia mewarisi limit yang sama — permukaan sintaks, bukan
model eksekusi baru. Grammar SELECT terdokumentasi
sekadar tidak punya token GROUP BY.
Untuk celah penuh antara PartiQL dan SQL nyata, lihat
PartiQL vs SQL.
Tanya di mana agregat Anda hidup dan kapan dihitung. Ada tiga jawaban.
Pattern 1: agregasi saat write (atomic counter)
Jika Anda tahu group di depan — count per status, total per customer, download per bulan — jaga item counter dan update pada setiap write.
Pakai ADD agar increment atomik dan
aman concurrency. ADD bekerja pada number dan set, dan menghindari race
read-modify-write, jadi dua writer yang meng-increment counter yang sama tidak
pernah saling clobber
(AWS mencatat ADD atomik "avoids read-modify-write race conditions"):
UpdateItem
Key { pk: "STATS#orders", sk: "status#shipped" }
UpdateExpression "ADD orderCount :one"
ExpressionAttributeValues { ":one": 1 }
Ini SELECT COUNT(*) … GROUP BY status Anda — kecuali count sudah duduk di sana
sebagai item, bisa dibaca dalam GetItem single-digit-millisecond. Trade-off:
Anda harus tahu grouping key saat write, dan Anda meng-couple update counter ke
jalur write. Jika app crash setelah write tetapi sebelum update counter,
keduanya drift out of sync — tepat mode kegagalan yang di-decouple pattern
berikutnya.
Pattern 2: DynamoDB Streams + Lambda rollup
Saat Anda tidak ingin logic agregasi di jalur write — atau write adalah
PutItem polos yang tidak mudah di-wrap — pindahkan ke hilir. Ini pattern
rekomendasi AWS sendiri, materialized aggregation
(AWS: Memakai GSI untuk query agregasi ter-materialisasi):
- App menulis item mentah (order, download, event). Tanpa logic agregasi.
- menangkap write sebagai stream record.
- Lambda yang terpasang ke stream membaca item baru, menurunkan group (status,
bulan, kategori…), dan
ADDke item agregat yang cocok denganUpdateItematomik — yang "avoids read-modify-write race conditions" saat banyak invocation menyentuh counter yang sama. - Anda Query agregat yang sudah di-pre-compute — sering lewat
yang hanya mengindeks item rollup, jadi "top
10 bulan ini" adalah satu
QuerydenganLimit 10.
Hanya item agregat yang membawa atribut terindeks (mis. Month), jadi baris
event mentah dikecualikan dari indeks secara otomatis — "a small fraction of the
total items in the table," yang menjaga indeks murah dan baca cepat.
Ini me-decouple agregasi dari jalur write dan menjaga write sederhana, dengan biaya eventual consistency — AWS mencatat "a delay of a few seconds between a download being recorded and the aggregation being updated." Untuk dashboard, leaderboard, dan counter tren itu baik-baik saja.
Invocation Lambda yang di-retry menjalankan ulang ADD, jadi "a retry would
increment the count more than once," meninggalkan nilai approximate. Untuk
count exact, tambah idempotency (mis. condition expression di-key pada id item
sumber); kalau tidak, margin kecil baik untuk analitik dan leaderboard.
Pattern 3: grouping di sisi app setelah Scan/Query
Atau baca item dan group di kode Anda.
groups = {}
resp = table.scan() # or query() for one partition
while True:
for item in resp["Items"]:
key = item["status"]
groups[key] = groups.get(key, 0) + 1
if "LastEvaluatedKey" not in resp:
break
resp = table.scan(ExclusiveStartKey=resp["LastEvaluatedKey"])Ini benar dan kadang pilihan yang tepat — tetapi jujur soal biayanya. Scan
membaca setiap item di tabel, dan kapasitas baca sama ada atau tidaknya
filter. Jadi grouping di sisi app atas Scan penuh berarti Anda membayar untuk
membaca seluruh tabel pada setiap agregasi, dan latensi tumbuh dengan tabel.
AWS mendaftar "scan and count at read time" sebagai "only suitable for very
small datasets where latency isn't a concern"
(AWS: Mengapa agregasi dihitung di muka).
Di-scope ke satu partisi via Query (mis. hitung order satu customer),
grouping di sisi app sepenuhnya masuk akal — Anda hanya membaca satu item
collection. Untuk celah biaya penuh antara keduanya, lihat
Query vs Scan. Di us-east-1 on-demand,
Scan full-table menagih 0,5 RCU per 4 KB eventually-consistent untuk
setiap item yang diperiksa — tabel 1 GB baris 1 KB kira-kira
250.000 RCU sebelum app Anda meng-group apa pun. Ukur item representatif
dengan kalkulator ukuran item, lalu
line-rate scan di
kalkulator harga.
Untuk SQL analitik ad-hoc sungguhan atas tabel DynamoDB — "GROUP BY status,
hitung mereka" sekali yang akan Anda jalankan — jawaban AWS adalah mengarahkan
engine terpisah ke sana: Amazon Athena DynamoDB connector membiarkan Anda
Query tabel dengan SQL nyata (GROUP BY, agregat, bahkan JOIN ke sumber lain)
via Lambda connector
(AWS: Konektor Amazon Athena untuk DynamoDB).
Ia men-scan tabel di balik layar, jadi alat reporting/BI, bukan hot path.
Pattern mana yang saya pakai?
| Anda butuh… | Pakai |
|---|---|
| Total group yang diketahui di hot read path | Pattern 1 — atomic counter (ADD) |
| Agregat tanpa menyentuh jalur write | Pattern 2 — Streams + Lambda rollup |
| Count di-scope ke satu partisi | Pattern 3 — Query lalu group di app |
| Total exact, tanpa drift | Pattern 1/2 dengan penjaga idempotency |
GROUP BY sekali sambil mengeksplorasi | DynoTable Workbench (di bawah) atau Athena |
| BI/reporting berulang dengan SQL | Athena DynamoDB connector |
Menjalankan GROUP BY langsung di SQL Workbench DynoTable
Pattern di atas adalah cara Anda melayani agregat di produksi. Tetapi saat Anda mengeksplorasi tabel — "berapa order per status, sekarang?" — Anda tidak ingin mem-provision Lambda atau berdiri Athena. Anda ingin mengetik query.
Itulah tujuan SQL Workbench DynoTable. Ia menjalankan SQL nyata —
GROUP BY, COUNT, SUM, AVG, HAVING, bahkan JOIN — langsung terhadap
tabel DynamoDB live Anda, mengeksekusi agregasi di sisi klien atas baris yang
dibacanya. Itu SQL yang ditolak endpoint PartiQL DynamoDB:
SELECT status, COUNT(*) AS orders, SUM(total) AS revenue
FROM "Orders"
GROUP BY status
HAVING SUM(total) > 1000
ORDER BY revenue DESCDi balik layar DynoTable membaca item seperti yang diizinkan API (Query di
mana bisa, Scan di mana harus), me-materialize, dan melakukan grouping di
Workbench — mekanika "baca lalu agregasi" yang sama dengan Pattern 3, hanya
tanpa loop, dan dalam aturan access-pattern DynamoDB. Dibangun untuk
eksplorasi dan analisis ad-hoc, bukan mengganti rollup produksi di hot
read path. Untuk itu, pre-compute (Pattern 1 / 2).
Untuk sisi JOIN dari wedge yang sama — DynoTable menjalankan cross-table join
yang PartiQL juga tidak bisa — lihat DynamoDB JOIN.
Membandingkan klien GUI pada kemampuan exact ini? Lihat
perbandingan GUI DynamoDB.
FAQ
Apakah DynamoDB PartiQL mendukung GROUP BY?
Tidak. SELECT PartiQL DynamoDB mendukung WHERE dan ORDER BY saja —
tanpa GROUP BY, HAVING, fungsi agregat, atau JOIN. Grammar
terdokumentasi
sebagai SELECT … FROM … [WHERE …] [ORDER BY …].
Bisakah saya melakukan COUNT(*) atas seluruh tabel DynamoDB?
Bukan sebagai fungsi agregat — PartiQL tidak punya. API memberi Anda
Select=COUNT pada Scan/Query, yang mengembalikan count item yang cocok
tetapi tetap membaca (dan menagih) setiap item yang disentuh scan
(referensi API Scan AWS:
kapasitas berdasarkan item yang diperiksa, bukan dikembalikan). Untuk total yang
sering dibaca, jaga item counter (Pattern 1).
Bisakah saya GROUP BY partition key?
Tidak di DynamoDB atau PartiQL. Jika "per partition key" adalah access pattern
yang diketahui, pelihara satu item agregat per key dengan ADD atomik
(Pattern 1), atau roll up dengan Streams + Lambda (Pattern 2).
Bagaimana saya melakukan SUM atau AVG per group?
SUM: jaga running total per group dan ADD padanya saat write. AVG: simpan
baik sum maupun count dan bagi saat baca — tidak ada average native. Untuk
AVG eksplorasi sekali, jalankan di SQL Workbench DynoTable atau via Athena
DynamoDB connector.
Apakah ada workaround partiql group by?
Tidak ada di sisi PartiQL. Entah pre-compute agregat (counter/Streams) dan
SELECT item rollup, atau jalankan GROUP BY di engine yang punya —
Workbench DynoTable untuk ad-hoc, Athena untuk reporting berulang.
Ingin menjalankan GROUP BY terhadap tabel Anda sendiri tanpa menulis Lambda?
Coba DynoTable dan arahkan SQL Workbench ke tabel live.