Query vs Scan dans DynamoDB
Query lit une seule collection d'items par clé de partition (en restreignant
éventuellement la clé de tri) ; Scan lit la table entière et filtre ensuite.
Ils se ressemblent dans l'API mais ils facturent — et passent à l'échelle —
complètement différemment.
Quand dois-je utiliser Query plutôt que Scan dans DynamoDB ?
Utilise Query dès que tu peux nommer la partition dont tu as besoin — il lit une seule collection d'items et ne facture que les items correspondants. Recours à Scan uniquement pour des exports ponctuels ou de petites tables ; il lit chaque item et facture la table entière avant même qu'un FilterExpression s'exécute. Sur des données réelles, Query l'emporte.
- Query est ciblée : tu paies pour les items de la partition correspondante.
- Scan est exhaustif : tu paies pour lire chaque item, puis tu en jettes la
plupart avec un
FilterExpressionqui s'exécute après que la lecture a été facturée.
Sur une table d'une taille réelle, un Scan avec un filtre est le piège classique
du « pourquoi ma facture est-elle énorme et ma latence pire que RDS ».
Côte à côte
| Query | Scan | |
|---|---|---|
| Lectures | Une partition (par PK) | Chaque item de la table |
| Capacité facturée | Items correspondants dans la partition | Table entière, avant filtrage |
FilterExpression | Appliqué après la lecture — toujours facturé pour la lecture | Idem — le filtrage ne réduit jamais le coût |
| Latence | Constante quand la table grandit | Croît avec la taille de la table |
| Pagination | 1 MB/page → LastEvaluatedKey | 1 MB/page ; parallélisable |
| À utiliser pour | Modes d'accès connus | Exports ponctuels, petites tables de config |
Le piège clé : un FilterExpression s'exécute après que DynamoDB a facturé la
lecture, sur les deux opérations. Un Scan qui « renvoie 10 lignes » peut facturer
la lecture d'un million — le filtrage est un confort, jamais un contrôle de coût.
Utilise Query
Query PK = "USER#42" AND SK begins_with "ORDER#"
Si tu te surprends à recourir à Scan pour répondre à un mode d'accès courant,
c'est un signal de modélisation : ajoute un
Global Secondary Index pour que le pattern devienne un
Query.
Le choix se résume à une seule question — peux-tu nommer la partition dont tu as besoin ?
Si la clé est connue, tu fais un Query ; sinon, ajoute un GSI pour en faire un, et
ne te rabats sur un Scan que lorsqu'aucune clé ne convient.
Quand Scan convient
Exports ponctuels, petites tables de config et jobs en arrière-plan qui parcourent
délibérément toute la table. Utilise Segment/TotalSegments pour répartir un
Scan sur plusieurs workers (un scan parallèle) quand tu dois vraiment tout
lire.
Un SELECT * FROM table réflexe sur DynamoDB est le même anti-pattern en habit
PartiQL — il se compile en un Scan. Quand tu as vraiment besoin d'analytique
inter-items (un GROUP BY, un JOIN, un agrégat), le Workbench SQL de DynoTable
les exécute côté client sur un ensemble de résultats borné au lieu de marteler la
table.
Estime les unités de lecture que chaque pattern coûtera avec le calculateur de capacité, et essaie DynoTable pour exécuter et inspecter ces requêtes sur tes propres tables.