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 查询:
|
|
结果表明, |
读取器会话 |
查询结果:
|