Intermedio8 min di lettura

DynamoDB Strategie di filtraggio

"Filtrare" in DynamoDB significa quattro cose diverse che portano la stessa parola. Tre restringere i dati prima che vengano letti e fatturati; uno — quello denominato "Filtro" — lo restringe dopo. Sapere qual è la parte più importante dell'abilità.

Come funziona il filtraggio in DynamoDB?

DynamoDB ha quattro modi per filtrare e solo uno viene eseguito dopo l'addebito. ILseleziona una partizione, la chiave di ordinamento restringe una sezione e un indice sparso filtra in base alla presenza di attributi: tutti e tre riducono i costi di lettura prima della misurazione. Un FilterExpression viene eseguito dopo la lettura, quindi riduce la risposta ma mai il conto.

- è il filtro più economico: seleziona la partizione, quindi non lo farai mai toccare il resto della tabella. - filtra all'interno di una partizione con begins_with, between, <, > — ancora prima della fatturazione, ancora economico. -filtra per assenza: un elemento appare nell'indice solo se ha l'attributo indicizzato, quindi l'indice è l'insieme filtrato.

  • FilterExpression è la trappola: corre dopo DynamoDB metri dalla lettura, quindi riduce la dimensione della risposta ma mai la bolletta.

Imposta l'esempio

Un catalogo prodotti. Una tabella, chiave di partizione PK, chiave di ordinamento SK:

PK = "DEPT#kitchen"   SK = "PROD#00194"

Ogni prodotto riporta anche "price", "inStock" (un valore booleano) e "clearanceAt". (un timestamp unix, presente solo sugli elementi contrassegnati per l'autorizzazione). Elementi in a il reparto condivide una partizione, ordinata per ID prodotto.

Vogliamo quattro modelli di accesso. Ognuno si associa a una diversa strategia di filtraggio: e la scelta sbagliata su ognuno di essi è un Scan che pagherai per sempre.

Filtra per chiave di partizione

"Dammi ogni prodotto in cucina." La chiave di partizione risponde direttamente a questa domanda:

Query  PK = "DEPT#kitchen"

DynamoDB legge esattamente una partizione. Nient'altro nella tabella viene toccato o fatturato. Questo è l'unico filtro gratuito nel senso che conta: è il differenza tra Query e Scan.

Venendo da SQL, questo sembra al contrario: non c'è WHERE dipartimento = 'cucina' scansionando un indice, basta rinominare la partizione. Se non puoi dargli un nome, è a problema di modellazione, non un problema di query.

Filtra per chiave di ordinamento

"Dammi i prodotti da cucina dal PROD#00100 in su." La chiave di ordinamento restringe dentro la partizione, e lo fa prima che la lettura venga misurata:

Query  PK = "DEPT#kitchen"  AND  SK between "PROD#00100" AND "PROD#00200"

Le condizioni della chiave di ordinamento sono appositamente limitate: =, <, <=, >, >=, "tra" e "begins_with". Nessun "OR", nessun predicato arbitrario.

Questo vincolo è ciò che mantiene la lettura mirata: DynamoDB cammina in modo contiguo porzione, non l'intera partizione.

La leva qui è come codificare la chiave di ordinamento. Se il tuo modello è "per prezzo band", una chiave di ordinamento PROD#<id> non aiuta: inseriresti il prezzo nella chiave.

Questa è una decisione di strategia di ordinamento, presa in fase di progettazione, non in fase di query.

Filtra per indice sparso

"Dammi tutto ciò che è attualmente in liquidazione." La maggior parte dei prodotti non lo sono, quindi non lo fai tu voglio leggere il catalogo per trovare i pochi che sono.

Un indice sparso risolve questo problema per assenza. UNsolo contiene un elemento se quell'elemento ha entrambi gli attributi chiave dell'indice.

Imposta un flag costante clearance = "CLEARANCE" come chiave di partizione GSI — scritto solo su elementi da liquidare, con "clearanceAt" come chiave di ordinamento e il file l'indice non contiene nient'altro.

AWS lo spiega chiaramente: un indice secondario globale contiene solo elementi che hanno l'estensione gli attributi chiave dell'indice, quindi gli elementi a cui manca l'attributo chiave semplicemente non lo sono propagato (AWS — Approfitta degli indici sparsi).

NoTavolo base - tutti i prodottiHas clearanceAt?Replicato in ClearanceIndexNon nell'indiceQuery l'indice = solo articoli inliquidazione

Ora la query legge solo gli articoli in liquidazione, fatturati solo per essi:

Query  ON ClearanceIndex   GSI_PK = "CLEARANCE"   (sorted by clearanceAt)

Il filtro è stato attivato quando hai scritto i dati, scegliendo se impostarli "clearanceAt" affatto. L'indice è l'insieme filtrato. Vedi GSI vs LSI per quale tipo di indice si adatta.

Filtra con FilterExpression

"Dammi i prodotti da cucina che sono in stock." "inStock" non è un attributo chiave, quindi raggiungi un FilterExpression:

Query  PK = "DEPT#kitchen"
Filter inStock = true

DynamoDB legge ogni articolo nella partizione cucina, misura la capacità di tutti e poi elimina quelli esauriti.

AWS afferma che un'espressione di filtro viene "applicata al termine di Query, ma prima che i risultati vengano restituiti" e "a Query consuma la stessa quantità di lettura capacità, indipendentemente dal fatto che sia presente un'espressione di filtro" — già pagato per la lettura completa (AWS — Espressioni filtro per Query).

Quindi se "cucina" ha 10.000 prodotti e 12 sono in stock, paghi per leggerne 10.000. La risposta è piccola; il conto no. "FilterExpression" riduce il carico utile attraversando il filo, mai la lettura.

C'è un secondo aspetto più netto: l'impaginazione viene misurata prima del filtraggio. Una pagina corrisponde a 1 MB di elementi letti, non a 1 MB di corrispondenze.

Un filtro può restituire una pagina vuota con un set LastEvaluatedKey — DynamoDB leggi un megabyte pieno, non corrispondeva a nulla, ti ha consegnato un array vuoto. Continui a cercare e hai pagato per ogni pagina vuota.

Costruisci l'espressione (nomi, valori e l'escape della parola riservata corretta) con il DynamoDB Expression Builder quindi il I segnaposto #inStock/:val sono corretti al primo tentativo.

Il builder di seguito è preimpostato su Scan con FilterExpression — l'esatto anti-modello sopra. Nota che il filtro viene eseguito sull'intera tabella, non su una porzione chiave:

Costruisci la tua richiesta
Codice generato
new ScanCommand({
  "TableName": "AuditLog",
  "FilterExpression": "#filter0 = :filterValue0",
  "ExpressionAttributeNames": {
    "#filter0": "action"
  },
  "ExpressionAttributeValues": {
    ":filterValue0": {
      "S": "delete"
    }
  }
})

Confronta i quattro

Quando filtraTaglia i costi di lettura?Potere predicativoCosto per l'installazione
Chiave di partizionePrima di leggereSì, una partizioneSolo uguaglianzaLibero (è la chiave)
Chiave di ordinamentoPrima di leggereSì, una fettaIntervallo / begins_withDesign con chiave di ordinamento
Indice sparsoPrima di leggereSì: solo indicePresenza di un attributoExtra GSI + costo di scrittura
FilterExpressionDopo aver lettoNoQuasi tutte le condizioniNessuno

Leggi la tabella da cima a fondo: il potere dei predicati aumenta, il controllo dei costi diminuisce giù. FilterExpression può esprimere qualsiasi cosa proprio perché continua articoli già letti: è lo stesso motivo per cui non può farti risparmiare denaro.

Vedilo in DynoTable

Quando esegui un Query con un filtro, il divario tra gli elementi read e items restituito è tutta la storia. DynoTable mostra gli elementi scansionati accanto agli elementi restituito come flusso di lettura filtrato, quindi un filtro che legge silenziosamente l'intera partizione non è visibile nascosti nella fattura mensile.

Per domande autentiche su più articoli a cui un filtro non può rispondere: "prezzo medio per dipartimento", "prodotti in stock uniti alle loro recensioni" — DynoTable's SQL Workbench esegue GROUP BY, JOIN e aggrega il lato client su un set di risultati, invece di compilare in un Scan a livello di tabella.

Insidie e passaggi successivi

  • Non utilizzare FilterExpression come percorso di accesso principale. Se un modello lo è comune, modellalo in una chiave o in un indice sparso. Un filtro è per l'ultimo piccolo un po' di restringimento, non il grosso.
  • Guarda le pagine vuote. Una query filtrata può restituire pagine per molto tempo niente. Onore a "LastEvaluatedKey"; non dare per scontato che una pagina vuota significhi "fatto".
  • Un indice sparso non è gratuito. Richiede capacità di scrittura e archiviazione per ogni oggetto che vi arriva: economico quando l'attributo è raro, meno quando non lo è.

Stima quanto costerà effettivamente una lettura filtrata con il calcolatore dei prezzi e prova DynoTable per controllare la capacità consumata rispetto alle righe restituite i tuoi tabelle

Aggiornato