

# Lock:Relation
<a name="wait-event.lockrelation"></a>

当查询等待获取当前被另一个事务锁定的表或视图（关系）上的锁定时，会发生 `Lock:Relation` 事件。

**Topics**
+ [支持的引擎版本](#wait-event.lockrelation.context.supported)
+ [上下文](#wait-event.lockrelation.context)
+ [等待次数增加的可能原因](#wait-event.lockrelation.causes)
+ [操作](#wait-event.lockrelation.actions)

## 支持的引擎版本
<a name="wait-event.lockrelation.context.supported"></a>

RDS for PostgreSQL 的所有版本均支持此等待事件信息。

## 上下文
<a name="wait-event.lockrelation.context"></a>

大多数 PostgreSQL 命令隐式使用锁来控制对表中数据的并发访问。您还可以通过 `LOCK` 命令在应用程序代码中显式使用这些锁。许多锁定模式彼此不兼容，它们可以在尝试访问同一对象时阻止事务。发生这种情况时，RDS for PostgreSQL 会生成一个 `Lock:Relation` 事件。以下是一些常见的示例：
+ `ACCESS EXCLUSIVE` 之类的独占锁可以阻止所有并发访问。数据定义语言 (DDL) 操作（例如 `DROP TABLE`、`TRUNCATE`、`VACUUM FULL` 和 `CLUSTER`）隐式获取 `ACCESS EXCLUSIVE` 锁定。`ACCESS EXCLUSIVE` 也是用于未显式指定模式的 `LOCK TABLE` 语句的原定设置锁定模式。
+ 在表上使用 `CREATE INDEX (without CONCURRENT)` 与数据操作语言 (DML) 语句 `UPDATE`、`DELETE` 和 `INSERT` 有冲突，这些语句可获取 `ROW EXCLUSIVE` 锁定。

有关表级锁和冲突锁模式的更多信息，请参阅 PostgreSQL 文档中的[显式锁定](https://www.postgresql.org/docs/13/explicit-locking.html)。

阻止查询和事务通常通过以下方式之一解锁阻止：
+ 阻止查询 – 应用程序可以取消查询或者用户可以结束该过程。引擎还可以因会话的语句超时或死锁检测机制而强制结束查询。
+ 阻止事务 – 事务在运行 `ROLLBACK` 或 `COMMIT` 语句时停止阻止。当会话被客户端或网络问题断开连接或结束时，也会自动发生回滚。当数据库引擎关闭、系统内存不足等时，可以结束会话。

## 等待次数增加的可能原因
<a name="wait-event.lockrelation.causes"></a>

当 `Lock:Relation` 事件的发生频率高于正常值时，可能表明存在性能问题。典型的原因包括：

**增加与表锁冲突的并发会话**  
用冲突锁定模式锁定相同表格的查询的并发会话数可能会增加。

**维护操作**  
`VACUUM` 和 `ANALYZE` 之类的运行状况维护操作可以显著增加冲突锁的数量。`VACUUM FULL` 获取 `ACCESS EXCLUSIVE` 锁，`ANALYSE` 获取 `SHARE UPDATE EXCLUSIVE`锁。这两种类型的锁都可能导致 `Lock:Relation` 等待事件。应用程序数据维护操作（例如刷新具体化视图）也可以增加阻止的查询和事务。

**读取器实例的锁定**  
写入器和读取器持有的关系锁之间可能存在冲突。目前，仅 `ACCESS EXCLUSIVE` 关系锁复制到读取器实例。但是，`ACCESS EXCLUSIVE` 关系锁将与读取器持有的任何 `ACCESS SHARE` 关系锁冲突。这可能会导致读取器上的锁定关系等待事件增加。

## 操作
<a name="wait-event.lockrelation.actions"></a>

根据等待事件的原因，我们建议采取不同的操作。

**Topics**
+ [减少阻止 SQL 语句的影响](#wait-event.lockrelation.actions.reduce-blocks)
+ [尽量减少维护操作的影响](#wait-event.lockrelation.actions.maintenance)

### 减少阻止 SQL 语句的影响
<a name="wait-event.lockrelation.actions.reduce-blocks"></a>

为了减少阻止 SQL 语句的影响，请尽可能修改应用程序代码。以下是减少数据块的两种常见方法：
+ 使用 `NOWAIT` 选项 – 一些 SQL 命令，例如 `SELECT` 和 `LOCK` 语句，支持此选项。如果无法立即获取锁定，则 `NOWAIT` 指令将取消请求锁定的查询。这种方法可以帮助防止阻止会话导致其后面堆积阻止的会话。

  例如：假设事务 A 正在等待事务 B 所持有的锁定。现在，如果 B 请求对被事务 C 锁定的表进行锁，那么事务 A 可能会被阻止，直到事务 C 完成。但是，如果事务 B 在请求对 C 进行锁定时使用 `NOWAIT`，它可能会很快失败，并确保事务 A 不必无限期等待。
+ 使用 `SET lock_timeout` – 设置 `lock_timeout` 值，以限制 SQL 语句等待获取关系锁的时间。如果锁未在指定的超时内获取，则请求锁定的事务将被取消。在会话级别设置此值。

### 尽量减少维护操作的影响
<a name="wait-event.lockrelation.actions.maintenance"></a>

维护操作（例如 `VACUUM` 和 `ANALYZE`）非常重要。我们建议您不要将其关闭，因为您会找到与这些维护操作相关的 `Lock:Relation` 等待事件。以下方法可以最大限度地减少这些操作的影响：
+ 在非高峰时段手动运行维护操作。
+ 要减少由 Autovacuum 任务导致的 `Lock:Relation` 等待，执行任何需要的 Autovacuum 优化。有关优化 Autovacuum 的信息，请参阅《*Amazon RDS 用户指南*》中的[在 Amazon RDS 上使用 PostgreSQL Autovacuum](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Autovacuum.html)。