

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 数据建模最佳实践：设计数据模型的建议
<a name="data-modeling"></a>

使用 Amazon Keyspaces（Apache Cassandra 兼容）时，有效的数据建模对于优化性能以及最大限度降低成本至关重要。本主题介绍在设计适合应用程序数据访问模式的数据模型时的一些关键注意事项及建议。
+ **分区键设计** - 分区键对于确定数据如何在 Amazon Keyspaces 的分区之间分布起着至关重要的作用。选择合适的分区键会显著影响查询性能和吞吐量成本。本节讨论设计分区键的策略，这些策略有便于读取和写入活动在分区间实现均匀分布。
+ **关键注意事项：**
  + **活动分布均匀** - 目标是在所有分区之间均匀分布读取和写入活动，进而最大限度地降低吞吐量成本并有效地利用容量爆增。
  + **访问模式** - 使分区键设计与应用程序的主要数据访问模式保持一致。
  + **分区大小** - 避免创建会增长过大的分区，因为这会影响性能并增加成本。

要更轻松地可视化和设计数据模型，可以使用 [NoSQL Workbench](workbench.md)。

**Topics**
+ [如何在 Amazon Keyspaces 中高效使用分区键](bp-partition-key-design.md)

# 如何在 Amazon Keyspaces 中高效使用分区键
<a name="bp-partition-key-design"></a>

唯一标识 Amazon Keyspaces 表中的每一行的主键可以包含一个或多个分区键列（用于确定存储数据的分区）以及一个或多个可选的聚类列（用于定义数据在分区内的聚类和排序方式）。

由于分区键确定存储数据的分区数量以及数据在这些分区中的分布方式，因此选择分区键的方式可能会对查询的性能产生很大影响。一般来说，设计应用程序时应确保磁盘上所有分区的活动一致。

将应用程序的读取和写入活动均匀分配到所有分区有助于最大限度地降低吞吐量成本，这适用于按需和预配置 read/write 容量模式。例如，如果您使用预置容量模式，则可以确定应用程序所需的访问模式，并估算每个表所需的总读取容量单位 (RCU) 和写入容量单位 (WCU)。只要给定分区的流量不超过 3,000 RCUs 和 1,000，Amazon Keyspaces 就会使用您预配置的吞吐量来支持您的访问模式。 WCUs

当分区的读取或写入吞吐量持续较高时，根据流量模式，Amazon Keyspaces 可能会自动将该分区拆分为两个新分区。每个新分区都包含原始分区行的一个子集，在两个分区之间均匀分配吞吐量。

Amazon Keyspaces 通过提供容量暴增为每个分区的吞吐量预置提供更大的灵活性，有关更多信息，请参阅[在 Amazon Keyspaces 中有效使用容量爆增](throughput-bursting.md)。

**Topics**
+ [使用写入分片在分区之间均匀分配工作负载](bp-partition-key-sharding.md)

# 使用写入分片在分区之间均匀分配工作负载
<a name="bp-partition-key-sharding"></a>

在 Amazon Keyspaces 中跨分区更好地分配写入的一种方式是扩展空间。可以通过多种不同方式来进行。您可以添加一个额外的分区键列，将随机数写入到该列，以便在分区间分配行。或者，可以使用基于查询内容计算的数字。

## 使用复合分区键和随机值进行分片
<a name="bp-partition-key-sharding-random"></a>

在分区中更均匀地分配负载的一种策略是添加一个额外的分区键列并在其中写入随机数。然后在更大空间内随机写入。

例如，请考虑下表，该表包含一个代表日期的分区键。

```
CREATE TABLE IF NOT EXISTS tracker.blogs (
   publish_date date,
   title text,
   description int,
   PRIMARY KEY (publish_date));
```

为了在分区间更均匀地分配此表，可以添加一个用于存储随机数的额外分区键列 `shard`。例如：

```
CREATE TABLE IF NOT EXISTS tracker.blogs (
   publish_date date, 
   shard int, 
   title text, 
   description int, 
   PRIMARY KEY ((publish_date, shard)));
```

插入数据时，您可以为 `shard` 列选择一个介于 `1` 和 `200` 之间的随机数。这将生成复合分区键值，比如 `(2020-07-09, 1)`、`(2020-07-09, 2)`，以此类推，直到 `(2020-07-09, 200)`。由于随机化分区键，每天表的写入将均匀分布在多个分区。这样可以提高并行度和总体吞吐量。

但是，要读取给定日期的所有行，必须针对所有分片查询这些行，然后合并结果。例如，先对分区键值 `(2020-07-09, 1)` 发出 `SELECT` 语句。然后，对 `(2020-07-09, 2)` 发出另一个 `SELECT` 语句，以此类推，直到 `(2020-07-09, 200)`。最后，应用程序必须合并所有这些 `SELECT` 语句的结果。

## 使用复合分区键和计算值进行分片
<a name="bp-partition-key-sharding-calculated"></a>

随机化策略可以显著改善写入吞吐量，但要读取特定行却很困难，因为您不知道在写入该行时，将哪个值写入 `shard` 列。要让读取单个行更轻松，可使用其他策略。不使用随机数在分区间分配行，而是使用可根据查询内容计算的数字。

考虑上一个示例，表在分区键中使用当天日期。现在假设每个行有一个可访问的 `title` 列，并且除了日期之外，您最常需要按标题查找行。在应用程序将行写入表之前，它可以根据标题计算哈希值，并使用该值来填充 `shard` 列。计算可能产生一个介于 1 和 200 之间非常均匀分布的数字，类似于随机策略所生成的数字。

简单的计算足够了，例如标题字符的 UTF-8 码位值的乘积，取模 200，加 1。复合分区键值是日期和计算结果的组合。

利用此策略，写入均匀分布在分区键值之间，从而均匀分布在物理分区之间。您可以对特定的行和日期轻松执行 `SELECT` 语句，因为您可以为特定的 `title` 值计算分区键值。

要读取指定日期的所有行，您仍然必须对每个 `(2020-07-09, N)` 键（其中，`N` 为 1-200）执行 `SELECT` 语句，然后应用程序必须合并所有结果。好处是避免出现单个“热门”分区键值，承担所有工作负载。