Lock:Relation
当查询等待获取当前被另一个事务锁定的表或视图(关系)上的锁定时,会发生 Lock:Relation
事件。
支持的引擎版本
Aurora PostgreSQL 的所有版本均支持此等待事件信息。
上下文
大多数 PostgreSQL 命令隐式使用锁来控制对表中数据的并发访问。您还可以通过 LOCK
命令在应用程序代码中显式使用这些锁。许多锁定模式彼此不兼容,它们可以在尝试访问同一对象时阻止事务。发生这种情况时,Aurora 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 文档中的显式锁定
阻止查询和事务通常通过以下方式之一解锁阻止:
阻止查询 – 应用程序可以取消查询或者用户可以结束该过程。引擎还可以因会话的语句超时或死锁检测机制而强制结束查询。
阻止事务 – 事务在运行
ROLLBACK
或COMMIT
语句时停止阻止。当会话被客户端或网络问题断开连接或结束时,也会自动发生回滚。当数据库引擎关闭、系统内存不足等时,可以结束会话。
等待次数增加的可能原因
当 Lock:Relation
事件的发生频率高于正常值时,可能表明存在性能问题。典型的原因包括:
- 增加与表锁冲突的并发会话
-
用冲突锁定模式锁定相同表格的查询的并发会话数可能会增加。
- 维护操作
-
VACUUM
和ANALYZE
之类的运行状况维护操作可以显著增加冲突锁的数量。VACUUM FULL
获取ACCESS EXCLUSIVE
锁,ANALYZE
获取SHARE UPDATE EXCLUSIVE
锁。这两种类型的锁都可能导致Lock:Relation
等待事件。应用程序数据维护操作(例如刷新具体化视图)也可以增加阻止的查询和事务。 - 读取器实例的锁定
-
写入器和读取器持有的关系锁之间可能存在冲突。目前,仅
ACCESS EXCLUSIVE
关系锁复制到读取器实例。但是,ACCESS EXCLUSIVE
关系锁将与读取器持有的任何ACCESS SHARE
关系锁冲突。这可能会导致读取器上的锁定关系等待事件增加。
操作
根据等待事件的原因,我们建议采取不同的操作。
减少阻止 SQL 语句的影响
为了减少阻止 SQL 语句的影响,请尽可能修改应用程序代码。以下是减少数据块的两种常见方法:
使用
NOWAIT
选项 – 一些 SQL 命令,例如SELECT
和LOCK
语句,支持此选项。如果无法立即获取锁定,则NOWAIT
指令将取消请求锁定的查询。这种方法可以帮助防止阻止会话导致其后面堆积阻止的会话。例如:假设事务 A 正在等待事务 B 所持有的锁定。现在,如果 B 请求对被事务 C 锁定的表进行锁,那么事务 A 可能会被阻止,直到事务 C 完成。但是,如果事务 B 在请求对 C 进行锁定时使用
NOWAIT
,它可能会很快失败,并确保事务 A 不必无限期等待。使用
SET lock_timeout
– 设置lock_timeout
值,以限制 SQL 语句等待获取关系锁的时间。如果未在指定的超时内获取锁定,则请求锁定的事务将被取消。在会话级别设置此值。
尽量减少维护操作的影响
维护操作(例如 VACUUM
和 ANALYZE
)非常重要。我们建议您不要将其关闭,因为您会找到与这些维护操作相关的 Lock:Relation
等待事件。以下方法可以最大限度地减少这些操作的影响:
在非高峰时段手动运行维护操作。
要减少由 Autovacuum 任务导致的
Lock:Relation
等待,执行任何需要的 Autovacuum 优化。有关优化 Autovacuum 的信息,请参阅《Amazon RDS 用户指南》中的在 Amazon RDS 上使用 PostgreSQL Autovacuum。
检查读取器锁
您可以看到写入器和读取器的并发会话如何持有互相阻止的锁。执行此操作的一种方法是运行返回锁定类型和关系的查询。在该表中,可以找到对两个此类并发会话(一个写入器会话和一个读取器会话)的一系列查询。
重播过程会在取消读取器查询之前等待持续时间 max_standby_streaming_delay
。如示例中所示,100 毫秒的锁定超时远低于 max_standby_streaming_delay
默认值 30 秒。锁定在出现问题之前已超时。
序列事件 | 会话 | 命令或输出 |
---|---|---|
使用指定的值设置名为 READER 的环境变量,并尝试使用此端点连接到数据库实例。 |
读取器会话 |
CLI 命令:
输出: psql (15devel, server 10.14) Type "help" for help. |
设置名为 WRITER 的环境变量,并尝试使用此端点连接到数据库实例。 |
写入器会话 |
CLI 命令:
输出: psql (15devel, server 10.14) Type "help" for help. |
写入器会话在写入器实例上创建表 t1。 |
写入器会话 |
PostgreSQL 查询:
|
如果写入器上没有冲突的查询,则会立即在写入器上获取 ACCESS EXCLUSIVE 锁定。 |
写入器会话 |
|
读取器会话将锁定超时间隔设置为 100 毫秒。 |
读取器会话 |
PostgreSQL 查询:
|
读取器会话尝试从读取器实例上的表 t1 中读取数据。 |
读取器会话 |
PostgreSQL 查询:
示例输出: b --- (0 rows) |
写入器会话删除 t1。 |
写入器会话 |
PostgreSQL 查询:
|
查询超时并在读取器上被取消。 |
读取器会话 |
PostgreSQL 查询:
示例输出: ERROR: canceling statement due to lock timeout LINE 1: SELECT * FROM t1; ^ |
为确定错误的原因,读取器会话查询 |
读取器会话 |
PostgreSQL 查询:
|
结果表明, |
读取器会话 |
查询结果:
|