Başlangıç7 dakikalık okuma

DynamoDB'de COUNT, SUM ve Toplama Nasıl Yapılır

DynamoDB'nin tam olarak tek bir yerleşik toplaması vardır: Select=COUNT ile eşleşen item'ları saymak. Yerel bir SUM, AVG, MIN veya MAX yoktur. Ve alabildiğiniz sayım bile saydığı her item'ı okur (ve faturalandırır). Bu kılavuz gerçekte neyin desteklendiğini, insanların başvurduğu yaklaşıklıkları ve ihtiyaç duyduğunuzda bir tablo üzerinde gerçek COUNT/SUM/AVG'nin nasıl çalıştırılacağını ele alır.

DynamoDB SUM, COUNT ve toplama işlevlerini yapabilir mi?

Çoğunlukla hayır. DynamoDB'nin tek yerleşik toplaması Select=COUNT'tur; eşleşen item sayısını döndürür ama yine de her item'ı okur (ve faturalandırır). Yerel bir SUM, AVG, MIN veya MAX yoktur ve PartiQL de hiçbirini eklemez. GROUP BY ile gerçek toplamalar için uygulamanızda toplayın, bir sayaç tutun veya DynoTable'ın Workbench'inde SQL çalıştırın.

  • Select=COUNT eşleşen item sayısını döndürür, ancak DynamoDB onu üretmek için yine de her item'ı okur — ucuz bir "sayım" maliyeti değil, tam Scan/Query okuma maliyetini ödersiniz.
  • Yerel bir SUM, AVG, MIN veya MAX yoktur. DynamoDB'nin okuma işlemleri item döndürür; onları bir sayıya katlamaz. PartiQL de toplama eklemez.
  • DescribeTable.ItemCount ücretsizdir ama yaklaşıktır ve yalnızca "yaklaşık olarak her altı saatte bir" güncellenir — bir gösterge panosu kutusu için uygun, kesin bir şey için yanlış.
  • Kesin COUNT/SUM/AVG/MIN/MAX (GROUP BY ile) için, uygulamanızda toplayın, bir sayaç tutun veya DynoTable'ın SQL Workbench'inde çalıştırın (aşağıda).

Item'ları sayma: Select=COUNT

Hem Query hem Scan bir Select parametresi kabul eder. Onu COUNT olarak ayarlayın ve yanıt item'lar yerine sayıları taşır:

aws dynamodb scan \
  --table-name Orders \
  --select COUNT \
  --filter-expression "#s = :open" \
  --expression-attribute-names '{"#s":"status"}' \
  --expression-attribute-values '{":open":{"S":"OPEN"}}'

Yanıt size iki sayı verir (AWS: Sonuçlardaki item'ları sayma):

  • Count — "bir filtre ifadesi (varsa) uygulandıktan sonra kalan item sayısı."
  • ScannedCount — "herhangi bir ScanFilter uygulanmadan önce değerlendirilen item sayısı." Filtre yoksa, ScannedCount Count ile aynıdır.

Yalnızca partition key'iniz varsa ve içindeki yinelenenleri saymanız gerekiyorsa, geçirdiğiniz koşul + filtre tam olarak DynamoDB Expression Builder'ın ürettiği şeydir — yukarıdaki KeyConditionExpression, FilterExpression ve ExpressionAttributeNames/Values haritaları — JSON'u elle kaçışlamadan.

Büyük tabloları sayan insanları ısıran iki tuzak daha:

  • 1 MB sayfa sınırı hâlâ geçerlidir. "Scan sonuç kümesinin boyutu 1 MB'tan büyükse, ScannedCount ve Count toplam item'ların yalnızca kısmi bir sayımını temsil eder" (AWS Scan dokümanları). Gerçek sayıyı elde etmek için LastEvaluatedKeyExclusiveStartKey ile sayfalama yapmanız ve çalışan bir toplam tutmanız gerekir — aynı döngü DynamoDB sayfalama'da ele alınmıştır.
  • Dar bir Query, bir Scan'i yener. Bir Query üzerindeki Select=COUNT yalnızca hedeflenen partition'daki item'ları metreler, tüm tabloyu değil. Bir partition key'i (temel tablo veya bir GSI) sabitleyebiliyorsanız, orada sayın — saymaya uygulanan Query ve Scan maliyet farkıdır.

Select=COUNT ve ItemCount (ve neden bayat)

DescribeTable, ücretsiz olarak, okuma maliyeti olmadan bir ItemCount (ve TableSizeBytes) döndürür. Püf noktası API referansının kendisindedir: "DynamoDB bu değeri yaklaşık olarak her altı saatte bir günceller. Son değişiklikler bu değere yansımayabilir." Bu yüzden tablonuzun gerçek durumunun epeyce gerisinde kalabilir.

Select=COUNTDescribeTable.ItemCount
KesinlikKesin (eşleşen küme için)Yaklaşık
TazelikCanlı~her 6 saatte bir güncellenir
MaliyetSayılan her item'ı okur + faturalandırırÜcretsiz (meta veri)
Bir alt kümeyi filtreleyebilir / sayabilirEvet (filtre ifadesi)Hayır — yalnızca tüm tablo

"Bu tablo ne kadar büyük" kabaca bir kontrol veya bir gösterge panosu kutusu için ItemCount kullanın. Kesin, filtrelenmiş veya güncel bir sayıya ihtiyacınız olduğunda Select=COUNT kullanın — ve okuma maliyetini kabul edin. Gerçekten canlı ve ücretsiz herhangi bir şey için, bir sayacı kendiniz izleyin (aşağıdaki Toplama kalıpları'na bakın).

Neden yerel bir SUM/AVG/MIN/MAX yok

DynamoDB'nin okuma işlemleri item döndürür. Bir sonuç kümesini bir skalere katlayacak bir sorgu planlayıcısı yoktur, bu yüzden bir SUM veya AVG hesaplayacak bir şey de yoktur. Sayma, API'nin sunduğu tek katlamadır, Select=COUNT aracılığıyla.

PartiQL bunu değiştirmez. PartiQL SELECT dilbilgisi SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …] şeklindedir; burada ifade, "* joker karakterinden veya bir veya daha fazla attribute adı ya da belge yolundan oluşan bir projeksiyon listesinden oluşturulan bir projeksiyondur." Bu dilbilgisinde toplama işlevi ve GROUP BY yan tümcesi yoktur — ve ORDER BY bir {{key}} alır, "döndürülen sonuçları sıralamak için kullanılacak bir hash key veya bir sort key" olarak belgelenmiştir. Her PartiQL SELECT yine bir GetItem, Query veya Scan'e derlenir, bu yüzden SELECT SUM(total) FROM "Orders" basitçe ifade edilemez. (PartiQL tavanı hakkında daha fazlası PartiQL ve SQL'de.)

Toplama kalıpları (sayaçlar, stream'ler, uygulama tarafı)

DynamoDB sizin için toplama yapmayacağından, yerleşik kalıplar işi başka yere iter:

  • Tutulan sayaç item'ı. Özel bir item tutun (örn. PK = "STATS#orders") ve her yazmada bir UpdateItem ile sayısal bir attribute'a ADD yapın. Toplamı okumak ardından tek bir GetItem'dır — kesin ve ucuz, ama artırma mantığına, tutarlılığına ve bir sayaç sürekli vurulursa çekişmeye siz sahipsiniz.
  • DynamoDB Streams → toplayıcı. Bir stream etkinleştirin ve item'lar değiştikçe çalışan toplamları (sayılar, toplamlar) güncelleyen bir Lambda'ya bağlayın. AWS Streams dokümanları'na göre, her kaydın NEW_AND_OLD_IMAGES taşıması için stream'in StreamViewType'ını yapılandırabilirsiniz — "item'ın hem yeni hem de eski görüntüleri" — yeniden taramadan SUM tarzı toplamaları güncel tutmaya yeter. Stream kayıtları 24 saatlik bir ömre tabidir ("bir parçadaki stream kayıtları 24 saat sonra otomatik olarak kaldırılır"), bu yüzden tüketicinin ayak uydurması gerekir.
  • Uygulama tarafı katlama. Eşleşen item'lar arasında sayfalayın ve SUM/AVG/MIN/MAX'ı kendi kodunuzda biriktirin. Doğru, ama her seferinde her item'ı okur (ve faturalandırır) — Select=COUNT ile aynı maliyet profili, artı veri aktarımı.
  • Analitiğe devretme. Yoğun veya geçici analitik toplama için, tabloyu S3'e dışa aktarın ve Athena ile sorgulayın ya da bir veri ambarına aktarın. AWS S3'e dışa aktarma dokümanları'na göre, dışa aktarma "okuma kapasite birimleri tüketmez" ve "Athena gibi AWS hizmetlerini kullanarak analitik ve karmaşık sorgular gerçekleştirmenize" izin verir — istek başına toplamayı aştığınızda AWS'nin önerdiği yol.

Her biri basitliği ya yazma zamanı kayıt tutmayla (sayaçlar, stream'ler) ya da okuma zamanı maliyetiyle (uygulama tarafı taramalar) takas eder. Hiçbir kalıp DynamoDB'nin kendisinin ücretsiz bir SUM hesaplamasını sağlamaz. Bu ödünleşimin gruplama sürümü — tüm tablo yerine anahtar başına toplama — kendi kılavuzudur: DynamoDB GROUP BY.

DynoTable'ın SQL Workbench'inde COUNT/SUM/AVG çalıştırma

Sadece cevaba ihtiyacınız olduğunda — "kaç OPEN sipariş var ve toplamları ne" — sayfalayan bir tarama döngüsü ya da bir Lambda yazmadan, DynoTable'ın SQL Workbench'i gerçek toplamalar çalıştırır. Tablolarınızı DynamoDB'nin gerçek Query/Scan çalışma zamanı üzerinden materyalize eder, ardından tüm SQL'inizi üstünde çalıştırır: DynamoDB'nin erişim modeli kuralları içinde SQL.

-- 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 DESC

Bu, COUNT, SUM, AVG, MIN, MAX, GROUP BY ve ORDER BY'dır — hiçbirini DynamoDB veya PartiQL ifade edemez — tek bir ifadede. Bu, DynamoDB için SQL ile aynı analitik kamadır; tam gruplama hikâyesi için DynamoDB GROUP BY'a bakın.

Workbench, alttaki erişim modeli hakkında dürüsttür, bir Postgres taklidi değildir:

  • Satırlar yine DynamoDB'nin gerçek Query/Scan'i üzerinden gelir. Tüm bir tablo üzerindeki bir GROUP BY yine altta bir Scan'dir — Workbench o maliyeti gizlemek yerine açığa çıkarır, aynı Query ve Scan ödünleşimi.
  • Toplamalar, satırlar yerleştikten sonra materyalize edilen skaler attribute'lar üzerinde çalışır.

SSS

DynamoDB'de tarama yapmadan item'ları sayabilir miyim? Tam olarak değil. Kesin, güncel bir sayım için item'ları okumalısınız — Select=COUNT yine sayılan her item'ı metreler. Tek tarama-yapmayan seçenekler, yaklaşık DescribeTable.ItemCount (~her 6 saatte bir güncellenir) veya her yazmada kendinizin tuttuğu bir sayaç item'ıdır.

Bir GSI'ye göre item'ları nasıl sayarım? İndeks üzerinde Select=COUNT ile Query (veya Scan) çalıştırın. Dar bir GSI partition'ı üzerinden saymak, temel tabloyu taramaktan çok daha ucuzdur, çünkü yalnızca o indeks partition'ındaki item'ları okursunuz — indeksi ihtiyaç duyduğunuz sayım etrafında modelleyin.

DescribeTable.ItemCount doğru mu? Yaklaşıktır. API referansı, DynamoDB'nin ItemCount ve TableSizeBytes'ı "yaklaşık olarak her altı saatte bir" güncellediğini ve "son değişikliklerin bu değere yansımayabileceğini" belirtir. Kesin veya canlı bir sayının önemli olduğu yerde kullanmayın.

DynamoDB SUM veya AVG yapabilir mi? Yerel olarak değil ve PartiQL'de değil — PartiQL SELECT dilbilgisi toplama işlevlerine sahip değildir. Uygulamanızda toplayın, bir sayaç tutun (isteğe bağlı olarak DynamoDB Streams aracılığıyla) ya da SUM/AVG'yi DynoTable'ın SQL Workbench'inde çalıştırın.

Count ile ScannedCount arasındaki fark nedir? ScannedCount, DynamoDB'nin filtrenizden önce kaç item değerlendirdiğidir; Count, ondan sonra kaçının kaldığıdır. Filtre ifadesi olmadığında eşittirler. Aralarındaki büyük bir fark, verimsiz bir sayım anlamına gelir.


DynamoDB verilerinizi bir tarama döngüsü yazmadan toplamak, ortalamasını almak veya gruplamak mı gerekiyor? DynoTable'ı indirin ve bir Workbench sekmesinde çalıştırın. Önce istemcileri mi karşılaştırıyorsunuz? Düz bir DynamoDB GUI karşısında nerede durduğuna bakın.

Güncellendi