Orta8 dakikalık okuma

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 SELECT grameri SELECT … FROM … [WHERE …] [ORDER BY …] şeklindedir — ve listenin tamamı bu kadardır. GROUP BY yok, HAVING yok, toplama işlevleri yok, JOIN yok (AWS PartiQL SELECT referansı).
  • DynamoDB "öğeler arasında SUM veya COUNT gibi 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):

  1. Uygulama ham öğeyi yazar (bir sipariş, bir indirme, bir olay). Toplama mantığı yok.
  2. DynamoDB Streams yazmayı bir akış kaydı olarak yakalar.
  3. Akışa bağlı bir Lambda yeni öğeyi okur, grubu türetir (durum, ay, kategori…) ve atomik bir UpdateItem ile ilgili toplam öğesine ADD yapar — bu, birçok çağrı aynı sayaca dokunduğunda "oku-değiştir-yaz yarış koşullarını önler".
  4. Ö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 10 olan tek bir Query olur.

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) + 1

Bu 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 toplamalarDesen 2 — Streams + Lambda toplaması
Tek bir bölüme indirgenmiş bir sayımDesen 3 — Query sonra uygulamada grupla
Tam toplamlar, sapma yokİdempotentlik korumalı Desen 1/2
Keşfederken tek seferlik bir GROUP BYDynoTable Workbench (aşağıda) veya Athena
SQL ile yinelenen BI/raporlamaAthena 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 DESC

Dü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.

Güncellendi