DynamoDB GROUP BY: Como agregar
Não há GROUP BY em DynamoDB. Não há COUNT, SUM ou AVG
também - não no nativo API, e não em PartiQL. DynamoDB é um valor-chave /
armazenamento de documentos, não um mecanismo de análise, então a agregação é algo que você
construir, não algo que o planejador de consultas faça por você.
Você pode GROUP BY em DynamoDB?
DynamoDB não tem GROUP BY, HAVING ou funções agregadas como COUNT, SUM e AVG - nem no nativo API e nem em PartiQL, cujo SELECT aceita apenas WHERE e ORDER BY. Você agrega pré-computando totais conforme alterações de dados (contadores atômicos ou+ Rollups Lambda) ou agrupando o lado do aplicativo após a leitura.
- A gramática
SELECTde DynamoDB PartiQL éSELECT… FROM… [WHERE …] [ORDER BY…]- e essa é a lista completa. Sem
GROUP BY, semHAVING, sem agregação funções, semJOIN(AWS PartiQLSELECTreferência).
- e essa é a lista completa. Sem
- Porque DynamoDB "não suporta nativamente operações de agregação como
SUMouCOUNTentre itens", a orientação do próprio AWS é pré-calcular agregados conforme os dados mudam e armazenam os resultados como itens comuns (AWS: agregação materializada). - A alternativa – ler cada item e depois agregá-lo em seu aplicativo – funciona, mas você pague para ler a tabela inteira em cada consulta.
- Para exploração única, SQL Workbench de DynoTable executa
GROUP BY/COUNT/SUM/AVGdiretamente em uma tabela ativa — os SQL DynamoDB's O terminal PartiQL é rejeitado.
Por que a agregação é difícil em DynamoDB
DynamoDB não possui mecanismo de agregação de tempo de varredura. Query e Scan retornam itens;
eles não os dobram. Um Scan lê a tabela inteira 1 MB por vez, e o
a capacidade que consome é baseada nos itens que lê, não nas linhas que você mantém - um
FilterExpression é aplicado após a varredura, mas antes do retorno dos resultados, então
restringe o conjunto de resultados sem diminuir a conta (AWS Scan API referência: um filtro
“não consome nenhuma unidade adicional de capacidade de leitura”; a capacidade é baseada no item
tamanho digitalizado, não devolvido). Não há gancho GROUP-BY
para gastar uma quantia ou contar em primeiro lugar.
PartiQL não muda isso. PartiQL é um dialeto SQL-compatível sobre o mesmo
motor, então ele herda os mesmos limites - é uma superfície de sintaxe, não um novo
modelo de execução. A gramática SELECT documentada
simplesmente não possui token GROUP BY.
Para saber a diferença completa entre PartiQL e SQL real, consulte
PartiQL vs SQL.
Pergunte onde está o seu agregado e quando ele é computado. Existem três respostas.
Padrão 1: agregação na gravação (contadores atômicos)
Se você conhece os grupos com antecedência – contagem por status, total por cliente, downloads por mês – mantenha um item de contador e atualize-o a cada gravação.
Use um ADDportanto, o incremento é atômico e seguro para simultaneidade.
ADD funciona com números e conjuntos e evita a corrida leitura-modificação-gravação, então
dois escritores incrementando o mesmo contador nunca se derrotam
(AWS observa o ADD atômico "evita condições de corrida de leitura-modificação-gravação"):
UpdateItem
Key { pk: "STATS#orders", sk: "status#shipped" }
UpdateExpression "ADD orderCount :one"
ExpressionAttributeValues { ":one": 1 }
Este é o seu SELECT COUNT(*)… GROUP BY status - exceto que a contagem já está
sentado lá como um item, legível em um milissegundo de um dígito GetItem. O
compensação: você deve conhecer a chave de agrupamento no momento da gravação e acoplar a
atualização do contador para o caminho de gravação. Se o aplicativo travar após a gravação, mas
antes da atualização do contador, os dois ficam fora de sincronia - que é exatamente o
modo de falha, o próximo padrão se desacopla.
Padrão 2: DynamoDB Streams + rollups Lambda
Quando você não deseja lógica de agregação no caminho de gravação — ou a gravação é um
PutItem simples você não pode quebrar facilmente - mova-o para baixo. Este é o próprio AWS
padrão recomendado, agregação materializada
(AWS: Usando GSIs para consultas de agregação materializadas):
- O aplicativo grava o item bruto (um pedido, um download, um evento). Sem agregação lógica. 2.captura a gravação como um registro de fluxo.
- Um Lambda anexado ao fluxo lê o novo item, deriva o grupo
(status, mês, categoria…) e
ADDs ao item agregado correspondente com um atômicoUpdateItem— que "evita condições de corrida de leitura-modificação-gravação" quando muitas invocações tocam o mesmo contador. - Você consulta o agregado pré-calculado — geralmente por meio de um isso
indexa apenas os itens de rollup, então "top 10 deste mês" é um
QuerycomLimite 10.
Apenas os itens agregados carregam o atributo indexado
(por exemplo, Month), para que as linhas brutas do evento sejam excluídas do índice automaticamente
— "uma pequena fração do total de itens da tabela", que mantém o índice
barato e a leitura rápida.
Isso desacopla a agregação do caminho de gravação e mantém as gravações simples, no custo de consistência eventual — AWS observa "um atraso de alguns segundos entre um download sendo gravado e a agregação sendo atualizada." Para painéis, tabelas de classificação e contadores de tendências, tudo bem.
Uma nova invocação do Lambda executa novamente o ADD, então
"uma nova tentativa aumentaria a contagem mais de uma vez", deixando um aproximado
valor. Para contagens exatas, adicione idempotência (por exemplo, uma expressão de condição digitada em
o id do item de origem); caso contrário, a pequena margem é adequada para análises e
tabelas de classificação.
Padrão 3: agrupamento do lado do aplicativo após Scan/Query
Ou leia os itens e agrupe-os em seu código.
groups = {}
resp = table.scan() # or query() for one partition
while True:
for item in resp["Items"]:
key = item["status"]
groups[key] = groups.get(key, 0) + 1
if "LastEvaluatedKey" not in resp:
break
resp = table.scan(ExclusiveStartKey=resp["LastEvaluatedKey"])Isso é correto e às vezes a decisão certa – mas seja honesto sobre o custo. Um
Scan lê todos os itens da tabela, e a capacidade de leitura é a mesma
se você filtra ou não. Portanto, agrupar o lado do aplicativo em um Scan completo significa que você paga
para ler a tabela inteira em cada agregação, e a latência aumenta com a tabela.
AWS lista "digitalizar e contar em tempo de leitura" como "adequado apenas para
conjuntos de dados onde a latência não é uma preocupação"
(AWS: Por que agregações de pré-cálculo).
Com escopo reduzido para uma única partição via Query (por exemplo, contar os pedidos para um
cliente), o agrupamento no lado do aplicativo é perfeitamente razoável - você está lendo apenas um
coleção de itens. Para a diferença total de custos entre os dois, consulte
Query vs Scan. Em us-east-1 sob demanda, uma tabela completa
Scan faturas 0,5 RCU por 4 KB eventualmente consistente para cada item examinado
— uma tabela de 1 GB de linhas de 1 KB equivale a aproximadamente 250.000 RCU antes do seu aplicativo
agrupa qualquer coisa. Dimensione um item representativo com o
calculadora de tamanho de item e, em seguida, avalie a linha
digitalize na calculadora de preços.
Para análise genuinamente ad-hoc SQL sobre uma mesa DynamoDB - o descartável
"GROUP BY status, conte-os" você executaria uma vez - a resposta de AWS é apontar um
mecanismo separado: o conector Amazon Athena DynamoDB permite consultar
a tabela com SQL real (GROUP BY, agrega e até JOINs para outras fontes)
através de um conector Lambda
(AWS: conector Amazon Athena DynamoDB).
Ele verifica a tabela nos bastidores, portanto é uma ferramenta de relatórios/BI, não um caminho ativo.
Qual padrão eu uso?
| Você precisa… | Usar |
|---|---|
| Um total de grupo conhecido em um caminho de leitura dinâmica | Padrão 1 — contador atômico (ADD) |
| Agrega sem tocar no caminho de gravação | Padrão 2 — Streams + rollup Lambda |
| Uma contagem com escopo para uma partição | Padrão 3 — Query e agrupe no aplicativo |
| Totais exatos, sem desvios | Padrão 1/2 com proteção de idempotência |
Um GROUP BY único durante a exploração | DynoTable Workbench (abaixo) ou Atenas |
| BI/relatórios recorrentes com SQL | Conector Athena DynamoDB |
Executando GROUP BY diretamente no DynoTable do SQL Workbench
Os padrões acima mostram como você atende agregados na produção. Mas quando você está explorando uma tabela - "quantos pedidos por status, agora?" - você não quer provisionar um Lambda ou stand up Athena. Você deseja digitar a consulta.
É para isso que serve o SQL Workbench de DynoTable. Funciona real SQL —
GROUP BY, COUNT, SUM, AVG, HAVING, até mesmo JOIN — diretamente contra o seu
tabelas DynamoDB ativas, executando a agregação do lado do cliente nas linhas
lê. É o SQL que o endpoint PartiQL de DynamoDB rejeita:
SELECT status, COUNT(*) AS orders, SUM(total) AS revenue
FROM "Orders"
GROUP BY status
HAVING SUM(total) > 1000
ORDER BY revenue DESCSob o capô DynoTable lê itens da maneira que API permite
(Query onde pode, Scan onde deve), materializa-os e faz o
agrupamento no Workbench - a mesma mecânica de "ler e agregar" do Padrão
3, apenas sem o loop e dentro das regras de padrão de acesso do DynamoDB. É
construído para exploração e análise ad hoc, não para substituir uma produção
rollup em um caminho de leitura quente. Para isso, pré-calcule (Padrão 1/2).
Para o lado JOIN da mesma fatia — DynoTable executa junções entre tabelas PartiQL
também não pode - consulte DynamoDB JOIN. Comparando GUI
clientes exatamente com esse recurso? Veja
a comparação da GUI DynamoDB.
FAQ
O DynamoDB PartiQL suporta GROUP BY?
Não. DynamoDB's PartiQL SELECT suporta apenas WHERE e ORDER BY - não
GROUP BY, HAVING, funções agregadas ou JOIN. A gramática é
documentado
como SELECT… FROM… [WHERE…] [ORDER BY…].
Posso fazer COUNT(*) em uma tabela DynamoDB inteira?
Não como uma função agregada — PartiQL não tem nenhuma. O API oferece
Select=COUNT em Scan/Query, que retorna uma contagem de itens correspondentes mas
ainda lê (e fatura) cada item que a digitalização toca
(AWS Scan API referência:
a capacidade é baseada em itens examinados, não devolvidos). Para uma leitura frequente
total, mantenha um item contador (Padrão 1).
Posso GROUP BY a chave de partição?
Não em DynamoDB ou PartiQL. Se "por chave de partição" for um padrão de acesso conhecido,
mantenha um item agregado por chave com um ADD atômico (Padrão 1) ou role-o
com Streams + Lambda (Padrão 2).
Como faço SUM ou AVG por grupo?
SUM: mantém um total em execução por grupo e ADD a ele na gravação. AVG: armazenar
tanto a soma quanto a contagem e divisão no momento da leitura - não há média nativa.
Para um AVG exploratório único, execute-o no DynoTable do SQL Workbench ou através do
Conector Athena DynamoDB.
Existe uma solução alternativa para partiql group by?
Não há lado PartiQL. Pré-calcule o agregado (contadores/Streams) e
SELECT o item de rollup ou execute GROUP BY em um mecanismo que tenha um -
DynoTable's Workbench para ad-hoc, Athena para relatórios recorrentes.
Quer executar GROUP BY em suas próprias tabelas sem escrever um Lambda?
Experimente DynoTable e aponte o SQL Workbench para uma mesa ao vivo.