

# 关系（SQL）数据库和 DynamoDB 在从表中读取数据方面的差异
<a name="SQLtoNoSQL.ReadData"></a>

利用 SQL，您可使用 `SELECT` 语句从表中检索一个或多个行。可使用 `WHERE` 子句来确定返回给您的数据。

这与使用 Amazon DynamoDB 不同，后者提供以下操作来读取数据：
+ `ExecuteStatement` 将会检索表中的单个或多个项目。`BatchExecuteStatement` 可以通过单个操作检索不同表中的多个项目。所有这些操作均使用 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)，一种 SQL 兼容的查询语言。
+ `GetItem` – 从表中检索单个项目。这是读取单个项目的最高效方式，因为它将提供对项目物理位置的直接访问。（DynamoDB 还提供 `BatchGetItem` 操作，允许在单个操作中执行最多 100 次 `GetItem` 调用。）
+ `Query` – 检索具有特定分区键的所有项目。在这些项目中，您可以将条件应用于排序键并仅检索一部分数据。`Query` 针对存储数据的分区提供快速、高效的访问。（有关更多信息，请参阅 [DynamoDB 中的分区和数据分布](HowItWorks.Partitions.md)。）
+ `Scan` – 检索指定表中的所有项目。（不应对大型表使用此操作，因为这可能会占用大量系统资源。）

**注意**  
利用关系数据库，您可以使用 `SELECT` 语句联接多个表中的数据并返回结果。联接是关系模型的基础。要确保联接高效运行，应持续优化数据库及其应用程序的性能。DynamoDB 是一个不支持表连接的非关系 NoSQL 数据库。相反，应用程序一次从一个表中读取数据。

以下各节介绍读取数据的各种使用案例，以及如何使用关系数据库和 DynamoDB 执行这些任务。

**Topics**
+ [使用项目的主键读取项目方面的差异](SQLtoNoSQL.ReadData.SingleItem.md)
+ [查询表方面的差异](SQLtoNoSQL.ReadData.Query.md)
+ [扫描表方面的差异](SQLtoNoSQL.ReadData.Scan.md)

# 使用项目的主键读取项目方面的差异
<a name="SQLtoNoSQL.ReadData.SingleItem"></a>

数据库的一个常见访问模式是从表中读取一个项目。您必须指定所需项目的主键。

**Topics**
+ [通过 SQL 使用项目的主键读取项目](#SQLtoNoSQL.ReadData.SingleItem.SQL)
+ [在 DynamoDB 中使用项目的主键读取项目](#SQLtoNoSQL.ReadData.SingleItem.DynamoDB)

## 通过 SQL 使用项目的主键读取项目
<a name="SQLtoNoSQL.ReadData.SingleItem.SQL"></a>

在 SQL 中，您将使用 `SELECT` 语句从表中检索数据。您可以在结果中请求一个或多个列 (或所有列，如果您使用 `*` 运算符)。`WHERE` 子句确定要返回的行。

以下是 `SELECT` 语句，它从 *Music* 表中检索单个行。`WHERE` 子句指定主键值。

```
SELECT *
FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today'
```

您可以修改此查询以仅检索一部分列。

```
SELECT AlbumTitle, Year, Price
FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today'
```

请注意，此表的主键包含 *Artist* 和 *SongTitle*。

## 在 DynamoDB 中使用项目的主键读取项目
<a name="SQLtoNoSQL.ReadData.SingleItem.DynamoDB"></a>

在 Amazon DynamoDB 中，您可以使用 DynamoDB API 或 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)（一种与 SQL 兼容的查询语言）读取表中的项目。

------
#### [ DynamoDB API ]

使用 DynamoDB API，您可以使用 `PutItem` 操作向表添加项目。

DynamoDB 提供 `GetItem` 操作来按项目的主键检索项目。`GetItem` 非常高效，因为它提供对项目物理位置的直接访问。（有关更多信息，请参阅 [DynamoDB 中的分区和数据分布](HowItWorks.Partitions.md)。）

默认情况下，`GetItem` 将返回整个项目及其所有属性。

```
{
    TableName: "Music",
    Key: {
        "Artist": "No One You Know",
        "SongTitle": "Call Me Today"
    }
}
```

您可以添加 `ProjectionExpression` 参数以仅返回一些属性。

```
{
    TableName: "Music",
    Key: {
        "Artist": "No One You Know",
        "SongTitle": "Call Me Today"
    },
    "ProjectionExpression": "AlbumTitle, Year, Price"
}
```

请注意，此表的主键包含 *Artist* 和 *SongTitle*。

DynamoDB `GetItem` 操作非常高效。此操作使用主键值确定相关项目的确切存储位置，并直接从此位置检索该项目。在按主键值检索项目时，SQL `SELECT` 语句同样高效。

SQL `SELECT` 语句支持多种类型的查询和表扫描。DynamoDB 的 `Query` 和 `Scan` 操作功能类似，这两个操作在 [查询表方面的差异](SQLtoNoSQL.ReadData.Query.md) 和 [扫描表方面的差异](SQLtoNoSQL.ReadData.Scan.md) 中介绍。

SQL `SELECT` 语句可执行表联接，这允许您同时从多个表中检索数据。在标准化数据库表的情况下，联接是最高效的，并且各个表之间的关系很明确。不过，如果您在一个 `SELECT` 语句中联接的表过多，则会影响应用程序性能。可使用数据库复制、具体化的视图或查询重写来解决此类问题。

DynamoDB 是一个非关系数据库且不支持表联接。如果您将现有应用程序从关系数据库迁移到 DynamoDB，则需要非规范化数据模型以消除联接需要。

------
#### [ PartiQL for DynamoDB ]

使用 PartiQL，您可以通过使用 PartiQL `ExecuteStatement` 语句来使用 `Select` 操作读取表中的项目。

```
SELECT AlbumTitle, Year, Price
FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today'
```

请注意，此表的主键包含 Artist 和 SongTitle。

**注意**  
 选择 PartiSQL 语句也可用于查询或扫描 DynamoDB 表

有关使用 `Select` 和 `ExecuteStatement` 的代码示例，请参阅 [PartiQL for DynamoDB 的 Select 语句](ql-reference.select.md)。

------

# 查询表方面的差异
<a name="SQLtoNoSQL.ReadData.Query"></a>

另一个常见访问模式是根据您的查询条件从表中读取多个项目。

**Topics**
+ [使用 SQL 查询表](#SQLtoNoSQL.ReadData.Query.SQL)
+ [在 DynamoDB 中查询表](#SQLtoNoSQL.ReadData.Query.DynamoDB)

## 使用 SQL 查询表
<a name="SQLtoNoSQL.ReadData.Query.SQL"></a>

使用 SQL 时，`SELECT` 语句可让您查询关键列、非关键列或任意组合。`WHERE` 子句确定返回的行，如以下示例所示。

```
/* Return a single song, by primary key */

SELECT * FROM Music
WHERE Artist='No One You Know' AND SongTitle = 'Call Me Today';
```

```
/* Return all of the songs by an artist */

SELECT * FROM Music
WHERE Artist='No One You Know';
```

```
/* Return all of the songs by an artist, matching first part of title */

SELECT * FROM Music
WHERE Artist='No One You Know' AND SongTitle LIKE 'Call%';
```

```
/* Return all of the songs by an artist, only if the price is less than 1.00 */

SELECT * FROM Music
WHERE Artist='No One You Know'
AND Price < 1.00;
```

请注意，此表的主键包含 *Artist* 和 *SongTitle*。

## 在 DynamoDB 中查询表
<a name="SQLtoNoSQL.ReadData.Query.DynamoDB"></a>

在 Amazon DynamoDB 中，您可以使用 DynamoDB API 或 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)（一种与 SQL 兼容的查询语言）查询表中的项目。

------
#### [ DynamoDB API ]

通过 Amazon DynamoDB，您可以使用 `Query` 操作以类似方式检索数据。`Query` 操作提供对存储数据的物理位置的快速高效访问。有关更多信息，请参阅 [DynamoDB 中的分区和数据分布](HowItWorks.Partitions.md)。

您可以将 `Query` 与任何表或二级索引一起使用。您必须为分区键的值指定相等条件，并且可以有选择性地为排序键属性（如果已定义）提供另一个条件。

`KeyConditionExpression` 参数指定要查询的键值。可使用可选 `FilterExpression` 在结果中的某些项目返回给您之前删除这些项目。

在 DynamoDB 中，您必须使用 `ExpressionAttributeValues` 作为表达式参数（如 `KeyConditionExpression` 和 `FilterExpression`）中的占位符。这类似于在关系数据库中使用*绑定变量*，其中，您在运行时将实际值代入 `SELECT` 语句。

请注意，此表的主键包含 *Artist* 和 *SongTitle*。

以下是其他几个 DynamoDB `Query` 示例。

```
// Return a single song, by primary key

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a and SongTitle = :t",
    ExpressionAttributeValues: {
        ":a": "No One You Know",
        ":t": "Call Me Today"
    }
}
```

```
// Return all of the songs by an artist

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a",
    ExpressionAttributeValues: {
        ":a": "No One You Know"
    }
}
```

```
// Return all of the songs by an artist, matching first part of title

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a and begins_with(SongTitle, :t)",
    ExpressionAttributeValues: {
        ":a": "No One You Know",
        ":t": "Call"
    }
}
```

```
// Return all of the songs by an artist, only if the price is less than 1.00

{
    TableName: "Music",
    KeyConditionExpression: "Artist = :a",
    FilterExpression: "Price < :p",
    ExpressionAttributeValues: {
        ":a": "No One You Know",
        ":p": 1.00
    }
}
```

**注意**  
`FilterExpression` 在 `Query` 读取匹配的项目之后应用，因此不会减少消耗的读取容量。尽可能对数据进行建模，以便范围条件可以在排序键上使用 `KeyConditionExpression` 高效地进行查询。有关更多信息，请参阅 [在 DynamoDB 中查询表](Query.md)。

------
#### [ PartiQL for DynamoDB ]

通过 PartiQL，您可以对分区键使用 `ExecuteStatement` 操作和 `Select` 语句执行查询。

```
SELECT AlbumTitle, Year, Price
FROM Music
WHERE Artist='No One You Know'
```

通过此方式使用 `SELECT` 语句将返回与此特定 `Artist` 关联的所有歌曲。

有关使用 `Select` 和 `ExecuteStatement` 的代码示例，请参阅 [PartiQL for DynamoDB 的 Select 语句](ql-reference.select.md)。

------

# 扫描表方面的差异
<a name="SQLtoNoSQL.ReadData.Scan"></a>

在 SQL 中，不带 `SELECT` 子句的 `WHERE` 语句将返回表中的每个行。在 Amazon DynamoDB 中，`Scan` 操作可执行相同的工作。在这两种情况下，您都可以检索所有项目或部分项目。

无论您使用的是 SQL 还是 NoSQL 数据库，都应谨慎使用扫描操作，因为它们会占用大量系统资源。有时，扫描是适合的 (例如，扫描小型表) 或不可避免的 (例如，执行数据的批量导出操作)。但通常来说，您应设计应用程序以避免执行扫描。有关更多信息，请参阅 [在 DynamoDB 中查询表](Query.md)。

**注意**  
执行批量导出还将为每个分区创建至少 1 个文件。每个文件中的所有项目都来自于该特定分区的哈希密钥空间。

**Topics**
+ [使用 SQL 扫描表](#SQLtoNoSQL.ReadData.Scan.SQL)
+ [在 DynamoDB 中扫描表](#SQLtoNoSQL.ReadData.Scan.DynamoDB)

## 使用 SQL 扫描表
<a name="SQLtoNoSQL.ReadData.Scan.SQL"></a>

使用 SQL 时，您可以在不指定 `SELECT` 子句的情况下使用 `WHERE` 语句扫描表并检索其所有数据。您可以在结果中请求一个或多个列。或者，如果您使用通配符 (\$1)，则可请求所有列。

以下是使用 `SELECT` 语句的示例。

```
/* Return all of the data in the table */
SELECT * FROM Music;
```

```
/* Return all of the values for Artist and Title */
SELECT Artist, Title FROM Music;
```

## 在 DynamoDB 中扫描表
<a name="SQLtoNoSQL.ReadData.Scan.DynamoDB"></a>

在 Amazon DynamoDB 中，您可以使用 DynamoDB API 或 [PartiQL](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html)（一种与 SQL 兼容的查询语言）对表执行扫描。

------
#### [ DynamoDB API ]

借助 DynamoDB API，您可以使用 `Scan` 操作来通过访问表或者二级索引中的每个项目来返回一个或多个项目和项目属性。

```
// Return all of the data in the table
{
    TableName:  "Music"
}
```

```
// Return all of the values for Artist and Title
{
    TableName:  "Music",
    ProjectionExpression: "Artist, Title"
}
```

`Scan` 操作还提供一个 `FilterExpression` 参数，您可以使用它丢弃不希望在结果中出现的项目。在执行扫描后且结果返回给您之前，应用 `FilterExpression`。（不建议对大表使用。即使仅返回几个匹配项目，您仍需为整个 `Scan` 付费。）

------
#### [ PartiQL for DynamoDB ]

使用 PartiQL，您可以通过 `Select` 语句来使用 `ExecuteStatement` 操作执行扫描，以返回表的所有内容。

```
SELECT AlbumTitle, Year, Price
FROM Music
```

请注意，此语句将返回 Music 表中的所有项目。

有关使用 `Select` 和 `ExecuteStatement` 的代码示例，请参阅 [PartiQL for DynamoDB 的 Select 语句](ql-reference.select.md)。

------