

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

您可以使用 Amazon DynamoDB 中的 `Query` API 操作基于主键值查找项目。

您必须提供分区键属性的名称以及该属性的一个值。`Query` 将返回具有该分区键值的所有项目。（可选）您可以提供排序键属性，并使用比较运算符来细化搜索结果。

有关如何使用 `Query` 的更多信息，例如请求语法、响应参数和其他示例，请参阅《Amazon DynamoDB API 参考》**中的[查询](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html)。

**Topics**
+ [

# DynamoDB 中的查询操作的键条件表达式
](Query.KeyConditionExpressions.md)
+ [

# DynamoDB 中的查询操作的筛选表达式
](Query.FilterExpression.md)
+ [

# 在 DynamoDB 中对表查询结果分页
](Query.Pagination.md)
+ [

# 在 DynamoDB 中使用查询操作的其他分面
](Query.Other.md)

# DynamoDB 中的查询操作的键条件表达式
<a name="Query.KeyConditionExpressions"></a>

您可以在键条件表达式中使用任意属性名称，前提是第一个字符是 `a-z` 或 `A-Z`，其余字符（从第二个字符开始，如果存在）为 `a-z`、`A-Z` 或 `0-9`。此外，属性名称不得为 DynamoDB 保留字。（有关这些保留关键字的完整列表，请参阅[DynamoDB 中的保留字](ReservedWords.md)。） 如果属性名称不满足这些要求，则您必须将表达式属性名称定义为占位符。有关更多信息，请参阅 [DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)。

对于具有给定分区键值的项目，DynamoDB 会将这些项目存储在紧邻位置并按照排序键值对其进行排序。在 `Query` 操作中，DynamoDB 按照排序顺序检索项目，然后使用 `KeyConditionExpression` 和可能存在的任何 `FilterExpression` 处理项目。只有在此时才会将 `Query` 结果发送回客户端。

`Query` 操作始终返回结果集。如果未找到匹配的项目，结果集将为空。

`Query` 结果始终按排序键值排序。如果排序键的数据类型为 `Number`，则按照数值顺序返回结果。否则，按照 UTF-8 字节的顺序返回结果。默认情况下，系统按升序排序。要颠倒顺序，请将 `ScanIndexForward` 参数设置为 `false`。

单个 `Query` 操作最多可检索 1 MB 的数据。在向结果应用任何 `FilterExpression` 或 `ProjectionExpression` 之前，将应用此限制。如果 `LastEvaluatedKey` 包含在响应中且为非 null 值，则您必须为结果集分页（请参阅[在 DynamoDB 中对表查询结果分页](Query.Pagination.md)）。

## 键条件表达式示例
<a name="Query.KeyConditionExpressions-example"></a>

要指定搜索条件，请使用*键条件表达式*—用于确定要从表或索引中读取的项目的字符串。

您必须指定分区键名称和值作为等式条件。无法在键条件表达式中使用非键属性。

您可选择为排序键提供另一个条件（如果有）。排序键条件必须使用下列比较运算符之一：
+ `a = b` — 如果属性 *a* 等于值 *b*，则为 true
+ `a < b` — 如果 *a* 小于 *b*，则为 true
+ `a <= b` — 如果 *a* 小于等于 *b*，则为 true
+ `a > b` — 如果 *a* 大于 *b*，则为 true
+ `a >= b` — 如果 *a* 大于等于 *b*，则为 true
+ `a BETWEEN b AND c` — 如果 *a* 大于或等于 *b*，且小于或等于 *c*，则为 true。

以下函数也受支持：
+ `begins_with (a, substr)` — 如果属性 `a` 的值以特定子字符串开头，则为 true。

以下 AWS Command Line Interface (AWS CLI) 示例将演示键条件表达式的用法。这些表达式使用占位符（例如 `:name` 和 `:sub`）而不是实际的值。有关更多信息，请参阅[DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)和[在 DynamoDB 中使用表达式属性值](Expressions.ExpressionAttributeValues.md)。

**Example**  
在 `Thread` 表中查询特定的 `ForumName`（分区键）。具有 `ForumName` 值的所有项目将由查询进行读取，因为排序键 (`Subject`) 未包括在 `KeyConditionExpression` 中。  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name" \
    --expression-attribute-values  '{":name":{"S":"Amazon DynamoDB"}}'
```

**Example**  
在 `Thread` 表中查询特定的 `ForumName`（分区键），但这一次仅返回具有给定 `Subject`（排序键）的项目。  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :name and Subject = :sub" \
    --expression-attribute-values  file://values.json
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":name":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"}
}
```

**Example**  
在 `Reply` 表中查询特定的 `Id`（分区键），但仅返回其 `ReplyDateTime`（排序键）以特定字符开头的项目。  

```
aws dynamodb query \
    --table-name Reply \
    --key-condition-expression "Id = :id and begins_with(ReplyDateTime, :dt)" \
    --expression-attribute-values  file://values.json
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":id":{"S":"Amazon DynamoDB#DynamoDB Thread 1"},
    ":dt":{"S":"2015-09"}
}
```

# DynamoDB 中的查询操作的筛选表达式
<a name="Query.FilterExpression"></a>

如果您需要进一步细化 `Query` 结果，则可以选择性地提供筛选表达式。*筛选表达式*可确定 `Query` 结果中应返回给您的项目。所有其他结果将会丢弃。

筛选表达式在 `Query` 已完成但结果尚未返回时应用。因此，无论是否存在筛选表达式，`Query` 都将占用同等数量的读取容量。

`Query` 操作最多可检索 1 MB 的数据。此限制在计算筛选表达式之前应用。

筛选表达式不得包含分区键或排序键属性。您需要在关键字条件表达式而不是筛选表达式中指定这些属性。

筛选表达式的语法与关键条件表达式的语法相似。筛选表达式可使用的比较运算符、函数和逻辑运算符与关键条件表达式可使用的相同。此外，筛选表达式可以使用不等于运算符 (`<>`)、`OR` 运算符、`CONTAINS` 运算符、`IN` 运算符、`BEGINS_WITH` 运算符、`BETWEEN` 运算符、`EXISTS` 运算符和 `SIZE` 运算符。有关更多信息，请参阅[DynamoDB 中的查询操作的键条件表达式](Query.KeyConditionExpressions.md)和[筛选条件和条件表达式的语法](Expressions.OperatorsAndFunctions.md#Expressions.OperatorsAndFunctions.Syntax)。

**Example**  
以下 AWS CLI 示例在 `Thread` 表中查询特定 `ForumName`（分区键）和 `Subject`（排序键）。在找到的项目中，只返回最常用的讨论线程，换句话说，只有那些具有超过一定数量 `Views` 的线程。  

```
aws dynamodb query \
    --table-name Thread \
    --key-condition-expression "ForumName = :fn and Subject begins_with :sub" \
    --filter-expression "#v >= :num" \
    --expression-attribute-names '{"#v": "Views"}' \
    --expression-attribute-values file://values.json
```
`--expression-attribute-values` 的参数存储在 `values.json` 文件中。  

```
{
    ":fn":{"S":"Amazon DynamoDB"},
    ":sub":{"S":"DynamoDB Thread 1"},
    ":num":{"N":"3"}
}
```
请注意，`Views` 在 DynamoDB 中是一个保留字（请参阅 [DynamoDB 中的保留字](ReservedWords.md)），因此本示例使用 `#v` 作为占位符。有关更多信息，请参阅 [DynamoDB 中的表达式属性名称（别名）](Expressions.ExpressionAttributeNames.md)。

**注意**  
筛选表达式将从 `Query` 结果集中删除项目。在您预计会检索到大量项目并且还需要丢弃其中大多数项目的情况下，请尽量避免使用 `Query`。

# 在 DynamoDB 中对表查询结果分页
<a name="Query.Pagination"></a>

DynamoDB *分页*来自 `Query` 操作的结果。利用分页，`Query` 结果将分成若干“页”大小为 1 MB（或更小）的数据。应用程序可以先处理第一页结果，然后处理第二页结果，依此类推。

单次 `Query` 只会返回符合 1 MB 大小限制的结果集。要确定是否存在更多结果，并一次检索一页结果，应用程序应执行以下操作：

1. 检查低级别 `Query` 结果：
   + 如果结果包含 `LastEvaluatedKey` 元素并且非空，请继续步骤 2。
   + 如果结果中*没有* `LastEvaluatedKey`，则表示没有其他要检索的项目。

1. 使用相同的 `KeyConditionExpression` 构造 `Query`。但是，此次获取来自步骤 1 的 `LastEvaluatedKey` 值，并将其用作新 `ExclusiveStartKey` 请求中的 `Query` 参数。

1. 运行新的 `Query` 请求。

1. 前往步骤 1。

换言之，`LastEvaluatedKey` 响应中的 `Query` 应该用作下一 `ExclusiveStartKey` 请求的 `Query`。如果 `LastEvaluatedKey` 响应中没有 `Query` 元素，则表示您已检索最后一页结果。如果 `LastEvaluatedKey` 不为空，并不一定意味着结果集中有更多数据。检查 `LastEvaluatedKey` 是否为空是确定您是否已到达结果集末尾的唯一方式。

您可以使用 AWS CLI 查看此行为。AWS CLI 向 DynamoDB 反复发送低级别 `Query` 请求，直到请求中不再有 `LastEvaluatedKey`。考虑以下 AWS CLI 示例，此示例检索特定年份的电影标题。

```
aws dynamodb query --table-name Movies \
    --projection-expression "title" \
    --key-condition-expression "#y = :yyyy" \
    --expression-attribute-names '{"#y":"year"}' \
    --expression-attribute-values '{":yyyy":{"N":"1993"}}' \
    --page-size 5 \
    --debug
```

通常，AWS CLI 自动处理分页。但是，在此例中，AWS CLI `--page-size` 参数限制了每页项目数。`--debug` 参数输出有关请求和响应的低级别信息。

如果您运行该示例，DynamoDB 的首次响应类似如下内容。

```
2017-07-07 11:13:15,603 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":5,"Items":[{"title":{"S":"A Bronx Tale"}},
{"title":{"S":"A Perfect World"}},{"title":{"S":"Addams Family Values"}},
{"title":{"S":"Alive"}},{"title":{"S":"Benny & Joon"}}],
"LastEvaluatedKey":{"year":{"N":"1993"},"title":{"S":"Benny & Joon"}},
"ScannedCount":5}'
```

响应中的 `LastEvaluatedKey` 指示并未检索所有项目。随后，AWS CLI 会将另一个 `Query` 请求发送到 DynamoDB。此请求和响应模式继续，直到收到最终响应。

```
2017-07-07 11:13:16,291 - MainThread - botocore.parsers - DEBUG - Response body:
b'{"Count":1,"Items":[{"title":{"S":"What\'s Eating Gilbert Grape"}}],"ScannedCount":1}'
```

如果不存在 `LastEvaluatedKey`，则表示没有其他要检索的项目。

**注意**  
AWS SDK 处理低级别的 DynamoDB 响应（包括是否存在 `LastEvaluatedKey`），并提供各种抽象概念对 `Query` 结果进行分页。例如，适用于 Java 的 SDK 文档接口提供 `java.util.Iterator` 支持，以便您能够一次处理一个结果。  
对于各种编程语言的代码示例，请参阅本地化的 [Amazon DynamoDB 入门指南](https://docs.aws.amazon.com/amazondynamodb/latest/gettingstartedguide/)和 AWS SDK 文档。

此外，您还可以通过使用 `Query` 操作的 `Limit` 参数来限制结果集中的项目数，以此减少页面大小。

有关用 DynamoDB 查询的更多信息，请参阅[在 DynamoDB 中查询表](Query.md)。

# 在 DynamoDB 中使用查询操作的其他分面
<a name="Query.Other"></a>

此部分介绍了 DynamoDB 查询操作的其他方面，包括限制结果大小、计算已扫描项目与已返回项目的数量、监控读取容量消耗以及控制读取一致性。

## 限制结果集中的项目数
<a name="Query.Limit"></a>

使用 `Query` 操作，您可以限制它读取的项目数。为此，请将 `Limit` 参数设置为您需要的最大项目数。

例如，假设您对某个表进行 `Query`，`Limit` 值为 `6`，并且没有筛选表达式。`Query` 结果将包含表中与请求中的键条件表达式匹配的前 6 个项目。

现在假设您向 `Query` 添加了一个筛选表达式。在这种情况下，DynamoDB 最多可读取六个项目，然后仅返回与筛选表达式匹配的项目。最终 `Query` 结果包含六个或更少的项目，即使更多项目（如果 DynamoDB 继续读取更多项目）与过滤表达式匹配，也是如此。

## 对结果中的项目进行计数
<a name="Query.Count"></a>

除了与您的条件匹配的项目之外，`Query` 响应还包含以下元素：
+ `ScannedCount` — 在应用筛选表达式（如果有）*之前*，与关键字条件表达式匹配的项目的数量。
+ `Count` — 在应用筛选表达式（如果有）*之后*，剩余的项目数量。

**注意**  
如果您不使用筛选表达式，那么 `ScannedCount` 和 `Count` 具有相同的值。

如果 `Query` 结果集的大小大于 1 MB，则 `ScannedCount` 和 `Count` 将仅表示项目总数的部分计数。您需要执行多次 `Query` 操作才能检索所有结果（请参阅[在 DynamoDB 中对表查询结果分页](Query.Pagination.md)）。

所有 `Query` 响应都将包含由该特定 `ScannedCount` 请求处理的项目的 `Count` 和 `Query`。要获取所有 `Query` 请求的总和，您可以对 `ScannedCount` 和 `Count` 记录流水账。

## 查询占用的容量单位
<a name="Query.CapacityUnits"></a>

您可以对任何表或二级索引进行 `Query`，只要您提供分区键属性的名称和该属性的单个值即可。`Query` 返回具有该分区键值的所有项目。（可选）您可以提供排序键属性，并使用比较运算符来细化搜索结果。`Query`API 操作将消耗读取容量单位，如下所示。


****  

| 如果对...进行 `Query` | DynamoDB 将占用...的读取容量单位 | 
| --- | --- | 
| 表 | 表的预置读取容量。 | 
| 全局二级索引 | 索引的预置读取容量。 | 
| 本地二级索引 | 基表的预置读取容量。 | 

默认情况下，`Query` 操作不会返回任何有关它占用的读取容量大小的数据。但是，您可在 `ReturnConsumedCapacity` 请求中指定 `Query` 参数以获取此信息。下面是 `ReturnConsumedCapacity` 的有效设置：
+ `NONE` — 不返回任何已占用容量数据。（这是默认值。）
+ `TOTAL` — 响应包含占用的读取容量单位的总数。
+ `INDEXES` — 响应显示占用的读取容量单位的总数，以及访问的每个表和索引的占用容量。

DynamoDB 将基于项目数量以及这些项目的大小，而不是基于返回到应用程序的数据量来计算消耗的读取容量单位数。因此，无论您是请求所有属性（默认行为）还是只请求部分属性（使用投影表达式），占用的容量单位数都是相同的。无论您是否使用筛选表达式，该数值也都是一样的。`Query` 使用最小的读取容量单位，来为高达 4 KB 的项目每秒执行一次强一致性读取，或每秒执行两次最终一致性读取。如果您需要读取大于 4KB 的项目，DynamoDB 需要额外的读取请求单位。空表和分区键数量稀疏的超大表，可能会有在超出查询的数据量后对一些额外的 RCU 收费的情况。这包括处理 `Query` 请求的费用，即使不存在数据也是如此。

## 查询的读取一致性
<a name="Query.ReadConsistency"></a>

默认情况下，`Query` 操作将执行最终一致性读取。这意味着 `Query` 结果可能无法反映由最近完成的 `PutItem` 或 `UpdateItem` 操作导致的更改。有关更多信息，请参阅 [DynamoDB 读取一致性](HowItWorks.ReadConsistency.md)。

如果您需要强一致性读取，请在 `ConsistentRead` 请求中将 `true` 参数设置为 `Query`。