

# 在 DynamoDB 中设计并有效使用分区键的最佳实践
<a name="bp-partition-key-design"></a>

唯一标识 Amazon DynamoDB 表中每个项目的主键可以是简单结构（仅分区键）或复合结构（分区键与排序键的组合）。

应对应用程序进行设计，以便在表中的所有分区键及其二级索引中开展统一的活动。可以确定应用程序所需的访问模式，以及每个表和二级索引所需的读取与写入单位。

**注意**  
自适应容量适用于按需模式和预调配容量。

DynamoDB 表中的每个分区都设计为提供每秒 3000 个读取单位和每秒 1000 个写入单位的最大容量。一个读取单位表示对大小最多为 4 KB 的项目每秒执行一次强一致性读取操作，或每秒执行两次最终一致性读取操作。一个写入单位表示对大小最多为 1 KB 的项目每秒执行一次写入操作。

在评估表的分区吞吐量限制时，必须考虑项目大小。例如，如果表的项目大小为 20 KB，则单个一致性读取操作将使用 5 个读取单位。这意味着，在达到分区限制之前，可以每秒同时对该单个项目进行 600 次一致性读取操作。表中所有分区的总吞吐量在预置模式下可能受预调配吞吐量所限，或在按需模式下可能受表级吞吐量限制所限。有关更多信息，请参阅[服务限额](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ServiceQuotas.html)。

**Topics**
+ [

# 在 DynamoDB 中设计分区键来分配工作负载
](bp-partition-key-uniform-load.md)
+ [

# 在 DynamoDB 表中使用写入分片来均匀分配工作负载
](bp-partition-key-sharding.md)
+ [

# 在 DynamoDB 中的数据上传期间高效分配写入活动
](bp-partition-key-data-upload.md)

# 在 DynamoDB 中设计分区键来分配工作负载
<a name="bp-partition-key-uniform-load"></a>

表主键的分区键部分确定存储表数据的逻辑分区，反过来会影响底层物理分区。不能有效分配 I/O 请求的分区键设计会产生“热”分区，从而导致节流且不能有效地使用预置 I/O 容量。

要最佳使用表的预调配吞吐量，不仅取决于各个项目的工作负载模式，还取决于分区键设计。这并不意味着必须访问所有分区键值以实现高效吞吐量，或者已访问分区键值的百分比必须非常高，而是工作负载访问的分区键值越不同，请求在已分配空间分配越多。通常随着访问分区键值数量与分区键值总数的比值增加，使用预调配吞吐量的效率将提高。

下面比较一些常见分区键架构的预调配吞吐量效率。


****  

| 分区键值 | 均匀性 | 
| --- | --- | 
| 用户 ID，应用程序有多个用户。 | 好 | 
| 状态代码，只有少数几个可能的状态代码。 | 差 | 
| 项目创建日期，四舍五入至最近的时间（例如，天、小时或分钟）。 | 差 | 
| 设备 ID，每个设备以相对类似间隔访问数据。 | 好 | 
| 设备 ID，即使跟踪多个设备，但其中一个设备远比所有其他设备热门。 | 差 | 

如果单个表只有少量的分区键值，请考虑更多不同非分区键值之间分配写入操作。也就是说，设计主键元素，避免出现一个“热门”（请求频率非常高的）分区键值，导致整体性能降低。

例如，考虑设计具有复合主键的表。分区键代表项目创建日期，四舍五入至最近的天。排序键是项目标识符。在指定日期，如 `2014-07-09`，**所有**新项目写入单个分区键值（和对应的物理分区）。

如果表可以完全放入单个分区（考虑数据随时间的增加），并且应用程序的读写吞吐量要求不超过单个分区的读取和写入容量，则应用程序不会因分区遇到意外节流。

要使用 NoSQL Workbench for DynamoDB 来帮助可视化您的分区键设计，请参阅[使用 NoSQL Workbench 构建数据模型](workbench.Modeler.md)。

# 在 DynamoDB 表中使用写入分片来均匀分配工作负载
<a name="bp-partition-key-sharding"></a>

扩大空间是一种在 Amazon DynamoDB 的分区键空间更好地分配写入的方式。可以通过多种不同方式来进行。可以将随机数加入分区键值，在分区之间分配项目。或者，可以使用基于查询内容计算的数字。

## 使用随机后缀分片
<a name="bp-partition-key-sharding-random"></a>

将随机数加入分区键值末尾，是在分区键空间更均匀分配负载的一种策略。然后在更大空间内随机写入。

例如，对于表示当天日期的分区键，可能选择介于 `1` 和 `200` 之间的随机数，并将它作为后缀连接到日期。这将生成分区键值 `2014-07-09.1`、`2014-07-09.2`，以此类推，直到 `2014-07-09.200`。由于随机化分区键，每天表的写入将均匀分布在多个分区。这样可以提高并行度和总体吞吐量。

但是，要读取指定日期的所有项目，必须针对所有后缀查询项目，然后合并结果。例如，先对分区键值 `2014-07-09.1` 发出 `Query` 请求。然后，对 `2014-07-09.2` 发出另一个 `Query`，以此类推，直到 `2014-07-09.200`。最后，应用程序必须合并所有 `Query` 请求的结果。

## 使用计算后缀分片
<a name="bp-partition-key-sharding-calculated"></a>

随机化策略可以显著改善写入吞吐量，但难以读取特定项目，因为不知道写入项目时使用的后缀值。要更容易读取各个项目，可使用其他策略。不使用随机数在分区间分配项目，而是使用可根据查询内容计算的数字。

考虑上一个示例，表在分区键中使用当天日期。现在假设每个项目有一个可访问的 `OrderId` 属性，除了日期外，最经常需要按订单 ID 查找项目。应用程序将项目写入表之前，可以根据订单 ID 计算一个哈希后缀，并将此后缀追加到分区键日期。计算可能产生一个介于 1 和 200 之间非常均匀分布的数字，类似于随机策略所生成的数字。

简单的计算足够了，例如订单 ID 字符的 UTF-8 码位值的乘积，取模 200，加 1。分区键值是连接计算结果的日期。

利用此策略，写入均匀分布在分区键值之间，从而均匀分布在物理分区之间。可以对特殊项目和日期轻松执行 `GetItem` 操作，因为可以为特定 `OrderId` 值计算分区键值。

要读取指定日期的所有项目，仍必须`Query`每个 `2014-07-09.N` 键（其中，`N` 为 1-200），然后应用程序必须合并所有结果。好处是避免出现单个“热门”分区键值，承担所有工作负载。

**注意**  
有关专门设计用于处理大容量时间序列数据的更高效策略，请参见[时间序列数据](bp-time-series.md)。

# 在 DynamoDB 中的数据上传期间高效分配写入活动
<a name="bp-partition-key-data-upload"></a>

通常从其他数据源加载数据时，Amazon DynamoDB 会在多个服务器上分区表数据。如果同时将数据上传到所有分配的服务器，则可以获得更好的性能。

例如，假设要将用户消息上传到的 DynamoDB 表使用复合主键，`UserID` 作为分区键，`MessageID` 作为排序键。

上传数据时，可以为每个用户上传的所有消息项目，一个用户接一个用户：


****  

| UserID | MessageID | 
| --- | --- | 
| U1 | 1 | 
| U1 | 2 | 
| U1 | ... | 
| U1 | ... 最多 100 | 
| U2 | 1 | 
| U2 | 2 | 
| U2 | ... | 
| U2 | ... 最多 200 | 

这种情况下的问题是没有在 DynamoDB 的分区键值中分配写入请求。一次取一个分区键值，上传所有项目，然后下一个分区键值，进行相同操作。

DynamoDB 后台在多个服务器中分区表的数据。要充分利用为表预置的所有吞吐容量，必须在分区键值之间分配工作负载。对全部具有相同分区键值的项目进行不均匀的上传工作，将无法完全利用 DynamoDB 为表预置的所有资源。

可以使用排序键从每个分区键值中加载一个项目，然后从每个分区键值加载另一个项目，以此类推，分配上传工作：


****  

| UserID | MessageID | 
| --- | --- | 
| U1 | 1 | 
| U2 | 1 | 
| U3 | 1 | 
| ... | ... | 
| U1 | 2 | 
| U2 | 2 | 
| U3 | 2 | 
| ... | ... | 

按这个顺序均匀加载，将使用不同的分区键值，使更多 DynamoDB 服务器同时处于繁忙状态，提高吞吐量性能。