

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

# 优化查询性能
<a name="working.optimize"></a>

**重要**  
终止支持通知：现有客户将能够使用 Amazon QLDB，直到 2025 年 7 月 31 日终止支持。有关更多详细信息，请参阅[将亚马逊 QLDB 账本迁移到亚马逊 Aurora PostgreSQL](https://aws.amazon.com/blogs/database/migrate-an-amazon-qldb-ledger-to-amazon-aurora-postgresql/)。

Amazon QLDB 旨在满足高性能联机事务处理（OLTP）的工作负载需求。这意味着 QLDB 已针对一组特定查询模式进行了优化，尽管它支持类似 SQL 的查询功能。涉及应用程序及其数据模型对于使用此查询模式至关重要。否则，随着表的增长，您将遇到严重的性能问题，包括查询延迟、事务超时和并发冲突。

该章节描述了 Amazon QLDB 中的查询限制，并提供了在这些限制条件下优化查询性能指导。

**Topics**
+ [事务超时限制](#working.optimize.txn-timeout)
+ [并发冲突](#working.optimize.occ)
+ [最优查询模式](#working.optimize.patterns)
+ [要避免的查询模式](#working.optimize.avoid)
+ [监控性能](#working.optimize.monitor)

## 事务超时限制
<a name="working.optimize.txn-timeout"></a>

QLDB 中的每个 PartiQL 语句（包括每个 `SELECT` 查询）都是在事务中处理的，并且受[事务超时限制](limits.md#limits.fixed)的约束。在提交之前，事务最多可运行 **30 秒**。超过此限制后，QLDB 会拒绝在事务完成的任何工作，并丢弃运行该事务[会话](concurrency.md#concurrency.sessions)。此限制通过启动事务（而不提交或取消事务）以保护服务的客户端免遭泄漏会话。

## 并发冲突
<a name="working.optimize.occ"></a>

在 QLDB 中，并发控制通过*乐观并发控制*（OCC）实现。次优查询也可能导致更多 OCC 冲突。有关 OCC 的信息，请参阅[Amazon QLDB 并发模型](concurrency.md)。

## 最优查询模式
<a name="working.optimize.patterns"></a>

按最佳实践标准，您应运行带有`WHERE`谓词子句的语句，该子句可以筛选索引字段或文档 ID。QLDB 需要在索引字段上使用*相等*运算符（例如`=`或`IN`）才能高效地查找文档。

以下是 [用户视图](working.userdata.md) 中最佳查询模式的示例。

```
--Indexed field (VIN) lookup using the = operator
SELECT * FROM VehicleRegistration
WHERE VIN = '1N4AL11D75C109151'

--Indexed field (VIN) AND non-indexed field (City) lookup
SELECT * FROM VehicleRegistration
WHERE VIN = '1N4AL11D75C109151' AND City = 'Seattle'

--Indexed field (VIN) lookup using the IN operator
SELECT * FROM VehicleRegistration
WHERE VIN IN ('1N4AL11D75C109151', 'KM8SRDHF6EU074761')

--Document ID (r_id) lookup using the BY clause
SELECT * FROM VehicleRegistration BY r_id
WHERE r_id = '3Qv67yjXEwB9SjmvkuG6Cp'
```

任何不遵循这些模式的查询都会调用 *全表扫描*。表扫描可能会导致大型表上的查询，或返回大型结果集的查询发生事务超时。它们还可能[导致 OCC 与竞争事务发生冲突](concurrency.md#concurrency.indexes)。

**高基数索引**

我们建议为包含高基数值的字段建立索引。例如，`VehicleRegistration`表中的 `VIN` 和 `LicensePlateNumber` 字段是索引字段，旨在保持唯一性。

避免对低基数字段（例如状态代码、地址州或省以及邮政编码）建立索引。如果您为此类字段编制索引，则查询可能会生成较大的结果集，这些结果集 *更有可能导致事务超时或导致意外的 OCC 冲突*。

**已提交视图查询**

您在[已提交视图](working.metadata.md)中运行的查询遵循与用户视图查询相同的优化准则。您在表上创建的索引也可用于已提交视图中的查询。

**历史记录函数查询**

[历史记录函数](working.history.md)查询不使用您在表上创建的索引。QLDB 历史记录按文档 ID 编制索引，目前无法创建其他历史索引。

最佳做法是，使用日期范围（*开始时间* 和 *结束时间*）和文档 ID（`metadata.id`）来限定历史查询。包含开始时间和结束时间的历史记录查询将从日期范围限定中获得便利。

**内部联接查询**

对于内部联接查询，请使用至少包含联接右侧表的索引字段的联接条件。如果没有连接索引，连接查询将调用多个表扫描 - 对于连接左表中的每个文档，查询将完全扫描右表。除了为至少一个表指定`WHERE`相等谓词外，最佳做法是对要加入的每个表建立索引的字段进行联接。

例如，以下查询将 `VehicleRegistration`和`Vehicle`表连接至各自的字段，这两个`VIN`字段均已编制索引。此查询还有一个`VehicleRegistration.VIN`相等谓词。

```
SELECT * FROM VehicleRegistration AS r INNER JOIN Vehicle AS v
ON r.VIN = v.VIN
WHERE r.VIN IN ('1N4AL11D75C109151', 'KM8SRDHF6EU074761')
```

为联接查询中的联接条件与相等谓词选择高基数索引。

## 要避免的查询模式
<a name="working.optimize.avoid"></a>

以下是**次优语句的示例，这些语**句不能很好地扩展 QLDB 中较大的表。我们强烈建议您不要依赖这些类型的查询来获取随时间增长的表，因为您的查询最终将导致事务超时。由于表包含大小不同的文档，因此很难为非索引查询定义精确的限制。

```
--No predicate clause
SELECT * FROM Vehicle

--COUNT() is not an optimized function
SELECT COUNT(*) FROM Vehicle

--Low-cardinality predicate
SELECT * FROM Vehicle WHERE Color = 'Silver'

--Inequality (>) does not qualify for indexed lookup
SELECT * FROM Vehicle WHERE "Year" > 2019

--Inequality (LIKE)
SELECT * FROM Vehicle WHERE VIN LIKE '1N4AL%'

--Inequality (BETWEEN)
SELECT SUM(PendingPenaltyTicketAmount) FROM VehicleRegistration
WHERE ValidToDate BETWEEN `2020-01-01T` AND `2020-07-01T`

--No predicate clause
DELETE FROM Vehicle

--No document id, and no date range for the history() function
SELECT * FROM history(Vehicle)
```

通常，我们*不建议*在 QLDB 中为生产用例运行以下类型查询模式：
+ 联机分析处理（OLAP）查询
+ 没有谓词子句的探索性查询
+ 报告查询
+ 文本搜索

相反，我们建议将您的数据流式传输到专门构建的数据库服务，该服务针对分析用例进行了优化。例如，您可以将 QLDB 数据流式传输到 A OpenSearch mazon 服务，以提供对文档的全文搜索功能。有关演示此用例的示例应用程序，请参阅 GitHub 存储库 [aws-sam amazon-qldb-streaming-amazon](https://github.com/aws-samples/amazon-qldb-streaming-amazon-opensearch-service-sample-python) ples/-。opensearch-service-sample-python有关 QLDB 流的信息，请参阅 [Amazon QLDB 流式传输日记账数据](streams.md)。

## 监控性能
<a name="working.optimize.monitor"></a>

QLDB 驱动程序在语句结果对象中提供消耗的 I/O 使用情况和计时信息。您可使用这些指标识别效率低下的 PartiQL 语句。要了解更多信息，请继续 [获取 PartiQL 语句统计信息](working.statement-stats.md)。

您还可以使用 Amazon CloudWatch 来跟踪账本在数据操作方面的表现。监控指定`LedgerName` 和 `CommandType`的`CommandLatency`指标。有关更多信息，请参阅 [使用 Amazon 进行监控 CloudWatch](monitoring-cloudwatch.md)。要了解 QLDB 如何使用命令管理数据操作，请参阅[驱动程序会话管理](driver-session-management.md)。