Menengah8 menit baca

DynamoDB GROUP BY: Cara Mengagregasi Tanpa Klausa GROUP BY

Tidak ada GROUP BY di DynamoDB. Tidak ada COUNT, SUM, atau AVG juga — tidak di API native, dan tidak di PartiQL. DynamoDB adalah penyimpanan key-value / dokumen, bukan engine analitik, jadi agregasi adalah sesuatu yang Anda bangun, bukan sesuatu yang dilakukan query planner untuk Anda.

Bisakah Anda melakukan GROUP BY di DynamoDB?

Tidak. DynamoDB tidak punya GROUP BY, HAVING, atau fungsi agregat seperti COUNT, SUM, dan AVG — tidak di API native maupun di PartiQL, yang SELECT-nya hanya menerima WHERE dan ORDER BY. Anda mengagregasi dengan menghitung-sebelumnya total saat data berubah (atomic counter atau rollup Streams + Lambda) atau dengan mengelompokkan di sisi-aplikasi setelah membaca.

  • Grammar PartiQL SELECT DynamoDB adalah SELECT … FROM … [WHERE …] [ORDER BY …] — dan itulah seluruh daftarnya. Tidak ada GROUP BY, tidak ada HAVING, tidak ada fungsi agregat, tidak ada JOIN (referensi PartiQL SELECT AWS).
  • Karena DynamoDB "tidak secara native mendukung operasi agregasi seperti SUM atau COUNT lintas item," panduan AWS sendiri adalah untuk menghitung-sebelumnya agregat saat data berubah dan menyimpan hasilnya sebagai item biasa (AWS: agregasi termaterialisasi).
  • Alternatifnya — baca setiap item lalu agregasi di aplikasi Anda — bekerja, tetapi Anda membayar untuk membaca seluruh tabel pada setiap query.
  • Untuk eksplorasi sekali-pakai, SQL Workbench DynoTable menjalankan GROUP BY / COUNT / SUM / AVG langsung terhadap tabel live — SQL yang ditolak endpoint PartiQL DynamoDB.

Mengapa agregasi sulit di DynamoDB

DynamoDB tidak punya engine agregasi waktu-scan. Query dan Scan mengembalikan item; mereka tidak melipatnya. Scan membaca seluruh tabel 1 MB sekaligus, dan kapasitas yang dikonsumsinya didasarkan pada item yang dibacanya, bukan baris yang Anda simpan — sebuah FilterExpression diterapkan setelah scan tetapi sebelum hasil kembali, jadi ia mempersempit set hasil tanpa menurunkan tagihan (referensi API Scan AWS: sebuah filter "tidak mengonsumsi read capacity unit tambahan"; kapasitas didasarkan pada 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 kompatibel-SQL atas engine yang sama, jadi ia mewarisi keterbatasan yang sama — ia permukaan sintaksis, bukan model eksekusi baru. Grammar SELECT yang didokumentasikan sederhananya tidak punya token GROUP BY. Untuk kesenjangan penuh antara PartiQL dan SQL sungguhan, lihat PartiQL vs SQL.

Jadi pertanyaannya bukan "bagaimana saya menulis GROUP BY" — melainkan "di mana agregat saya hidup, dan kapan ia dihitung?" Ada tiga jawaban.

Pola 1: agregasi saat tulis (atomic counter)

Jika Anda tahu grup di muka — hitung per status, total per pelanggan, unduhan per bulan — pelihara item counter dan perbaruinya pada setiap penulisan.

Gunakan update expression ADD agar inkremen atomik dan aman-konkurensi. ADD bekerja pada angka dan set, dan ia menghindari race read-modify-write, jadi dua penulis yang menginkremen counter yang sama tidak pernah saling menimpa (AWS mencatat ADD atomik "menghindari race condition read-modify-write"):

UpdateItem
Key                         { pk: "STATS#orders", sk: "status#shipped" }
UpdateExpression            "ADD orderCount :one"
ExpressionAttributeValues   { ":one": 1 }

Ini adalah SELECT COUNT(*) … GROUP BY status Anda — kecuali hitungannya sudah duduk di sana sebagai item, terbaca dalam GetItem satu-digit-milidetik. Trade-off-nya: Anda harus tahu key pengelompokan pada waktu tulis, dan Anda menggandengkan pembaruan counter ke jalur tulis. Jika aplikasi crash setelah penulisan tetapi sebelum pembaruan counter, keduanya menyimpang dari sinkron — yang justru merupakan mode kegagalan yang dipisahkan oleh pola berikutnya.

Pola 2: rollup DynamoDB Streams + Lambda

Ketika Anda tak ingin logika agregasi di jalur tulis — atau penulisan adalah PutItem biasa yang sulit Anda bungkus — pindahkan ke hilir. Ini pola rekomendasi AWS sendiri, agregasi termaterialisasi (AWS: Menggunakan GSI untuk query agregasi termaterialisasi):

  1. Aplikasi menulis item mentah (sebuah order, sebuah unduhan, sebuah event). Tanpa logika agregasi.
  2. DynamoDB Streams menangkap penulisan sebagai record stream.
  3. Sebuah Lambda yang terpasang ke stream membaca item baru, menurunkan grup (status, bulan, kategori…), dan ADD ke item agregat yang cocok dengan UpdateItem atomik — yang "menghindari race condition read-modify-write" saat banyak invokasi menyentuh counter yang sama.
  4. Anda query agregat yang dihitung-sebelumnya — sering melalui GSI sparse yang mengindeks hanya item rollup, jadi "10 teratas bulan ini" adalah satu Query dengan Limit 10.

Trik GSI sparse: hanya item agregat yang membawa atribut terindeks (mis. Month), jadi baris event mentah dikecualikan dari indeks secara otomatis — "fraksi kecil dari total item dalam tabel," yang menjaga indeks murah dan baca cepat.

Ini memisahkan agregasi dari jalur tulis dan menjaga penulisan tetap sederhana, dengan biaya eventual consistency — AWS mencatat "penundaan beberapa detik antara sebuah unduhan dicatat dan agregasi diperbarui." Untuk dashboard, leaderboard, dan counter tren itu tidak masalah.

Caveat retry yang sama berlaku: invokasi Lambda yang di-retry menjalankan ulang ADD, jadi "sebuah retry akan menginkremen hitungan lebih dari sekali," meninggalkan nilai aproksimatif. Untuk hitungan eksak, tambahkan idempotensi (mis. condition expression yang berkunci pada id item sumber); jika tidak, margin kecil tak masalah untuk analitik dan leaderboard.

Pola 3: pengelompokan sisi-aplikasi setelah Scan/Query

Opsi brute-force: baca item, kelompokkan di kode Anda.

groups = {}
for item in paginate(table.scan()):       # atau query() untuk satu partisi
    key = item["status"]
    groups[key] = groups.get(key, 0) + 1

Ini benar dan kadang merupakan keputusan yang tepat — tetapi jujurlah tentang biayanya. Scan membaca setiap item dalam tabel, dan kapasitas bacanya sama terlepas dari apakah Anda memfilter. Jadi pengelompokan sisi-aplikasi atas Scan penuh berarti Anda membayar untuk membaca seluruh tabel pada setiap agregasi, dan latensi tumbuh seiring tabel. AWS mendaftar "scan dan count saat baca" sebagai "hanya cocok untuk dataset sangat kecil di mana latensi bukan masalah" (AWS: Mengapa menghitung-sebelumnya agregasi).

Dipersempit ke satu partisi via Query (mis. hitung order untuk satu pelanggan), pengelompokan sisi-aplikasi sangat masuk akal — Anda hanya membaca satu koleksi item. Untuk kesenjangan biaya penuh antara keduanya, lihat Query vs Scan. Untuk mengestimasi apa yang akan dibaca scan agregasi tertentu sebelum Anda menjalankannya, ukur item representatif dengan kalkulator ukuran itemkapasitas baca dibulatkan ke atas per 4 KB, jadi ukuran item menggerakkan tagihan.

Untuk SQL analitis yang benar-benar ad-hoc atas tabel DynamoDB — "GROUP BY status, hitung mereka" sekali pakai yang Anda jalankan sekali — jawaban AWS adalah mengarahkan engine terpisah ke sana: konektor Amazon Athena DynamoDB memungkinkan Anda query tabel dengan SQL sungguhan (GROUP BY, agregat, bahkan JOIN ke sumber lain) via konektor Lambda (AWS: konektor Amazon Athena DynamoDB). Ia men-scan tabel di balik layar, jadi ia alat reporting/BI, bukan jalur panas.

Pola mana yang saya pakai?

Anda butuh…Gunakan
Total grup yang dikenal di jalur baca panasPola 1 — atomic counter (ADD)
Agregat tanpa menyentuh jalur tulisPola 2 — rollup Streams + Lambda
Hitungan yang dipersempit ke satu partisiPola 3 — Query lalu kelompokkan di app
Total eksak, tanpa driftPola 1/2 dengan pengaman idempotensi
GROUP BY sekali-pakai saat mengeksplorasiDynoTable Workbench (di bawah) atau Athena
BI/reporting berulang dengan SQLKonektor Athena DynamoDB

Menjalankan GROUP BY langsung di SQL Workbench DynoTable

Pola di atas adalah cara Anda melayani agregat di produksi. Tetapi ketika Anda mengeksplorasi sebuah tabel — "berapa banyak order per status, sekarang juga?" — Anda tak ingin men-provision Lambda atau mendirikan Athena. Anda ingin mengetik query-nya.

Itulah gunanya SQL Workbench DynoTable. Ia menjalankan SQL sungguhan — GROUP BY, COUNT, SUM, AVG, HAVING, bahkan JOIN — langsung terhadap tabel DynamoDB live Anda, mengeksekusi agregasi di sisi-klien atas baris yang dibacanya. Ini 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 DESC

Pembingkaian jujur: di balik layar DynoTable membaca item dengan cara yang diizinkan API (Query di mana ia bisa, Scan di mana ia harus), memmaterialisasinya, dan melakukan pengelompokan di Workbench — mekanika "baca lalu agregasi" yang sama dengan Pola 3, hanya tanpa loop, dan dalam aturan pola-akses DynamoDB. Ia dibangun untuk eksplorasi dan analisis ad-hoc, bukan untuk menggantikan rollup produksi di jalur baca panas. Untuk itu, hitung-sebelumnya (Pola 1 / 2).

Untuk sisi JOIN dari wedge yang sama — DynoTable menjalankan join lintas-tabel yang PartiQL juga tidak bisa — lihat DynamoDB JOIN. Membandingkan klien GUI pada kemampuan ini persis? Lihat perbandingan GUI DynamoDB.

FAQ

Apakah PartiQL DynamoDB mendukung GROUP BY? Tidak. SELECT PartiQL DynamoDB mendukung WHERE dan ORDER BY saja — tidak ada GROUP BY, HAVING, fungsi agregat, atau JOIN. Grammar-nya didokumentasikan sebagai SELECT … FROM … [WHERE …] [ORDER BY …].

Bisakah saya melakukan COUNT(*) atas seluruh tabel DynamoDB? Tidak sebagai fungsi agregat — PartiQL tidak punya. API memberi Anda Select=COUNT pada Scan/Query, yang mengembalikan hitungan item yang cocok tetapi tetap membaca (dan menagih) setiap item yang disentuh scan (referensi API Scan AWS: kapasitas didasarkan pada item yang diperiksa, bukan yang dikembalikan). Untuk total yang sering-dibaca, pelihara item counter (Pola 1).

Bisakah saya GROUP BY partition key? Tidak di DynamoDB atau PartiQL. Jika "per partition key" adalah pola akses yang dikenal, pelihara satu item agregat per key dengan ADD atomik (Pola 1), atau roll-up dengan Streams + Lambda (Pola 2).

Bagaimana saya melakukan SUM atau AVG per grup? SUM: pelihara total berjalan per grup dan ADD ke sana saat tulis. AVG: simpan baik sum maupun count dan bagi saat baca — tidak ada average native. Untuk AVG eksploratif sekali-pakai, jalankan di SQL Workbench DynoTable atau via konektor Athena DynamoDB.

Apakah ada workaround partiql group by? Tidak ada yang di sisi-PartiQL. Entah hitung-sebelumnya 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.

Diperbarui