DynamoDB Estratégias de filtragem
"Filtrar" em DynamoDB significa quatro coisas diferentes usando a mesma palavra. Três
restrinja os dados antes de serem lidos e cobrados; um — aquele chamado Filtro —
restringe depois. Saber qual é qual é a maior parte da habilidade.
Como funciona a filtragem em DynamoDB?
DynamoDB tem quatro maneiras de filtrar e apenas uma é executada após a cobrança. Oescolhe uma partição, a chave de classificação restringe uma fatia e um índice esparso filtra por presença de atributo – todos os três reduzem o custo de leitura antes da medição. Um FilterExpression é executado após a leitura, diminuindo a resposta, mas nunca a conta.
- é o filtro mais barato: ele escolhe a partição, então você nunca toque no resto da mesa.
- filtra dentro de uma partição com
begins_with,between,<,>— ainda antes do faturamento, ainda barato. - filtros por ausência: um item só aparece no índice se tem o atributo indexado, então o índice é o conjunto filtrado.
FilterExpressioné a armadilha: ela é executada após DynamoDB medir a leitura, então isso reduz o tamanho da sua resposta, mas nunca a sua conta.
Configure o exemplo
Um catálogo de produtos. Uma tabela, chave de partição PK, chave de classificação SK:
PK = "DEPT#kitchen" SK = "PROD#00194"
Cada produto também carrega price, inStock (um booleano) e clearanceAt
(um carimbo de data/hora unix, presente apenas em itens marcados para liberação). Itens em um
departamento compartilha uma partição, classificada por ID do produto.
Queremos quatro padrões de acesso. Cada um mapeia para uma estratégia de filtragem diferente –
e a escolha errada em qualquer um deles é um Scan pelo qual você pagará para sempre.
Filtrar por chave de partição
"Dê-me todos os produtos da 'cozinha'." A chave de partição responde diretamente:
Query PK = "DEPT#kitchen"
DynamoDB lê exatamente uma partição. Nada mais na mesa é tocado ou
faturado. Este é o único filtro gratuito no sentido que importa - é o
diferença entre Query e Scan.
Vindo de SQL, parece ao contrário: não há WHERE departamento = 'cozinha'
digitalizando um índice, basta nomear a partição. Se você não consegue nomeá-lo, isso é um
problema de modelagem, não um problema de consulta.
Filtrar por chave de classificação
"Dê-me produtos de cozinha de PROD#00100 em diante." A chave de classificação restringe dentro
a partição, e faz isso antes que a leitura seja medida:
Query PK = "DEPT#kitchen" AND SK between "PROD#00100" AND "PROD#00200"
As condições da chave de classificação são limitadas propositalmente: =, <, <=, >, >=,
entre e begins_with. Sem OR, sem predicado arbitrário.
Essa restrição é o que mantém a leitura direcionada - DynamoDB percorre um caminho contíguo fatia, não a partição inteira.
A alavanca aqui é como você codifica a chave de classificação. Se o seu padrão for "por preço
band", uma chave de classificação PROD#<id> não ajudará - você incluiria o preço na chave.
Essa é uma decisão de estratégia de classificação, tomada em tempo de design, não em tempo de consulta.
Filtrar por índice esparso
"Dê-me tudo que está atualmente em liquidação." A maioria dos produtos não é, então você não quero ler o catálogo para encontrar os poucos que existem.
Um índice esparso resolve isso por ausência. UMapenas contém um item se esse item tiver ambos os atributos-chave do índice.
Defina um sinalizador constante clearance = "CLEARANCE" como a chave de partição GSI -
escrito apenas em itens de liquidação - com clearanceAt como chave de classificação e o
índice não contém mais nada.
AWS explica isso: um índice secundário global contém apenas itens que possuem o atributos-chave do índice, portanto, os itens que faltam o atributo-chave simplesmente não são propagado ([AWS — Aproveite as vantagens de índices esparsos][esparsos]).
Agora a consulta lê apenas os itens de liquidação, faturados apenas por eles:
Query ON ClearanceIndex GSI_PK = "CLEARANCE" (sorted by clearanceAt)
O filtro aconteceu quando você escreveu os dados - escolhendo se deseja definir
clearanceAt em absoluto. O índice é o conjunto filtrado. Veja
GSI vs LSI para qual tipo de índice se ajusta.
Filtrar com FilterExpression
“Dê-me produtos de cozinha que estejam em estoque.” inStock não é um atributo chave,
então você pega um FilterExpression:
Query PK = "DEPT#kitchen"
Filter inStock = true
DynamoDB lê cada item na partição cozinha, mede a capacidade para
todos eles, e então descarta os que estão fora de estoque.
AWS afirma que uma expressão de filtro é "aplicada após o término de Query, mas
antes que os resultados sejam retornados" e "um Query consome a mesma quantidade de leitura
capacidade, independentemente de uma expressão de filtro estar presente" — você já
pago pela leitura completa (AWS — Filtrar expressões para Query).
Então se a cozinha tem 10.000 produtos e 12 estão em estoque, você paga para ler 10.000.
A resposta é pequena; a conta não é. FilterExpression reduz a carga útil
cruzando o fio, nunca a leitura.
Há uma segunda vantagem mais nítida: a paginação é medida antes da filtragem. Uma página é 1 MB de itens lidos, não 1 MB de correspondências.
Um filtro pode retornar uma página vazia com um conjunto LastEvaluatedKey - DynamoDB leia um
megabyte completo, não correspondeu a nada, entregou a você um array vazio. Você continua paginando e
você pagou por cada página vazia.
Construa a expressão - nomes, valores e o escape correto da palavra reservada - com
o DynamoDB Expression Builder então o
Os espaços reservados #inStock/:val estão corretos na primeira tentativa.
O construtor abaixo está predefinido para Scan com FilterExpression — o exato
antipadrão acima. Observe que o filtro é executado em toda a tabela, não em uma fatia chave:
Compare os quatro
| Quando filtra | Reduz o custo de leitura? | Poder predicado | Custo de configuração | |
|---|---|---|---|---|
| Chave de partição | Antes de ler | Sim — uma partição | Apenas igualdade | Grátis (é a chave) |
| Chave de classificação | Antes de ler | Sim – uma fatia | Faixa / begins_with | Design de chave de classificação |
| Índice esparso | Antes de ler | Sim — somente índice | Presença de um atributo | Extra GSI + custo de gravação |
| FilterExpression | Depois de ler | Não | Quase qualquer condição | Nenhum |
Leia a tabela de cima a baixo: o poder do predicado aumenta, o controle de custos aumenta
para baixo. FilterExpression pode expressar qualquer coisa precisamente porque roda em
itens já lidos - é a mesma razão pela qual você não pode economizar dinheiro.
Veja no DynoTable
Quando você executa um Query com um filtro, a lacuna entre os itens lidos e os itens
retornado é a história toda. DynoTable mostra os itens digitalizados ao lado dos itens
retornado como fluxos de leitura filtrados - portanto, um filtro que lê silenciosamente toda a partição fica visível, não
escondido em sua fatura mensal.
Para perguntas genuínas sobre itens cruzados, um filtro não consegue responder — "preço médio por
departamento", "produtos em estoque associados às suas avaliações" — DynoTable's SQL
Workbench executa GROUP BY, JOIN e agrega o lado do cliente em um limite
conjunto de resultados, em vez de compilar para um Scan de toda a tabela.
Armadilhas e próximos passos
- Não use
FilterExpressioncomo seu caminho de acesso principal. Se um padrão for comum, modele-o em uma chave ou em um índice esparso. Um filtro é para o último pouco um pouco de estreitamento, não a maior parte. - Observar páginas vazias. Uma consulta filtrada pode retornar uma página por um longo tempo
nada. Honre
LastEvaluatedKey; não presuma que uma página vazia significa "pronto". - Um índice esparso não é gratuito. Custa capacidade de gravação e armazenamento para cada item que cai nele — barato quando o atributo é raro, menos quando não é.
Estime quanto custará realmente uma leitura filtrada com o calculadora de preços e tente DynoTable para observar a capacidade consumida em relação às linhas retornadas em suas próprias mesas.