DynamoDB GROUP BY: GROUP BY Yan Tümcesi Olmadan Nasıl Toplama Yapılır
DynamoDB'de GROUP BY yoktur. COUNT, SUM veya AVG da yoktur — ne yerel
API'de ne de PartiQL'de. DynamoDB bir anahtar-değer / belge deposudur, bir
analitik motoru değil, dolayısıyla toplama, sorgu planlayıcının sizin için yaptığı
bir şey değil, sizin kurduğunuz bir şeydir.
DynamoDB'de GROUP BY yapabilir misiniz?
Hayır. DynamoDB'de GROUP BY, HAVING ya da COUNT, SUM ve AVG gibi toplama işlevleri yoktur — ne yerel API'de ne de PartiQL'de; PartiQL'in SELECT'i yalnızca WHERE ve ORDER BY kabul eder. Toplama işlemini, ya veri değiştikçe toplamları önceden hesaplayarak (atomik sayaçlar ya da Streams + Lambda toplamaları) ya da okuduktan sonra uygulama tarafında gruplayarak yaparsınız.
- DynamoDB'nin PartiQL
SELECTgrameriSELECT … FROM … [WHERE …] [ORDER BY …]şeklindedir — ve listenin tamamı bu kadardır.GROUP BYyok,HAVINGyok, toplama işlevleri yok,JOINyok (AWS PartiQLSELECTreferansı). - DynamoDB "öğeler arasında
SUMveyaCOUNTgibi toplama işlemlerini yerel olarak desteklemediği" için, AWS'nin kendi önerisi toplamları veri değiştikçe önceden hesaplamak ve sonuçları sıradan öğeler olarak saklamaktır (AWS: gerçekleştirilmiş toplama). - Alternatif — her öğeyi okuyup sonra uygulamanızda toplamak — işe yarar, ancak her sorguda tüm tabloyu okumanın bedelini ödersiniz.
- Tek seferlik keşif için, DynoTable'ın SQL Workbench'i
GROUP BY/COUNT/SUM/AVG'yi canlı bir tabloya doğrudan çalıştırır — DynamoDB'nin PartiQL uç noktasının reddettiği SQL.
DynamoDB'de toplama neden zordur
DynamoDB'nin tarama anında çalışan bir toplama motoru yoktur. Query ve Scan
öğeleri döndürür; onları katlamazlar. Bir Scan tüm tabloyu birer MB okur ve
tükettiği kapasite okuduğu öğelere dayanır, tuttuğunuz satırlara değil — bir
FilterExpression taramadan sonra ama sonuçlar dönmeden önce uygulanır, bu
yüzden faturayı düşürmeden sonuç kümesini daraltır (AWS Scan API referansı: bir filtre
"hiçbir ek okuma kapasite birimi tüketmez"; kapasite döndürülen değil, taranan
öğe boyutuna dayanır). Üzerine bir toplam veya sayım asacağınız bir GROUP-BY
kancası baştan yoktur.
PartiQL bunu değiştirmez. PartiQL, aynı motor üzerinde SQL ile uyumlu bir
lehçedir, bu yüzden aynı sınırları miras alır — yeni bir yürütme modeli değil, bir
söz dizimi yüzeyidir. Belgelenen SELECT grameri
basitçe hiçbir GROUP BY belirteci içermez.
PartiQL ile gerçek SQL arasındaki tüm farklar için bkz.
PartiQL vs SQL.
Yani soru "nasıl GROUP BY yazarım" değil — "toplamam nerede yaşar ve ne zaman
hesaplanır?" sorusudur. Üç yanıt vardır.
Desen 1: yazma anında topla (atomik sayaçlar)
Grupları önceden biliyorsanız — duruma göre sayı, müşteriye göre toplam, aya göre indirme — bir sayaç öğesi tutun ve her yazmada güncelleyin.
Artırmanın atomik ve eşzamanlılığa karşı güvenli olması için bir ADD güncelleme
ifadesi kullanın. ADD sayılar ve kümeler üzerinde çalışır ve oku-değiştir-yaz
yarışını önler, böylece aynı sayacı artıran iki yazıcı asla birbirini ezmez
(AWS, atomik ADD'in "oku-değiştir-yaz yarış koşullarını önlediğini" belirtir):
UpdateItem
Key { pk: "STATS#orders", sk: "status#shipped" }
UpdateExpression "ADD orderCount :one"
ExpressionAttributeValues { ":one": 1 }
Bu sizin SELECT COUNT(*) … GROUP BY status ifadenizdir — yalnızca sayım zaten
bir öğe olarak orada durur ve tek haneli milisaniyelik bir GetItem ile okunabilir.
Ödün: gruplama anahtarını yazma anında bilmeniz ve sayaç güncellemesini yazma
yoluna bağlamanız gerekir. Uygulama yazmadan sonra ama sayaç güncellemesinden
önce çökerse, ikisi senkronizasyondan çıkar — ki bu tam olarak bir sonraki
desenin ayırdığı arıza modudur.
Desen 2: DynamoDB Streams + Lambda toplamaları
Yazma yolunda toplama mantığı istemediğinizde — ya da yazma kolayca saramayacağınız
düz bir PutItem olduğunda — onu aşağı akışa taşıyın. Bu, AWS'nin kendi önerdiği
desendir, gerçekleştirilmiş toplama
(AWS: Gerçekleştirilmiş toplama sorguları için GSI kullanma):
- Uygulama ham öğeyi yazar (bir sipariş, bir indirme, bir olay). Toplama mantığı yok.
- DynamoDB Streams yazmayı bir akış kaydı olarak yakalar.
- Akışa bağlı bir Lambda yeni öğeyi okur, grubu türetir (durum, ay, kategori…) ve
atomik bir
UpdateItemile ilgili toplam öğesineADDyapar — bu, birçok çağrı aynı sayaca dokunduğunda "oku-değiştir-yaz yarış koşullarını önler". - Önceden hesaplanmış toplamı sorgularsınız — çoğunlukla yalnızca toplam öğelerini
indeksleyen bir seyrek GSI aracılığıyla, böylece "bu ay ilk 10"
Limit 10olan tek birQueryolur.
Seyrek GSI hilesi: yalnızca toplam öğeleri indekslenen özniteliği taşır
(ör. Month), böylece ham olay satırları indeksten otomatik olarak dışlanır
— "tablodaki toplam öğelerin küçük bir kesri" — bu da indeksi ucuz ve okumayı
hızlı tutar.
Bu, toplamayı yazma yolundan ayırır ve yazmaları basit tutar; bunun bedeli nihai tutarlılıktır — AWS "bir indirmenin kaydedilmesi ile toplamanın güncellenmesi arasında birkaç saniyelik bir gecikme" olduğunu belirtir. Panolar, sıralama tabloları ve trend sayaçları için bu gayet iyidir.
Aynı yeniden deneme uyarısı geçerlidir: yeniden denenen bir Lambda çağrısı ADD'i
yeniden çalıştırır, böylece "bir yeniden deneme sayımı birden fazla artırır" ve
yaklaşık bir değer bırakır. Tam sayımlar için idempotentlik ekleyin (ör. kaynak
öğenin kimliğine dayalı bir koşul ifadesi); aksi takdirde küçük marj analitik ve
sıralama tabloları için yeterlidir.
Desen 3: Scan/Query sonrası uygulama tarafında gruplama
Kaba kuvvet seçeneği: öğeleri okuyun, onları kodunuzda gruplayın.
groups = {}
for item in paginate(table.scan()): # ya da tek bir bölüm için query()
key = item["status"]
groups[key] = groups.get(key, 0) + 1Bu doğrudur ve bazen doğru çağrıdır — ama maliyet konusunda dürüst olun. Bir
Scan tablodaki her öğeyi okur ve okuma kapasitesi filtrelseniz de
filtrelemeseniz de aynıdır. Yani tam bir Scan üzerinde uygulama tarafında
gruplama, her toplamada tüm tabloyu okumanın bedelini ödemeniz anlamına gelir ve
gecikme tabloyla birlikte büyür. AWS, "okuma anında tarama ve sayma"yı "yalnızca
gecikmenin önemli olmadığı çok küçük veri kümeleri için uygun" olarak listeler
(AWS: Toplamaları neden önceden hesaplamalı).
Bir Query aracılığıyla tek bir bölüme indirgenmiş olarak (ör. bir müşterinin
siparişlerini sayma), uygulama tarafında gruplama tamamen makuldür — yalnızca bir
öğe koleksiyonu okuyorsunuz. İkisi arasındaki tam maliyet farkı için bkz.
Query vs Scan. Belirli bir toplama taramasının çalışmadan
önce ne okuyacağını tahmin etmek için, temsili bir öğeyi
öğe boyutu hesaplayıcısı ile boyutlandırın —
okuma kapasitesi her 4 KB için yukarı yuvarlar,
böylece öğe boyutu faturayı belirler.
Bir DynamoDB tablosu üzerinde gerçekten geçici analitik SQL için — bir kez
çalıştıracağınız "GROUP BY status, onları say" tipi tek kullanımlık sorgu —
AWS'nin yanıtı ona ayrı bir motor yöneltmektir: Amazon Athena DynamoDB
bağlayıcısı, tabloyu bir Lambda bağlayıcısı aracılığıyla gerçek SQL ile
(GROUP BY, toplamalar, hatta diğer kaynaklara JOIN'ler) sorgulamanıza olanak
tanır
(AWS: Amazon Athena DynamoDB bağlayıcısı).
Perde arkasında tabloyu tarar, bu yüzden bir raporlama/BI aracıdır, sıcak bir yol
değildir.
Hangi deseni kullanırım?
| İhtiyacınız… | Kullanın |
|---|---|
| Sıcak okuma yolunda bilinen bir grup toplamı | Desen 1 — atomik sayaç (ADD) |
| Yazma yoluna dokunmadan toplamalar | Desen 2 — Streams + Lambda toplaması |
| Tek bir bölüme indirgenmiş bir sayım | Desen 3 — Query sonra uygulamada grupla |
| Tam toplamlar, sapma yok | İdempotentlik korumalı Desen 1/2 |
Keşfederken tek seferlik bir GROUP BY | DynoTable Workbench (aşağıda) veya Athena |
| SQL ile yinelenen BI/raporlama | Athena DynamoDB bağlayıcısı |
DynoTable'ın SQL Workbench'inde GROUP BY'ı doğrudan çalıştırma
Yukarıdaki desenler, toplamaları üretimde nasıl sunduğunuzdur. Ama bir tabloyu keşfederken — "şu anda duruma göre kaç sipariş var?" — bir Lambda sağlamak ya da Athena kurmak istemezsiniz. Sorguyu yazmak istersiniz.
DynoTable'ın SQL Workbench'i bunun içindir. Gerçek SQL'i —
GROUP BY, COUNT, SUM, AVG, HAVING, hatta JOIN — canlı DynamoDB
tablolarınıza doğrudan çalıştırır ve toplamayı okuduğu satırlar üzerinde istemci
tarafında yürütür. Bu, DynamoDB'nin PartiQL uç noktasının reddettiği SQL'dir:
SELECT status, COUNT(*) AS orders, SUM(total) AS revenue
FROM "Orders"
GROUP BY status
HAVING SUM(total) > 1000
ORDER BY revenue DESCDürüst çerçeveleme: kaputun altında DynoTable öğeleri API'nin izin verdiği şekilde
okur (yapabildiği yerde Query, mecbur olduğu yerde Scan), onları
gerçekleştirir ve gruplamayı Workbench'te yapar — Desen 3 ile aynı "oku sonra
topla" mekaniği, sadece döngü olmadan ve DynamoDB'nin erişim deseni kuralları
içinde. Keşif ve geçici analiz için yapılmıştır, sıcak bir okuma yolunda bir
üretim toplamasını değiştirmek için değil. Onun için önceden hesaplayın
(Desen 1 / 2).
Aynı kamanın JOIN tarafı için — DynoTable, PartiQL'in de yapamadığı tablolar
arası birleştirmeleri çalıştırır — bkz. DynamoDB JOIN. Tam
bu yetenek üzerinde GUI istemcilerini mi karşılaştırıyorsunuz? Bkz.
DynamoDB GUI karşılaştırması.
SSS
DynamoDB PartiQL GROUP BY'ı destekler mi?
Hayır. DynamoDB'nin PartiQL SELECT'i yalnızca WHERE ve ORDER BY'ı destekler —
GROUP BY, HAVING, toplama işlevleri veya JOIN yoktur. Gramer,
belgelendiği şekliyle
SELECT … FROM … [WHERE …] [ORDER BY …] şeklindedir.
Tüm bir DynamoDB tablosu üzerinde COUNT(*) yapabilir miyim?
Bir toplama işlevi olarak değil — PartiQL'de hiç yoktur. API, bir Scan/Query
üzerinde Select=COUNT verir; bu, eşleşen öğelerin bir sayımını döndürür ama
yine de taramanın dokunduğu her öğeyi okur (ve faturalandırır)
(AWS Scan API referansı:
kapasite döndürülen değil, incelenen öğelere dayanır). Sık okunan bir toplam için
bir sayaç öğesi tutun (Desen 1).
Bölüm anahtarına göre GROUP BY yapabilir miyim?
DynamoDB'de veya PartiQL'de hayır. "Bölüm anahtarına göre" bilinen bir erişim
deseniyse, anahtar başına bir toplam öğeyi atomik bir ADD ile tutun (Desen 1) ya
da Streams + Lambda ile toplayın (Desen 2).
Grup başına SUM veya AVG'yi nasıl yaparım?
SUM: grup başına çalışan bir toplam tutun ve yazma anında ona ADD yapın. AVG:
hem toplamı hem sayımı saklayın ve okuma anında bölün — yerel bir ortalama yoktur.
Tek seferlik keşif amaçlı bir AVG için, onu DynoTable'ın SQL Workbench'inde veya
Athena DynamoDB bağlayıcısı aracılığıyla çalıştırın.
Bir partiql group by geçici çözümü var mı?
PartiQL tarafında yok. Ya toplamı önceden hesaplayın (sayaçlar/Streams) ve toplam
öğeyi SELECT edin ya da GROUP BY'ı buna sahip bir motorda çalıştırın —
geçici için DynoTable'ın Workbench'i, yinelenen raporlama için Athena.
GROUP BY'ı bir Lambda yazmadan kendi tablolarınıza karşı çalıştırmak ister
misiniz? DynoTable'ı deneyin ve SQL Workbench'i canlı bir tabloya
yöneltin.