【问题标题】:Composite key in DynamoDB with more than 2 columns?DynamoDB 中超过 2 列的复合键?
【发布时间】:2015-08-31 18:51:47
【问题描述】:

我正在探索在我工作的应用程序中使用 DynamoDB,该应用程序目前只有一个数据库组件——在 RDS 上运行的 MySQL 数据库。

我们大量使用 AWS 并为我们的数据库使用分片方案,但它只能让我们在没有人工干预的情况下走到这一步。在使用 Aurora 时,我实际上看到与我们的 MySQL 数据库相比性能显着下降,因此我正在评估 DynamoDB 以查看它是否适合我们,因为它可以有效地存储 JSON 数据,并且还可以轻松扩展(只需增加读取或写入每秒在 AWS 控制台中,让 Amazon 完成繁重的工作)。

在我们的几个 MySQL 表中,我们有一个主键,它是一个自动增量列,但我们还有几个索引以支持其他方式的查询性能。其他索引至关重要,因为我们的一些表中有超过 10 亿行。本质上,我们在客户端、object_name 等之间进行分区。所以我可能会在 MySQL 中做这样的事情:

Create Table: CREATE TABLE `record` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `client_id` int(10) unsigned NOT NULL,
  `data_id_start` bigint(20) unsigned NOT NULL,
  `data_id_end` bigint(20) unsigned NOT NULL DEFAULT '8888888888888888',
  `object_name` varchar(255) NOT NULL,
  `uuid` varchar(255) NOT NULL,
  `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
  ...
  PRIMARY KEY (`id`),
  ...
  KEY `client_id_object_name_data_id_data_id_end_deleted` (`client_id`,`object_name`,`data_id_start`,`data_id_end`,`deleted`),
  KEY `client_id_object_name_data_id_end_uuid_id` (`client_id`,`object_name`,`data_id_end`,`uuid_id`),
  ...
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

我正在评估将其中的一些数据复制到 DynamoDB 中以用作缓存,因此在某些情况下我们不必去 S3 检索存储的数据。相反,我将直接将 JSON 数据存储在缓存中。在 DynamoDB 中,看起来我可以在键中使用 HASH 或 HASH 和 RANGE 属性。例如,我可以使用 MySQL 表中的自动增量列作为 HASH,但是我看到的所有 RANGE 键、全局/本地二级索引等示例只指定 ONE 其他属性作为范围。当“where”子句中指定了 3 个或更多值时,我想创建一个索引以进行高效查找。

例如,我想使用这样的表达式来查询这个表:

var params = {
    TableName: "Cache",
    KeyConditionExpression: "clientId = :clientId and objectName = :objectName and uuid = :uuid",
    ExpressionAttributeValues: {
        ":clientId": 17,
        ":objectName": "Some name",
        ":uuid": "ABC123-KDJFK3244-CCB"
    }
};

请注意,我在 KeyConditionExpression 中的“where 子句”使用了 3 个值。那里可能有 4 或 5 个值。那么在 DynamoDB 中是否有任何方法可以创建包含 2 个以上属性(列)的复合键?

如果不是,我想我可以将 3 列连接成一个字符串,并将其用作每次插入时的主键。或者至少连接 clientId 和 objectName,然后使用 uuid 作为 RANGE 或类似的东西。实际上,我需要翻阅特定 clientId/objectName 组合的所有值,然后根据每行中的某些属性直接从缓存中获取其值,或者将其视为未命中并从 S3 检索值(即慢得多)。

【问题讨论】:

    标签: amazon-web-services amazon-dynamodb


    【解决方案1】:

    为此,DynamoDB 允许对基本上无限量的数据进行一致的低延迟查询。您建议的连接值的模型似乎是一个好方法。

    需要注意的一点是,哈希键属性值限制为 2048 字节。如果您要连接的值不是可预测的长度(您不能很好地填充它们)或超过此限制,那么对项目的值进行散列并根据项目的散列进行搜索可能是一种更好的方法。以下是有关限制的相关文档:https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html。 DynamoDB 项目的总数据也限制为 400KB。

    为了正确起见,我还将为范围键使用一些唯一标识符,这将允许哈希值发生冲突(即使它很少见),并且架构是可扩展的,因为每个哈希键值有少量项目。

    【讨论】:

    • 嗯...如果我将客户端和对象连接起来,它实际上会导致相当多的冲突。我们的一些客户拥有 2400 万个相同类型的对象。如果那是哈希值,那将是很多冲突。那么每条记录的唯一 ID 可能是一个 RANGE,但同样——这仍然是一个非常大量的潜在冲突。但是您能回答我是否可以创建包含 2 列以上的索引的问题吗?
    • 您不能创建超过 2 列的索引。如果数据模型适合,此限制允许 DynamoDB 以任何规模提供一致的低延迟写入/读取。你能提供更多关于为什么会有这么多碰撞的信息吗?如果每个客户端 ID 都是唯一的,并且每个客户端都有唯一的对象名称,这将提供一个很好的均匀分布的哈希键值。
    • 好的,谢谢。 2 列与我随处可见的内容相得益彰。同样,我们的客户可以拥有数百万个相同类型的对象。所以连接 clientId + objectName 意味着数百万条记录都具有相同的哈希值。 uuid 可以是唯一的 RANGE 属性,但是 24M+ 记录可能具有相同的哈希值,然后 uuid 会打破平局,这是一个问题吗?如果这是关系,我会做类似“SELECT * FROM cache WHERE client_id=? AND object_name=? LIMIT X OFFSET Y”之类的事情,然后对所有记录进行分页。
    • 如果单个哈希键的读/写访问频率高于其他键,您可能会遇到热键问题(因此具有相同哈希的 24M+ 记录可能会非常有问题)。所以同一个clientId有重复的objectName值吗?最好的方法是在散列键值中使用一些具有 clientId 和 objectName 的唯一值进行查找。由于哈希键值可以是 2048 字节,因此哈希键有 2^(2048*8) ~ 10^4932 个可能的值。
    • 是的。这是 Salesforce 数据,因此单个客户可能拥有数百万个客户对象。选择可能类似于:mysql> select client_id, object_name, uuid from record; | 1 |帐户 | AB1 | | 1 |帐户 | AB2 | | 1 |帐户 | AB3 | ...也许我应该在 (client_id, object_name) 上使用另一个 MySQL 数据库和索引,但我看不出这与 Dynamo 中的哈希冲突有何不同。
    猜你喜欢
    • 2023-01-19
    • 2015-06-04
    • 2013-12-19
    • 2016-05-17
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    • 2022-09-28
    • 1970-01-01
    相关资源
    最近更新 更多