Intermédiaire4 min de lecture

Single-Table Design dans DynamoDB

Venant du SQL, l'instinct est une table par entité : customers, orders, order_items. Dans DynamoDB, cet instinct est généralement faux. Une seule table qui stocke chaque entité, distinguée par des préfixes de clé surchargés, te laisse récupérer un parent et ses enfants en un seul Query — pas de jointures, pas de N+1.

Pars des modes d'accès, pas des entités

Le single-table design est orienté modes-d'accès-d'abord. Avant de choisir une clé unique, note chaque lecture que ton app effectue — « récupérer le profil d'un client », « lister les commandes d'un client du plus récent au plus ancien », « trouver toutes les commandes ouvertes » — car les clés n'existent que pour servir cette liste. La normalisation relationnelle optimise le stockage ; la modélisation DynamoDB optimise les requêtes que tu sais déjà devoir exécuter. Énumère-les, puis conçois les clés pour que chacune soit un seul Query.

L'idée

Choisis des noms de clé génériques (PK, SK) et encode le type d'entité dans la valeur :

PKSKattributes
CUSTOMER#42PROFILEname, email, plan
CUSTOMER#42ORDER#2026-001total, status
CUSTOMER#42ORDER#2026-002total, status

Maintenant un seul Query PK = "CUSTOMER#42" renvoie le profil et chaque commande en une seule lecture facturée. SK begins_with "ORDER#" le restreint aux seules commandes.

Visuellement, les items surchargés s'empilent sous une seule clé de partition comme une seule collection d'items :

Partition: CUSTOMER#42SK: PROFILESK: ORDER#2026-001SK: ORDER#2026-002One Query

Une seule lecture de la partition renvoie le client et chaque commande ensemble.

GSI surchargés

La même astuce fonctionne sur les index. Mets un GSI1PK/GSI1SK générique sur les items, et un seul GSI sert plusieurs modes d'accès selon ce que chaque item écrit dans ces attributs :

PKSKGSI1PKGSI1SK
ORDER#001METADATASTATUS#OPEN2026-01-04
ORDER#002METADATASTATUS#OPEN2026-01-05

Maintenant Query GSI1 WHERE GSI1PK = "STATUS#OPEN" liste les commandes ouvertes par date — un pattern auquel la table de base ne peut pas répondre. Une entité différente peut réutiliser GSI1 avec sa propre signification (par ex. CATEGORY#books). Un index, plusieurs requêtes.

Plusieurs-à-plusieurs : la liste d'adjacence

Pour les relations (un utilisateur dans plusieurs équipes, une équipe avec plusieurs utilisateurs), écris l'arête deux fois avec les ids inversés : PK=USER#1, SK=TEAM#9 et PK=TEAM#9, SK=USER#1. Requêter un côté liste l'autre — le substitut DynamoDB d'une table de jointure.

Quand ne pas faire de single-table

Ce n'est pas gratuit. Une table surchargée est plus difficile à raisonner, plus difficile à faire évoluer et hostile à l'analytique. Si tes modes d'accès sont réellement inconnus ou changent constamment, ou si les données sont surtout analytiques, des tables séparées (ou un autre stockage) peuvent être le choix plus sain. Le single-table gagne quand les patterns sont connus et à fort volume.

Coût de la mauvaise forme

Modéliser en tables séparées force un Scan ou une jointure côté client pour réassembler un client, et c'est le piège du Scan. Modélise d'abord les modes d'accès, puis conçois les clés pour que chacun soit un Query.

Estime ce que ces items coûtent par lecture avec le calculateur de taille d'item et de capacité, et essaie DynoTable pour parcourir un schema single-table et voir les collections surchargées côte à côte.

Mis à jour