从DynamoDB中删除大量项目的推荐方法是什么?

Tyl*_*ler 88 database cloud amazon-web-services nosql amazon-dynamodb

我正在DynamoDB中编写一个简单的日志记录服务.

我有一个日志表,由user_id哈希和时间戳(Unix epoch int)范围键入.

当服务的用户终止其帐户时,我需要删除表中的所有项目,而不管范围值如何.

这种操作的推荐方法是什么(请记住可能有数百万项要删除)?

据我所知,我的选择是:

答:执行扫描操作,在每个返回的项目上调用删除,直到没有剩余项目

B:执行BatchGet操作,再次对每个项目调用delete,直到没有剩下

这些对我来说都很糟糕,因为它们需要很长时间.

我理想的做法是调用LogTable.DeleteItem(user_id) - 不提供范围,并让它为我删除所有内容.

Ste*_*pel 46

我理想的做法是调用LogTable.DeleteItem(user_id) - 不提供范围,并让它为我删除所有内容.

确实可以理解的要求; 我可以想象这些高级操作可能会随着时间的推移而被AWS团队添加(他们有首先从有限的功能集开始并根据客户反馈评估扩展的历史),但这是你应该做的,以避免成本至少完整扫描:

  1. 使用Query而不是Scan来检索所有项目user_id- 无论使用何种组合散列/范围主键,这都有效,因为HashKeyValueRangeKeyCondition是此API中的单独参数,前者仅针对复合的散列组件Attribute值首要的关键..

    • 请注意,您必须像往常一样处理查询API分页,请参阅ExclusiveStartKey参数:

      从中继续先前查询的项的主键.如果在完成查询之前该查询操作被中断,则较早的查询可能将此值提供为LastEvaluatedKey; 由于结果集大小或Limit参数.LastEvaluatedKey可以在新的查询请求中传回,以从该点继续操作.

  2. 遍历所有返回的项目,并像往常一样方便DeleteItem

    • 更新:最有可能BatchWriteItem更适合这样的用例(详见下文).

更新

正如ivant强调的那样,BatchWriteItem操作使您能够在单个API调用中跨多个表放置或删除多个项目[强调我的]:

要上传一个项目,您可以使用PutItem API并删除一个项目,您可以使用DeleteItem API.但是,当您要上载或删除大量数据(例如从Amazon Elastic MapReduce(EMR)上载大量数据或将数据从其他数据库迁移到Amazon DynamoDB)时,此API提供了一种有效的替代方案.

请注意,这仍有一些相关的限制,最值得注意的是:

  • 单个请求中的最大操作数 - 您最多可以指定25个放置或删除操作; 但是,总请求大小不能超过1 MB(HTTP有效负载).

  • 不是原子操作 - BatchWriteItem中指定的单个操作是原子操作; 但BatchWriteItem作为一个整体是"尽力而为"的操作而不是原子操作.也就是说,在BatchWriteItem请求中,某些操作可能会成功,而其他操作可能会失败.[...]

然而,这显然为像手头的用例提供了潜在的显着收益.

  • 我意识到这是旧的,并且 OP 没有提到特定语言的 SDK,但是在 Python 中有一个高级的 `batch_writer()` 作为 `boto3.resource.Table` API 的一部分,它将“自动处理缓冲和批量发送项目。此外,批处理编写器还将自动处理任何未处理的项目并根据需要重新发送它们”,即它是 BatchWriteItem 的包装器,用于管理烦人的部分。https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Table.batch_writer (4认同)
  • 我认为第二步使用批量删除是有意义的(它被"掩盖"为[批量写入操作](http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/batch-operation-lowlevel-java的.html)) (3认同)

jon*_*han 45

根据DynamoDB文档,您可以删除整个表.

见下文:

"删除整个表比逐个删除项目效率要高得多,这实际上使写入吞吐量翻了一倍,就像执行put操作一样多的删除操作"

如果您只想删除数据的一部分,那么您可以为每个月,每年或类似的表单创建单独的表.这样您就可以删除"上个月"并保持其余数据的完整性.

这是使用AWS SDK在Java中删除表的方法:

DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
  .withTableName(tableName);
DeleteTableResult result = client.deleteTable(deleteTableRequest);
Run Code Online (Sandbox Code Playgroud)

  • 如果您使用CloudFormation等自动配置将表作为堆栈的一部分进行管理,则删除表也可能不是一个有吸引力的选项.我不知道一种简单的方法可以让CloudFormation重新创建一个手动删除的表. (8认同)
  • 我也喜欢这个答案,但请注意:这可能会在您的系统中创建许多表格,并且我们按表格付费.因此,您需要在月末之后减少配置(如果您的表是每月),而不删除此表. (7认同)
  • 同意这个答案,它适用于你需要删除表中的所有记录,但这里的提问者想要删除用户基本条目而不是整个表. (2认同)
  • 这种方法需要花费大量时间来删除和重新创建表(需要时),从而使其在整个时间内都不可用。该问题明确指出要删除用户数据,这对于将每个用户表拆分成单独的表是不切实际的。 (2认同)
  • 我相信删除并重新创建表将停止使用该表 ARN 的任何 lambda(或其他系统)对更改的监控 (2认同)

Luk*_*kas 8

如果您想在一段时间后删除项目,例如一个月后,只需使用生存时间选项.它不会计算写入单位.

在您的情况下,我会在日志过期时添加ttl,并在删除用户后保留这些内容.TTL会确保最终删除日志.

在表上启用"生存时间"时,后台作业将检查项目的TTL属性以查看它们是否已过期.

DynamoDB通常会在到期后48小时内删除过期的项目.到期后项目真正被删除的确切持续时间特定于工作负载的性质和表的大小.已过期但尚未删除的项目仍将显示在读取,查询和扫描中.这些项目仍然可以更新,并且将更新成功更新以更改或删除过期属性.

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

  • 我同意,如果已经配置了 TTL 并且清理可以等待长达 48 小时,那绝对是最佳选择。如果我不清楚,我很抱歉。 (2认同)

Ima*_*ghi 6

这个问题的答案取决于物品的数量、大小和您的预算。取决于我们有以下 3 种情况:

1-表中的项目数量和项目大小不是很多。然后正如 Steffen Opel 所说,您可以使用 Query 而不是 Scan 来检索 user_id 的所有项目,然后遍历所有返回的项目,并促进DeleteItemBatchWriteItem. 但请记住,您可能会在这里消耗大量吞吐量。例如,假设您需要从 DynamoDB 表中删除 1000 个项目。假设每个项目的大小为 1 KB,导致大约 1MB 的数据。此批量删除任务将需要总共 2000 个写入容量单位进行查询和删除。要在 10 秒内执行此数据加载(在某些应用程序中甚至认为速度不快),您需要将表的预配置写入吞吐量设置为 200 个写入容量单位。正如您所看到的,如果它用于较少数量的物品或小尺寸的物品,则可以使用这种方式。

2-我们有很多项目或非常大的项目在表中,我们可以根据时间将它们存储到不同的表中。然后就像乔纳森说的那样,您可以删除该表。这好多了,但我认为它与您的情况不符。由于无论何时创建日志,您都希望删除所有用户数据,因此在这种情况下您无法删除特定表。如果你想为每个用户有一个单独的表,那么我猜如果用户数量很高,那么它太贵了,这对你的情况不切实际。

3- 如果您有大量数据并且无法将冷热数据划分到不同的表中,并且需要经常进行大规模删除,那么不幸的是,DynamoDB 根本不是您的好选择。它可能会变得更贵或很慢(取决于您的预算)。在这些情况下,我建议为您的数据找到另一个数据库。