Başlangıç7 dakikalık okuma

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

DynamoDB'nin yerleşik tek bir toplaması vardır: eşleşen öğeleri Select=COUNT ile saymak. Yerel bir SUM, AVG, MIN veya MAX yoktur. Ve elde edebileceğin sayım bile, saydığı her öğeyi okur (ve onun için faturalandırır). Bu kılavuz, gerçekte neyin desteklendiğini, insanların başvurduğu yaklaşımları ve ihtiyaç duyduğunda bir tablo üzerinde gerçek COUNT/SUM/AVG'yi nasıl çalıştıracağını kapsar.

DynamoDB, SUM, COUNT ve toplama fonksiyonları yapabilir mi?

Çoğunlukla hayır. DynamoDB'nin tek yerleşik toplaması Select=COUNT'tur; eşleşen öğe sayılarını döndürür ama yine de her öğeyi okur (ve onun için 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, bunları uygulamanda katla, bir sayaç tut veya DynoTable'ın Workbench'inde SQL çalıştır.

  • Select=COUNT, eşleşen öğe sayısını döndürür ama DynamoDB onu üretmek için yine de her öğeyi okur — ucuz bir "sayım" maliyeti değil, tam Scan/Query okuma maliyetini ödersin.
  • Yerel bir SUM, AVG, MIN veya MAX yoktur. DynamoDB'nin okuma işlemleri öğeleri döndürür; onları bir sayıya katlamazlar. PartiQL de toplama eklemez.
  • DescribeTable.ItemCount bedavadır ama yaklaşıktır ve yalnızca "yaklaşık her altı saatte bir" güncellenir — bir gösterge paneli kutucuğu için uygundur, kesin olması gereken bir şey için yanlıştır.
  • Kesin COUNT/SUM/AVG/MIN/MAX için (GROUP BY ile), uygulamanda topla, bir sayaç tut veya DynoTable'ın SQL Workbench'inde çalıştır (aşağıda).

Öğeleri saymak: Select=COUNT

Hem Query hem de Scan bir Select parametresi kabul eder. Onu COUNT yaparsan, yanıt öğeler yerine sayımları 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 sana iki sayı verir (AWS: Sonuçlardaki öğeleri sayma):

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

Yalnızca 'e sahipsen ve onun içindeki mükerrerleri sayman gerekiyorsa, geçirdiğin koşul + filtre tam olarak DynamoDB Expression Builder'ın ürettiği şeydir — yukarıdaki FilterExpression ve ExpressionAttributeNames/Values haritaları, artı bir Query üzerinden tek bir partition içinde saydığında KeyConditionExpression — JSON'ı elle kaçırmadan.

Büyük tablolar sayan insanların ayağını kaydıran iki tuzak daha:

  • 1 MB sayfa limiti hâlâ geçerlidir. "Scan sonuç kümesinin boyutu 1 MB'tan büyükse, ScannedCount ve Count, toplam öğelerin yalnızca kısmi bir sayısını temsil eder" (AWS Scan dokümanları). Gerçek sayıyı elde etmek için, her yanıtın LastEvaluatedKey'ini bir sonraki isteğin ExclusiveStartKey'i olarak besleyerek ve çalışan bir toplam tutarak sayfalamalısın — DynamoDB sayfalamada kapsanan aynı döngü.
  • Dar bir Query, bir Scan'i yener. Bir Query üzerindeki Select=COUNT, tüm tabloyu değil, yalnızca hedeflenen partition'daki öğeleri ölçer. Bir partition key sabitleyebiliyorsan (temel tablo veya bir GSI), orada say — bu, sayıma uygulanan Query-vs-Scan maliyet farkıdır.

Select=COUNT vs ItemCount (ve neden eskidir)

DescribeTable, bedava, 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 her altı saatte bir günceller. Son değişiklikler bu değere yansımayabilir." Yani tablonun gerçek durumunun oldukça gerisinde kalabilir.

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

Kaba bir "bu tablo ne kadar büyük" iç kontrolü ya da bir gösterge paneli kutucuğu için ItemCount kullan. Kesin, filtrelenmiş veya güncel bir sayıya ihtiyacın olduğunda Select=COUNT kullan — ve okuma maliyetini kabul et. Gerçekten canlı ve bedava olan bir şey için, bir sayacı kendin izle (aşağıdaki Toplama desenleri).

Neden yerel SUM/AVG/MIN/MAX yok

DynamoDB'nin okuma işlemleri öğeleri döndürür. Bir sonuç kümesini bir skalere katlayacak bir sorgu planlayıcısı yoktur, dolayısıyla 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 grameri SELECT {{expression}} [, …] FROM {{table}}[.{{index}}] [WHERE …] [ORDER BY {{key}} …]'dir; burada ifade, "* joker karakterinden ya da bir veya daha fazla öznitelik adı veya belge yolundan oluşan bir projeksiyon listesinden oluşan bir projeksiyondur." O gramerde toplama fonksiyonu ve GROUP BY cümlesi yoktur — ve ORDER BY bir {{key}} alır ki "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, dolayısıyla SELECT SUM(total) FROM "Orders" basitçe ifade edilemez. (PartiQL tavanı hakkında dahası PartiQL vs SQL'de.)

Toplama desenleri (sayaçlar, akışlar, uygulama tarafı)

DynamoDB senin için toplama yapmadığına göre, yerleşik desenler işi başka yere iter:

  • Tutulan sayaç öğesi. Özel bir öğe tut (örn. PK = "STATS#orders") ve her yazmada bir UpdateItem ile sayısal bir özniteliğe ADD ekle. Toplamı okumak o zaman tek bir GetItem'dır — kesin ve ucuz, ama artırma mantığını, tutarlılığını ve tek bir sayaç örsleniyorsa çekişmesini sen sahiplenirsin.
  • Bir toplayıcıyı besleyen . Bir akış etkinleştir ve öğeler değiştikçe çalışan toplamları (sayımlar, toplamlar) güncelleyen bir Lambda'ya bağla. AWS Streams dokümanlarına göre, akışın StreamViewType'ını her kaydın NEW_AND_OLD_IMAGES — "öğenin hem yeni hem de eski imajlarını" — taşıyacak şekilde yapılandırabilirsin; bu, yeniden taramadan SUM tarzı toplamaları güncel tutmaya yeter. Akış kayıtları 24 saatlik bir ömre tabidir ("bir shard içindeki akış kayıtları 24 saat sonra otomatik olarak kaldırılır"), dolayısıyla tüketici ayak uydurmalıdır.
  • Uygulama tarafı katlama. Eşleşen öğeler arasında sayfa dola ve kendi kodunda SUM/AVG/MIN/MAX'i biriktir. Doğru, ama her seferinde her öğeyi okur (ve onun için faturalandırır) — Select=COUNT ile aynı maliyet profili, artı veri aktarımı.
  • Analitiğe boşalt. Ağır veya ad-hoc analitik toplama için, tabloyu S3'e dışa aktar ve Athena ile sorgula ya da bir ambara akıt. AWS S3'e dışa aktarma dokümanlarına göre, dışa aktarma "okuma kapasitesi birimleri tüketmez" ve "Athena gibi AWS hizmetlerini kullanarak analitik ve karmaşık sorgular yapmana" izin verir — istek başına toplamayı aştığında AWS'nin önerdiği yol.

Her biri, ya yazma zamanı defter tutma (sayaçlar, akışlar) ya da okuma zamanı maliyeti (uygulama tarafı taramalar) karşılığında sadeliği takas eder. Hiçbir desen, DynamoDB'nin kendisinin bir SUM'ı bedavaya hesaplamasını sağlamaz. Bu takasın gruplama sürümü — tüm tablo üzerinde değil, anahtar başına toplama — kendi kılavuzudur: DynamoDB GROUP BY.

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

Sadece yanıta ihtiyacın olduğunda — "kaç OPEN sipariş var ve toplamları ne" — sayfalayan bir tarama döngüsü veya bir Lambda yazmadan, DynoTable'ın SQL Workbench'i gerçek toplamalar çalıştırır. Tablolarını DynamoDB'nin gerçek Query/Scan çalışma zamanı üzerinden somutlaştırır, sonra üzerinde tek bir SELECT çalıştırır — toplamalar, GROUP BY, HAVING, DISTINCT: DynamoDB'nin erişim modeli kurallarının 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; hesaplanmış bir toplama üzerinde COUNT, SUM, AVG, MIN, MAX, GROUP BY ve ORDER BY'dır — hiçbirini DynamoDB veya PartiQL ifade edemez (PartiQL'in ORDER BY'ı anahtar özniteliklerle sınırlıdır) — tek bir ifadede. Bu, DynamoDB için SQL ile aynı analitik kamadır; tam gruplama hikayesi için bkz. DynamoDB GROUP BY.

Workbench, altındaki erişim modeli konusunda dürüsttür, sahte bir Postgres değildir:

  • Satırlar yine DynamoDB'nin gerçek Query/Scan'i üzerinden gelir. Tüm bir tablo üzerindeki bir GROUP BY, altında yine bir Scan'dir — Workbench bu maliyeti gizlemek yerine yüzeye çıkarır, aynı Query-vs-Scan takası.
  • Toplamalar, satırlar geldikten sonra somutlaştırılmış skaler öznitelikler üzerinde çalışır.

SSS

DynamoDB'de tarama yapmadan öğeleri sayabilir miyim? Tam olarak değil. Kesin, güncel bir sayım için öğeleri okumalısın — Select=COUNT yine sayılan her öğeyi ölçer. Tek tarama-yapmayan seçenekler, yaklaşık DescribeTable.ItemCount (~her 6 saatte güncellenir) veya her yazmada kendin tuttuğun bir sayaç öğesidir.

Bir GSI'ye göre öğeleri nasıl sayarım? Index'e karşı Select=COUNT ile bir Query (veya Scan) çalıştır. Dar bir GSI partition'ı üzerinden saymak, temel tabloyu taramaktan çok daha ucuzdur, çünkü yalnızca o index partition'ındaki öğeleri okursun — index'i ihtiyacın olan sayımın etrafında modelle.

DescribeTable.ItemCount doğru mu? Yaklaşıktır. API referansı, DynamoDB'nin ItemCount ve TableSizeBytes'i "yaklaşık 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 kullanma.

DynamoDB SUM veya AVG yapabilir mi? Yerel olarak değil ve PartiQL'de değil — PartiQL SELECT gramerinin toplama fonksiyonu yoktur. Uygulamanda topla, bir sayaç tut (isteğe bağlı olarak DynamoDB Streams aracılığıyla) veya SUM/AVG'yi DynoTable'ın SQL Workbench'inde çalıştır.

Count ile ScannedCount arasındaki fark nedir? ScannedCount, DynamoDB'nin filtren öncesinde kaç öğe değerlendirdiğidir; Count ise sonrasında kaçının kaldığıdır. Filtre ifadesi yokken eşittirler. Aralarındaki büyük bir boşluk, verimsiz bir sayım anlamına gelir.


DynamoDB verini bir tarama döngüsü yazmadan toplamak, ortalamak veya gruplamak mı istiyorsun? DynoTable'ı indir ve bir Workbench sekmesinde çalıştır. Önce istemcileri mi karşılaştırıyorsun? Düz bir DynamoDB GUI'ye karşı nerede durduğunu gör.

Güncellendi