什么是哈希和范围主键?

Posted

技术标签:

【中文标题】什么是哈希和范围主键?【英文标题】:What is Hash and Range Primary Key? 【发布时间】:2015-02-04 10:10:59 【问题描述】:

我无法理解 Working with Tables and Data in DynamoDB 文档中的范围/主键是什么

它是如何工作的?

“哈希属性上的无序哈希索引和范围属性上的排序范围索引”是什么意思?

【问题讨论】:

【参考方案1】:

哈希和范围主键”表示 DynamoDB 中的单行具有由 哈希范围 组成的唯一主键强>键。例如,使用 X 的哈希键和 Y 的范围键,您的主键实际上是 XY。同一个哈希键也可以有多个范围键,但组合必须是唯一的,例如 XZXA。让我们为每种类型的表使用他们的示例:

Hash Primary Key - 主键由一个属性组成,一个哈希 属性。例如,ProductCatalog 表的 ProductID 可以为 它的主键。 DynamoDB 在此基础上构建无序哈希索引 主键属性。

这意味着每一行都与该值无关。 DynamoDB 中的每一行都将为此属性设置一个必需的唯一值。无序哈希索引意味着所说的 - 数据没有排序,并且您无法保证数据的存储方式。 您将无法对无序索引进行查询,例如获取 ProductID 大于 X 的所有行。您根据散列键写入和获取项目。例如,从表中获取 ProductID X 的行。您正在对无序索引进行查询,因此您对它的查询基本上是键值查找,速度非常快,并且使用的吞吐量非常小。


Hash and Range Primary Key – 主键由两个组成 属性。第一个属性是哈希属性,第二个 属性是范围属性。例如论坛 Thread 表 可以将 ForumName 和 Subject 作为其主键,其中 ForumName 是 哈希属性和主题是范围属性。 DynamoDB 构建 散列属性上的无序散列索引和排序范围索引 在范围属性上。

这意味着每一行的主键是散列键和范围键的组合。如果您同时拥有散列键和范围键,则可以直接获取单行,或者您可以针对排序范围索引进行查询。例如,get Get me all rows from the table with Hash key X that have range keys greater than Y,或其他有影响的查询。与针对未索引字段的扫描和查询相比,它们具有更好的性能和更少的容量使用。来自their documentation:

查询结果始终按范围键排序。如果数据类型为 range键为Number,结果按数字顺序返回; 否则,结果按 ASCII 字符码的顺序返回 价值观。默认情况下,排序顺序是升序。要颠倒顺序, 将 ScanIndexForward 参数设置为 false

我在输入此内容时可能遗漏了一些东西,而我只是触及了表面。还有很多更多aspects to take into consideration when working with DynamoDB tables(吞吐量、一致性、容量、其他指标、密钥分布等)。您应该查看sample tables and data 页面以获取示例。

【讨论】:

这是我读过的最有用的堆栈溢出答案之一。 为什么没有选项只能使用没有哈希的范围?例如,如果我的所有数据都以其时间戳作为主键存储,我希望能够选择“2015 年 10 月 15 日下午 2 点到 4 点之间的所有数据” @Teofrostus,哈希键用于标识包含项目的分区。没有它,DynamoDB 将不会查看哪个分区。不知道在哪里查看会破坏查询,并且是扫描(或全局二级索引)的用例,但这不适合您只使用时间的用例系列选择数据)。 @mkobit 有什么方法可以在不扫描的情况下检索给定分区键的所有排序键? @VNR 我不确定我是否理解您在 DynamoDB 上下文中的问题。您是说在提供哈希键时获取所有哈希+范围键吗?【参考方案2】:

@mkobit 已经给出了很好解释的答案,但我将添加范围键和哈希键的大图。

简单来说range + hash key = composite primary keyCoreComponents of Dynamodb

主键由散列键和可选范围键组成。 哈希键用于选择 DynamoDB 分区。分区是 部分表数据。范围键用于对 分区(如果存在)。

所以两者都有不同的目的,并且共同帮助进行复杂的查询。 上面的例子hashkey1 can have multiple n-range.range和hashkey的另一个例子是game,userA(hashkey)可以玩Ngame(range)

表、项目和属性中描述的 Music 表是一个 具有复合主键的表示例(Artist 和 歌名)。您可以直接访问 Music 表中的任何项目,如果 您为该项目提供 Artist 和 SongTitle 值。

复合主键在查询时为您提供了额外的灵活性 数据。例如,如果您仅提供 Artist、DynamoDB 的值 检索该艺术家的所有歌曲。仅检索子集 特定艺术家的歌曲,您可以为 Artist 提供一个值 以及 SongTitle 的一系列值。

https://www.slideshare.net/InfoQ/amazon-dynamodb-design-patterns-best-practices https://www.slideshare.net/AmazonWebServices/awsome-day-2016-module-4-databases-amazon-dynamodb-and-amazon-rds https://ceyhunozgun.blogspot.com/2017/04/implementing-object-persistence-with-dynamodb.html

【讨论】:

Music 表的示例中,一位艺术家无法制作两首具有相同标题的歌曲,但令人惊讶的是 - 在视频游戏中,我们有 1993 年的《毁灭战士》和 2016 年的《毁灭战士》en.wikipedia.org/wiki/Doom_(franchise) 具有相同的“艺术家” "(开发者):id Software. 一个超级简单的解释。谢谢! 谢谢,有帮助的回答。【参考方案3】:

由于整个事情正在混淆,让我们看一下它的功能和代码,以简明扼要地模拟它的含义

获取行的唯一方法是通过主键

getRow(pk: PrimaryKey): Row

主键数据结构可以是这样的:

// If you decide your primary key is just the partition key.
class PrimaryKey(partitionKey: String)

// and in thids case
getRow(somePartitionKey): Row

但是,在这种情况下,您可以决定您的主键是分区键 + 排序键:

// if you decide your primary key is partition key + sort key
class PrimaryKey(partitionKey: String, sortKey: String)

getRow(partitionKey, sortKey): Row
getMultipleRows(partitionKey): Row[]

所以底线:

    决定你的主键只是分区键?按分区键获取单行。

    确定你的主键是分区键+排序键? 2.1 通过(分区键、排序键)获取单行或通过(分区键)获取行范围

无论哪种方式,您都可以通过主键获得单行,唯一的问题是您是否将该主键定义为仅分区键或分区键 + 排序键

构建块是:

    表 项目 KV 属性。

将 Item 视为一行,将 KV Attribute 视为该行中的单元格。

    您可以通过主键获取一个项目(一行)。 可以通过指定(HashKey, RangeKeyQuery)获取多个项目(多行)

只有当您确定您的 PK 由 (HashKey, SortKey) 组成时,您才能执行 (2)。

在我看来,它的复杂性更直观:

+----------------------------------------------------------------------------------+
|Table                                                                             |
|+------------------------------------------------------------------------------+  |
||Item                                                                          |  |
||+-----------+ +-----------+ +-----------+ +-----------+                       |  |
|||primaryKey | |kv attr    | |kv attr ...| |kv attr ...|                       |  |
||+-----------+ +-----------+ +-----------+ +-----------+                       |  |
|+------------------------------------------------------------------------------+  |
|+------------------------------------------------------------------------------+  |
||Item                                                                          |  |
||+-----------+ +-----------+ +-----------+ +-----------+ +-----------+         |  |
|||primaryKey | |kv attr    | |kv attr ...| |kv attr ...| |kv attr ...|         |  |
||+-----------+ +-----------+ +-----------+ +-----------+ +-----------+         |  |
|+------------------------------------------------------------------------------+  |
|                                                                                  |
+----------------------------------------------------------------------------------+

+----------------------------------------------------------------------------------+
|1. Always get item by PrimaryKey                                                  |
|2. PK is (Hash,RangeKey), great get MULTIPLE Items by Hash, filter/sort by range     |
|3. PK is HashKey: just get a SINGLE ITEM by hashKey                               |
|                                                      +--------------------------+|
|                                 +---------------+    |getByPK => getBy(1        ||
|                 +-----------+ +>|(HashKey,Range)|--->|hashKey, > < or startWith ||
|              +->|Composite  |-+ +---------------+    |of rangeKeys)             ||
|              |  +-----------+                        +--------------------------+|
|+-----------+ |                                                                   |
||PrimaryKey |-+                                                                   |
|+-----------+ |                                       +--------------------------+|
|              |  +-----------+   +---------------+    |getByPK => get by specific||
|              +->|HashType   |-->|get one item   |--->|hashKey                   ||
|                 +-----------+   +---------------+    |                          ||
|                                                      +--------------------------+|
+----------------------------------------------------------------------------------+

那么上面发生了什么。请注意以下观察结果。正如我们所说,我们的数据属于(Table、Item、KVAttribute)。然后每个项目都有一个主键。现在,您构成该主键的方式对于您如何访问数据是有意义的。

如果您决定 PrimaryKey 只是一个哈希键,那么您可以从中得到一个项目。但是,如果您决定主键是 hashKey + SortKey,那么您还可以对主键进行范围查询,因为您将通过 (HashKey + SomeRangeFunction(on range key)) 获取项目。因此,您可以通过主键查询获取多个项目。

注意:我没有提到二级索引。

【讨论】:

【参考方案4】:

@vnr 您可以通过使用分区键的查询来检索与分区键关联的所有排序键。无需扫描。这里的重点是分区键在查询中是强制性的。排序键仅用于获取数据范围

【讨论】:

以上是关于什么是哈希和范围主键?的主要内容,如果未能解决你的问题,请参考以下文章

一个表只能有一个主键索引,一个主键索引可以多个字段

MySQL普通索引的加锁

PHP,可以吗?将密码哈希中的字符串作为主键存储在数据库中?

如何合并两个表(包括主键和范围限制)

非聚集索引和复合主键之间的性能

多范围读取优化