【问题标题】:Should I always create my DynamoDB tables using hash and range primary key type?我是否应该始终使用散列和范围主键类型创建我的 DynamoDB 表?
【发布时间】:2015-07-06 17:21:31
【问题描述】:

在文档 (http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/APISummary.html) 中指出:

只能查询主键为 hash-and-range 类型的表

我们建议您设计您的应用程序,以便您可以主要使用查询操作,并仅在适当的情况下使用扫描

没有直接说明,但这是否使使用散列和范围主键成为最佳实践?

编辑:

回答 TL;DR:使用对您的数据模型有意义的任何主键类型,并使用二级索引以获得更好的查询支持。

参考资料:

http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html

http://www.allthingsdistributed.com/2013/12/dynamodb-global-secondary-indexes.html

https://forums.aws.amazon.com/thread.jspa?messageID=604862

In what situation do you use Simple Hash Keys on DynamoDB?

【问题讨论】:

    标签: amazon-dynamodb


    【解决方案1】:

    不一定。最好为您的用例选择支持访问模式的主键。

    例如,假设您想为 Users 提供一个表格。您将存储单个用户的详细信息(姓名、电子邮件、创建者等)。您的访问模式可能是您正在获取特定用户的详细信息。在这种情况下,使用 hash 类型的主键和 userId 的散列键更有意义。

    假设您还想要另一个存储的表。您的访问模式可能是您希望获取给定组的所有成员。在这里,使用 hash 和 range 类型的主键更有意义,您的 hash 和 range 键分别是 groupIduserId

    需要了解的重要事项是differences between both key types(以下引用)和Guidelines for Working with Tables

    • 哈希类型主键——主键由一个属性组成,即哈希属性。 DynamoDB 在此基础上构建无序哈希索引
      主键属性。表中的每个项目都是唯一标识
      通过它的哈希键值。

    • 哈希和范围类型主键——主键由两个属性组成。第一个属性是哈希属性,第二个
      一个是范围属性。 DynamoDB 构建无序哈希索引
      在散列主键属性上,以及在
      范围主键属性。表中的每个项目都是唯一的
      由其哈希和范围键值的组合标识。它是 两个项目可能具有相同的哈希键值,但是这两个 项目必须具有不同的范围键值。

    您可以在 Dynamo DB Guidelines for Working with Tables documentation 中查看有关最佳实践的更多信息

    【讨论】:

    • 谢谢!在评论了@spin 的答案后,我查看了你的答案,看到你使用了我使用的确切示例。我了解 Hash 和 Hash-and-Range 之间的区别,但我的困难是使用 Hash Type Primary Key 查询表。比如说,我想通过电子邮件在登录时查找用户,但我还没有 userId,我该怎么做呢?也许答案在我还没有完全掌握的二级索引中,但是文档的那部分使得在使用哈希主键的表上执行Query 似乎是不可能的。
    • 我使用userId 作为我的示例,但您也可以轻松地使用emailAddress 作为哈希键(取决于您的设计和访问权限)。假设您有 emailAddress 作为表的 hash 键。当您想使用emailAddress 访问此表中的项目时,您可以拨打GetItem 电话。您不能仅在emailAddress 上查询此表。如果您需要使用其他属性作为键来访问此表,则必须创建一个索引并针对该索引进行查询。该索引也可以是 hash / hash-range,您可以设置要投射到其上的属性。
    • 谢谢。我知道我可以使用email 作为我的哈希键,但我最常见的用例是通过userId 查找。假设我有一个 REST 资源 GET /users/1 我可以轻松查询 userId 1。这比通过电子邮件查询要普遍得多,我主要用于登录。假设,如果我要说“我唯一一次想要通过电子邮件查询正在登录”进行条件扫描而不是创建二级索引会更好吗?我知道扫描会贵得多,但由于这是一个相对罕见的动作,可能还可以,对吧?再次感谢!
    【解决方案2】:

    使用哪个键的选择取决于特定场景的用例和数据要求。例如,如果您要存储 User Session 数据,则使用 Range Key 可能没有多大意义,因为每条记录都可以由 GUID 引用并直接访问而无需分组要求.一般来说,一旦你知道了 Session Id,你就可以通过键获得特定的项目查询。另一个示例可能是存储用户帐户或个人资料数据,每个用户都有自己的数据,您很可能会直接访问它(通过用户 ID 或其他内容)。

    但是,如果您要存储 Order Items,则 Range Key 更有意义,因为您可能想要检索按其 Order 分组的项目时间>。

    数据模型而言,Hash Key可以让你从你的表中唯一标识一条记录,而Range Key可以可选地用于对通常一起检索的多条记录进行分组和排序。示例:如果您要定义一个聚合来存储 Order Items,则 Order Id 可以是您的 Hash Key,而 OrderItemId 范围键。每当您想从特定的Order 中搜索Order Items 时,您只需通过哈希键(Order Id)进行查询,您就会得到所有的订单项目

    您可以在下面找到使用这两个键的正式定义:

    "Composite Hash Key with Range Key 允许开发者创建一个 主键是两个属性的组合,一个'散列 属性”和“范围属性”。查询复合材料时 key,hash属性需要唯一匹配但是一个范围 可以为范围属性指定操作:例如所有订单 过去 24 小时内来自维尔纳的比赛,或个人参加的所有比赛 过去 24 小时内的玩家。”[VOGELS]

    所以 Range KeyData Model 添加了分组功能,然而,这两个 Key 的使用对 Storage Model:

    "Dynamo 使用一致的散列将其键空间划分为 副本并确保均匀的负载分布。统一的钥匙 分布可以帮助我们实现均匀的负载分布,假设 密钥的访问分布没有高度倾斜。” [DDB-SOSP2007]

    Hash Key不仅可以唯一标识记录,也是保证负载分布的机制。 范围键(使用时)有助于指示将大部分一起检索的记录,因此,也可以针对这种需要优化存储。

    选择正确的键来表示您的数据是您设计过程中最关键的方面之一,它直接影响您的应用程序的性能、规模和成本。


    脚注:

    • 数据模型是我们感知和操作数据的模型。它描述了我们如何与数据库中的数据交互 [FOWLER]。换句话说,它是您抽象数据模型的方式、对实体进行分组的方式、选择作为主键的属性等

    • 存储模型描述了数据库如何在内部存储和操作数据 [FOWLER]。尽管您无法直接控制这一点,但您当然可以通过了解数据库内部的工作方式来优化数据的检索或写入方式。

    【讨论】:

    • 感谢您的详细回答。我知道我可以使用它们的哈希键访问哈希键表中的项目,但是问题就变成了确定项目的哈希键。举一个简单的例子,当用户使用电子邮件和密码登录时,主键是userId。登录时不知道userId,需要查询email。 (我可以使用email 作为主键,但我无法通过userId 进行查找)。我还没有深入了解本地和全球索引,但我觉得我的答案可能就在那里。
    • 根据您在 Vogels 博客上链接到的文章,我正在寻找 GSI。 “此外,GSI 的性能旨在满足 DynamoDB 的个位数毫秒延迟 - 您可以将项目添加到具有数千万用户的游戏应用程序的用户表中,用户 ID 作为主键,但根据他们的家乡检索它们,不会降低查询性能。”
    • Vogels 博客中的示例使用 hash-and-range 类型的主键。仅使用哈希主键可以实现相同的目标吗?
    • 好的,我想我有这个。你能帮我确认一下吗?我可以使用userId 作为哈希主键(无范围)创建user 表。然后我可以创建一个主键为email 的GSI UserEmailIndex,这将给我userId(因为主键总是投影到GSI 中)。然后我可以通过使用提供的email 查询UserEmailIndex 来获取userId,然后使用userId 我可以从user 表中获取项目。
    • 这是有道理的,你可以有一个带有 email#password 作为哈希键和 userId 作为属性的表......你的登录过程将尝试使用计算的哈希键执行一个简单的 GetItem,如果返回了 userId,你不仅有认证过程的确认,还有检索其他用户信息的密钥。
    【解决方案3】:

    正如其他人已经说过的 - 不,你不应该。

    首先让你困惑并导致你问这个问题的陈述是错误

    只能查询主键为 hash-and-range 类型的表

    可以查询主键为单属性(仅分区)类型的表。

    证明:

    # Create single-attribute primary key table
    aws dynamodb create-table --table-name testdb6 --attribute-definitions '[{"AttributeName": "Id", "AttributeType": "S"}]' --key-schema '[{"AttributeName": "Id", "KeyType": "HASH"}]' --provisioned-throughput '{"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}' 
    
    # Populate table
    aws dynamodb put-item --table-name testdb6 --item '{ "Id": {"S": "1"}, "LastName": {"S": "Lopez"}, "FirstName": {"S": "Maria"}}'
    aws dynamodb put-item --table-name testdb6 --item '{ "Id": {"S": "2"}, "LastName": {"S": "Fernandez"}, "FirstName": {"S": "Augusto"}}'
    
    # Query table using only partition attribute
    aws dynamodb query --table-name testdb6 --select ALL_ATTRIBUTES --key-conditions '{"Id": {"AttributeValueList": [{"S": "1"}], "ComparisonOperator": "EQ"}}'
    

    最后一条命令的输出(有效):

    {
    "Count": 1,
    "Items": [
        {
            "LastName": {
                "S": "Lopez"
            },
            "Id": {
                "S": "1"
            },
            "FirstName": {
                "S": "Maria"
            }
        }
    ],
    "ScannedCount": 1,
    "ConsumedCapacity": null
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-21
      • 2019-04-20
      • 2011-05-30
      • 2010-10-24
      • 1970-01-01
      • 2020-08-06
      • 1970-01-01
      相关资源
      最近更新 更多