Quelle est la méthode recommandée pour supprimer un grand nombre d'éléments de DynamoDB?

111

J'écris un service de journalisation simple dans DynamoDB.

J'ai une table de journaux qui est saisie par un hachage user_id et une plage d'horodatage (Unix epoch int).

Lorsqu'un utilisateur du service met fin à son compte, je dois supprimer tous les éléments du tableau, quelle que soit la valeur de la plage.

Quelle est la méthode recommandée pour effectuer ce type d'opération (en gardant à l'esprit qu'il pourrait y avoir des millions d'éléments à supprimer)?

Mes options, d'après ce que je peux voir, sont:

R: Effectuez une opération de numérisation, appelant la suppression sur chaque élément retourné, jusqu'à ce qu'il ne reste plus d'éléments

B: Effectuez une opération BatchGet, en appelant à nouveau delete sur chaque élément jusqu'à ce qu'il n'en reste plus

Ces deux éléments me semblent terribles car ils prendront beaucoup de temps.

Ce que je veux idéalement faire est d'appeler LogTable.DeleteItem (user_id) - Sans fournir la plage, et faites-le tout supprimer pour moi.

Tyler
la source

Réponses:

52

Ce que je veux idéalement faire est d'appeler LogTable.DeleteItem (user_id) - Sans fournir la plage, et faites-le tout supprimer pour moi.

Une demande compréhensible en effet; Je peux imaginer que des opérations avancées comme celles-ci pourraient être ajoutées au fil du temps par l'équipe AWS (ils ont l'habitude de commencer avec un ensemble de fonctionnalités limité et d'évaluer les extensions en fonction des commentaires des clients), mais voici ce que vous devez faire pour éviter le coût de une analyse complète au moins:

  1. Utilisez Query plutôt que Scan pour récupérer tous les éléments pour user_id- cela fonctionne quelle que soit la clé primaire de hachage / plage combinée utilisée, car HashKeyValue et RangeKeyCondition sont des paramètres distincts dans cette API et le premier cible uniquement la valeur d'attribut du composant de hachage du composite clé primaire. .

    • Veuillez noter que vous devrez gérer la pagination de l'API de requête ici comme d'habitude, voir le paramètre ExclusiveStartKey :

      Clé primaire de l'élément à partir de laquelle poursuivre une requête précédente. Une requête antérieure peut fournir cette valeur en tant que LastEvaluatedKey si cette opération de requête a été interrompue avant de terminer la requête; soit en raison de la taille du jeu de résultats, soit du paramètre Limit. Le LastEvaluatedKey peut être renvoyé dans une nouvelle demande de requête pour poursuivre l'opération à partir de ce point.

  2. Boucle sur tous les articles retournés et soit faciliter DeleteItem comme d'habitude

    • Mise à jour : BatchWriteItem est probablement plus approprié pour un cas d'utilisation comme celui-ci (voir ci-dessous pour plus de détails).

Mettre à jour

Comme souligné par ivant , l' opération BatchWriteItem vous permet de mettre ou de supprimer plusieurs éléments sur plusieurs tables en un seul appel d'API [c'est moi qui souligne] :

Pour télécharger un élément, vous pouvez utiliser l'API PutItem et pour supprimer un élément, vous pouvez utiliser l'API DeleteItem. Toutefois, lorsque vous souhaitez télécharger ou supprimer de grandes quantités de données, comme le téléchargement de grandes quantités de données depuis Amazon Elastic MapReduce (EMR) ou migrer des données d'une autre base de données vers Amazon DynamoDB, cette API offre une alternative efficace.

Veuillez noter que cela a encore quelques limitations pertinentes, notamment:

  • Opérations maximales dans une seule demande - Vous pouvez spécifier un total de 25 opérations d'insertion ou de suppression au maximum; cependant, la taille totale de la demande ne peut pas dépasser 1 Mo (la charge utile HTTP).

  • Pas une opération atomique - Les opérations individuelles spécifiées dans un BatchWriteItem sont atomiques; cependant BatchWriteItem dans son ensemble est une opération "best-effort" et non une opération atomique. Autrement dit, dans une demande BatchWriteItem, certaines opérations peuvent réussir et d'autres peuvent échouer. [...]

Néanmoins, cela offre évidemment un gain potentiellement significatif pour des cas d'utilisation comme celui qui nous occupe.

Steffen Opel
la source
4
Je pense qu'il serait logique d'utiliser la suppression par lots pour la deuxième étape (c'est "masqué" comme une opération d'écriture par lots )
ivant
1
@ivant - merci beaucoup pour l'indication, cette fonctionnalité de suppression "masquée" de BatchWriteItem m'a effectivement échappé à l'époque; J'ai mis à jour la réponse en conséquence.
Steffen Opel
pour la suppression avec des BatchWriteIteméléments doivent être spécifiés viaTableWriteItems
Neil
1
Le lien vers BatchWriteItem est maintenant docs.aws.amazon.com/amazondynamodb/latest/APIReference/…
Tony
3
Je me rends compte que c'est vieux et que l'OP n'a pas mentionné un SDK de langage spécifique, mais en Python, il existe un haut niveau batch_writer()dans l' boto3.resource.TableAPI qui "gérera automatiquement la mise en mémoire tampon et l'envoi d'éléments par lots. De plus, le rédacteur de lots va gérer automatiquement tous les éléments non traités et les renvoyer si nécessaire "c'est-à-dire que c'est un wrapper autour de BatchWriteItem qui gère les parties ennuyeuses. boto3.amazonaws.com/v1/documentation/api/latest/reference/…
Davos
46

Selon la documentation DynamoDB, vous pouvez simplement supprimer la table complète.

Voir ci-dessous:

"La suppression d'une table entière est beaucoup plus efficace que la suppression des éléments un par un, ce qui double essentiellement le débit d'écriture car vous effectuez autant d'opérations de suppression que d'opérations put"

Si vous souhaitez supprimer uniquement un sous-ensemble de vos données, vous pouvez créer des tableaux séparés pour chaque mois, année ou similaire. De cette façon, vous pouvez supprimer "le mois dernier" et conserver le reste de vos données intactes.

Voici comment supprimer une table en Java à l'aide du kit AWS SDK:

DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
  .withTableName(tableName);
DeleteTableResult result = client.deleteTable(deleteTableRequest);
Jonathan
la source
8
J'aime aussi cette réponse mais attention: cela pourrait créer de nombreuses tables dans votre système et nous payons par disposition de table. Vous devez donc réduire le provisionnement après la fin du mois (si votre table est mensuelle) tant que cette table n'est pas supprimée.
Sergio MC Figueiredo
2
d'accord avec cette réponse, elle est appliquée si vous devez supprimer tous les enregistrements de la table, mais ici, l'interrogateur souhaite supprimer les entrées de la base d'utilisateurs et non la table entière.
Ihtsham Minhas
1
Avoir une table de table séparée pour chaque utilisateur serait coûteux compte tenu de la tarification DynamoDB. Une table par mois aggraverait les choses. C'est clairement une réponse à un problème différent et très spécifique.
André Werlang
11
La suppression de la table peut également ne pas être une option intéressante si vous utilisez le provisionnement automatisé tel que CloudFormation pour gérer votre table dans le cadre d'une pile. Je ne connais pas un moyen simple de faire recréer à CloudFormation une table que vous avez supprimée manuellement.
brabster
2
Cette approche prend un peu de temps pour supprimer et recréer (si nécessaire) la table, la rendant indisponible pendant tout le temps. La question énonce clairement la suppression des données utilisateur, ce qui ne serait pas pratique à diviser en tables distinctes par utilisateur.
André Werlang
13

Si vous souhaitez supprimer des éléments après un certain temps, par exemple après un mois, utilisez simplement l'option Time To Live. Il ne comptera pas les unités d'écriture.

Dans votre cas, j'ajouterais ttl lorsque les journaux expirent et je les laisserais après la suppression d'un utilisateur. TTL s'assurerait que les journaux sont finalement supprimés.

Lorsque Time To Live est activé sur une table, un travail d'arrière-plan vérifie l'attribut TTL des éléments pour voir s'ils sont expirés.

DynamoDB supprime généralement les éléments expirés dans les 48 heures suivant l'expiration. La durée exacte pendant laquelle un élément est réellement supprimé après l'expiration est spécifique à la nature de la charge de travail et à la taille de la table. Les éléments qui ont expiré et qui n'ont pas été supprimés apparaîtront toujours dans les lectures, requêtes et analyses. Ces éléments peuvent toujours être mis à jour et les mises à jour réussies pour modifier ou supprimer l'attribut d'expiration seront honorées.

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html

Lukas Liesis
la source
l'ajout de TTL est une "mise à jour" (opération d'écriture). Je ne suis pas sûr qu'il y ait un gain à faire une "mise à jour" au lieu d'une "suppression".
Tomer
vous pouvez insérer ces données avec l'écriture d'origine et les mettre à jour avec toute autre action de mise à jour. Bien sûr, ce n'est pas une option si vous avez un tas de données et que vous souhaitez ensuite les supprimer. Mais c'est une option valide pour les cas où vous pouvez avoir ttl pour les données que vous insérez ou mettez à jour.
Lukas Liesis
1
Je suis d'accord, s'il y a déjà TTL configuré et que le nettoyage peut attendre jusqu'à 48 heures, c'est certainement l'option optimale. Mes excuses si je n'étais pas clair.
Tomer
4

La réponse à cette question dépend du nombre d'articles et de leur taille et de votre budget. Cela dépend de cela, nous avons 3 cas suivants:

1- Le nombre d'articles et la taille des articles dans le tableau ne sont pas beaucoup. Ensuite, comme Steffen Opel l'a dit, vous pouvez utiliser la requête plutôt que le scan pour récupérer tous les éléments pour user_id, puis parcourir tous les éléments retournés et faciliter DeleteItemouBatchWriteItem. Mais gardez à l'esprit que vous risquez de brûler beaucoup de capacité de débit ici. Par exemple, considérez une situation où vous devez supprimer 1 000 éléments d'une table DynamoDB. Supposons que chaque élément a une taille de 1 Ko, ce qui entraîne environ 1 Mo de données. Cette tâche de suppression en bloc nécessitera un total de 2000 unités de capacité d'écriture pour l'interrogation et la suppression. Pour effectuer ce chargement de données dans les 10 secondes (ce qui n'est même pas considéré comme rapide dans certaines applications), vous devez définir le débit d'écriture provisionné de la table sur 200 unités de capacité d'écriture. Comme vous pouvez le voir, il est possible d'utiliser cette méthode si c'est pour moins d'articles ou des articles de petite taille.

2- Nous avons beaucoup d'articles ou de très gros articles dans la table et nous pouvons les stocker en fonction du temps dans différentes tables. Ensuite, comme Jonathan l'a dit, vous pouvez simplement supprimer la table. c'est beaucoup mieux mais je ne pense pas que cela corresponde à votre cas. Comme vous souhaitez supprimer toutes les données des utilisateurs quelle que soit l'heure de création des journaux, dans ce cas, vous ne pouvez pas supprimer une table particulière. si vous voulez avoir une table séparée pour chaque utilisateur, je suppose que si le nombre d'utilisateurs est élevé, c'est tellement cher et ce n'est pas pratique pour votre cas.

3- Si vous avez beaucoup de données et que vous ne pouvez pas diviser vos données chaudes et froides en différentes tables et que vous devez faire des suppressions à grande échelle fréquemment, malheureusement DynamoDB n'est pas du tout une bonne option pour vous. Cela peut devenir plus cher ou très lent (dépend de votre budget). Dans ces cas, je recommande de trouver une autre base de données pour vos données.

Iman Sedighi
la source
0

Mon approche pour supprimer toutes les lignes d'une table i DynamoDb consiste simplement à extraire toutes les lignes de la table, à l'aide de DynamoDbs ScanAsync, puis à transmettre la liste de résultats à DynamoDbs AddDeleteItems. Le code ci-dessous en C # fonctionne très bien pour moi.

        public async Task DeleteAllReadModelEntitiesInTable()
    {
        List<ReadModelEntity> readModels;

        var conditions = new List<ScanCondition>();
        readModels = await _context.ScanAsync<ReadModelEntity>(conditions).GetRemainingAsync();

        var batchWork = _context.CreateBatchWrite<ReadModelEntity>();
        batchWork.AddDeleteItems(readModels);
        await batchWork.ExecuteAsync();
    }

Remarque: la suppression de la table puis sa recréation à partir de la console Web peut entraîner des problèmes si vous utilisez YAML / CloudFront pour créer la table.

Mohammad
la source
0

Nous n'avons pas la possibilité de tronquer les tables dynamo. nous devons laisser tomber la table et créer à nouveau. Les frais DynamoDB sont basés sur ReadCapacityUnits et WriteCapacityUnits. Si nous supprimons tous les éléments à l'aide de la fonction BatchWriteItem, il utilisera WriteCapacityUnits.Il est donc préférable de supprimer des enregistrements spécifiques ou de supprimer la table et de recommencer.

Shraavan Hebbar
la source