Débutant7 min de lecture

Pourquoi un Scan DynamoDB est lent et coûteux

Un Scan lit chaque item de la table et ne filtre qu'ensuite. C'est l'opération que tu sors par mémoire musculaire SQL, et celle qui fait discrètement grimper ta facture tout en empirant ta latence par rapport à la machine RDS que tu as quittée.

Pourquoi mon Scan DynamoDB est-il lent et coûteux ?

Un Scan lit chaque item de la table avant l'exécution du FilterExpression, donc tu paies pour lire toute la table quel que soit le nombre de lignes renvoyées, et ça devient plus lent à mesure que la table grandit. Le correctif est presque toujours un Query clé — modélise le motif d'accès autour d'une clé pour que DynamoDB ne touche qu'une seule partition au lieu de tout.

  • Un Scan lit toute la table, à chaque fois. La taille, pas ton nombre de résultats, décide ce que tu paies et combien de temps ça prend.
  • Le FilterExpression est un mensonge sur le coût. Il s'exécute après que la lecture est mesurée, donc renvoyer 12 items peut facturer la lecture de 12 millions.
  • Un Scan ralentit à mesure que tu grandis. Un Query clé reste plat — il touche une seule partition quelle que soit la taille de la table.
  • Le correctif est presque toujours la modélisation, pas le réglage. Si tu fais un Scan pour répondre à une question de routine, il te manque une clé.

Ce qu'un Scan fait réellement

Venant de SQL, SELECT * FROM events WHERE type = 'checkout' semble gratuit — le moteur a un index, ou non, mais dans les deux cas tu récupères des lignes. Dans DynamoDB il n'y a pas de planificateur de requêtes qui décide ça pour toi.

Un Scan parcourt toute la table séquentiellement, 1 Mo à la fois, et remet chaque page à ton FilterExpression. Ce que le filtre rejette est quand même lu, quand même mesuré, et quand même sur ta facture. (AWS : Scanning tables)

C'est le piège. Le filtre ressemble à une clause WHERE, mais il change l'ensemble de résultats, jamais le coût. Un Scan consomme la même capacité de lecture, qu'un filtre soit présent ou non. (AWS : Scanning tables)

Compte les read units

DynamoDB mesure les lectures en read capacity units (RCU). Une RCU achète une seule lecture fortement cohérente d'un item jusqu'à 4 Ko ; les lectures à cohérence à terme coûtent la moitié. Les items plus gros arrondissent au prochain 4 Ko. (AWS : Read/write capacity mode)

Prends une table d'analytique, ProductEvents. Chaque ligne est un événement suivi :

PK  = "TENANT#acme"
SK  = "TS#2026-06-23T14:08:55Z#evt_9f3a"
attrs: eventType, sessionId, userId, payloadBytes

Disons qu'elle contient 2 000 000 événements, chacun ~1 Ko, tous sous un seul locataire occupé. Tu veux les checkouts d'aujourd'hui. Le mouvement réflexe :

Scan ProductEvents
FilterExpression: eventType = "checkout"

Ce filtre pourrait renvoyer 40 lignes. Mais le Scan a d'abord lu les 2 000 000 items. À ~1 Ko chacun (1 RCU par 4 Ko, à cohérence à terme ≈ 0,5 RCU par 4 Ko), tu as mesuré à peu près 250 000 RCU — et paginé à travers ~500 Mo de données — pour remettre 40 items.

Maintenant modélise le motif d'accès comme une clé et fais un Query à la place :

Query ProductEvents
PK = "TENANT#acme"
AND SK begins_with "TS#2026-06-23"

Ça ne lit que la tranche matchée d'une seule partition. Si ces 40 lignes de checkout plus les autres événements du jour font ~2 Mo, tu paies pour ~2 Mo de lectures, pas 500 Mo. Même réponse, une fraction minuscule du coût — et la latence reste plate à mesure que la table grandit.

Scan vs Query, mesurés

Scan + filtreQuery clé
LitChaque item de la tableUne partition, restreinte par SK
Capacité facturéeToute la table, avant le filtreSeulement les items de ta tranche
Notre exemple~250 000 RCU (~500 Mo)quelques centaines de RCU (~2 Mo)
LatenceCroît avec la taille de la tablePlate à mesure que la table grandit
Nombre de résultatsNe décide rien sur le coûtCorrespond à ce que tu paies

La leçon que la table encode : sur un Scan, ton nombre de résultats et ta facture sont sans rapport. Sur un Query, ils se suivent.

Décide avant de Scan

La plupart des Scan accidentels viennent d'une question : puis-je nommer la partition dont j'ai besoin ? Si oui, c'est un Query. Si non, le correctif est une clé, pas un plus gros filtre.

Voici la décision sous forme de flux.

OuiNonOuiNonBesoin de lire des itemsConnaît la clé de partition ?Query une partitionUn GSI peut-il la clé ?Ajouter un GSI, puis QueryScan dernier recours

Le chemin se termine presque toujours sur Query ; tu ne retombes sur Scan que quand aucune clé — présente ou ajoutable — ne convient au motif d'accès.

Si le motif est réel et récurrent mais que la table de base ne peut pas le clé, c'est le signal d'ajouter un Global Secondary Index pour que la question devienne un Query. Modéliser tes clés autour de tes motifs d'accès dès le départ est tout le jeu — vois single-table design.

Écris la requête clée, pas un filtre

Quand tu as besoin d'une condition au-delà de la clé, construis-la délibérément plutôt que de tout déverser dans un FilterExpression. Le DynamoDB Expression Builder génère la KeyConditionExpression et les placeholders d'attribut pour toi, pour que la clé de partition et la clé de tri fassent la restriction — avant que DynamoDB mesure la lecture, pas après.

KeyConditionExpression: PK = :tenant AND begins_with(SK, :day)

Quand un Scan est réellement acceptable

Un Scan n'est pas interdit — c'est juste le mauvais défaut. C'est le bon outil quand tu veux véritablement dire « tout lire » :

  • Exports ponctuels ou backfills lancés à la main.
  • Petites tables de config / de lookup où toute la table fait quelques Ko.
  • Tâches de fond qui paginent toute la table exprès. Découpe-les entre des workers avec Segment / TotalSegments — un scan parallèle — au lieu d'un seul long parcours séquentiel. (AWS : Scanning tables)

Et note que PartiQL ne te sauve pas : SELECT * FROM ProductEvents WHERE eventType = 'checkout' sans prédicat de clé compile directement en un Scan. C'est la même arme à fragmentation en habits SQL. (Vois Query vs Scan pour le décorticage complet.)

Quand tu as vraiment besoin d'analytique inter-items — un GROUP BY, un JOIN, un agrégat que DynamoDB ne peut pas exprimer — le SQL Workbench de DynoTable les exécute côté client sur un ensemble de résultats borné, au lieu de marteler la table avec un Scan complet.

Étapes suivantes

Estime ce que coûte chaque motif avec le calculateur de capacité, lis Query vs Scan pour le contraste au niveau de l'API, et télécharge DynoTable pour les exécuter contre tes propres tables et regarder toi-même la capacité consommée.

Mis à jour