PostgreSQL 中 5 个最容易“踩坑”的锁行为

PostgreSQL 锁 PostgreSQL的锁机制在保证数据一致性和并发控制方面发挥着重要作用。了解锁的类型、工作原理以及优化策略,有助于提高数据库性能和稳定性。本文对PostgreSQL的锁进行了详细介绍,希望对您有所帮助。# PostgreSQL 锁## 引言在数据库管理系统中,锁是确保数据一致性和并发控制的关键机制。PostgreSQL,作为一款功能强大的开源关系型数据库管理系统,同样采用了锁机制来处理并发访问和事务管理。本文将深入探讨PostgreSQL中的锁机制,包括锁的类型、工作原理以及如何进行优化。 阅读详情

前言

PostgreSQL 使用 MVCC(多版本并发控制)实现并发控制机制,读写操作互不阻塞。PostgreSQL 提供了 8 种表级锁模式与 4 种行级锁模式,官方文档的锁冲突对照表清晰标注了各类锁的互斥关系。

但在真实生产环境中,锁冲突往往并不会像文档描述得那样直观。很多看似无害的 SQL,会在特定条件下触发意料之外的阻塞链、死锁甚至业务中断。

本文整理了 PostgreSQL 中 5 个最容易被忽略、却又极具破坏性的锁行为。

运行环境

  • 数据库版本:PostgreSQL 18
  • 事务隔离级别:READ COMMITTED(默认)

一、ACCESS EXCLUSIVE 等待时,会触发“连锁阻塞”

这是 PostgreSQL 中最经典、也最危险的一类锁问题。一个本应瞬间完成的 ALTER TABLE,可能导致整个业务读请求全部阻塞。

假设存在如下场景:

Session 1

SELECT pg_sleep(600) FROM t LIMIT 1; -- a long-running SELECT

Session 2

ALTER TABLE t ADD COLUMN name text;

由于 Session 1 持有 ACCESS SHARE 锁,因此 ALTER TABLE 所需的 ACCESS EXCLUSIVE 锁只能等待。到这里为止,一切都符合预期。真正容易被忽略的是 PostgreSQL 的锁等待机制采用 FIFO 队列。

1.png

因此,一旦 ACCESS EXCLUSIVE 锁进入等待队列,后续所有访问该表的新 SELECT,也会被排在它后面等待,即使这些 SELECT 与最开始那个长查询本身并不冲突。

最终形成以下阻塞链:

  1. 数据表上运行长耗时查询;
  2. 表结构变更等需要排他访问锁的语句,因锁冲突进入等待队列;
  3. 后续所有查询语句均在队列中排队等待。

链式阻塞会大幅延长查询响应时间,进而引发业务故障。

优化方案

  • 执行需申请排他访问锁的语句时,配置lock_timeout参数,避免锁等待无限持续;
  • 通过pg_stat_activity视图提前排查数据库内的长耗时查询。

二、外键约束导致的“隐式死锁”

外键约束会隐式触发锁申请,由此引发非直观的死锁问题。

当 INSERT 写入子表时,PostgreSQL 会自动对父表对应记录加锁FOR KEY SHARE,这是为了保证引用完整性。

以数据表 t 和主表 s 为例,向 t 插入数据时,系统会自动对 s 的关联行添加键共享锁。键共享锁与更新锁存在互斥关系,若两个会话以相反顺序,先对主表不同行加更新锁,再插入外键关联数据,会形成循环等待,最终触发死锁。

Session 1

BEGIN;
SELECT * FROM s WHERE id=1 FOR UPDATE; -- lock row s.id=1 with FOR UPDATE

Session 2

BEGIN;
SELECT * FROM s WHERE id=2 FOR UPDATE; -- lock row s.id=2 with FOR UPDATE

Session 1

INSERT INTO t (s_id) VALUES (2); -- wants FOR KEY SHARE on row s.id=2 (waits for Session 2)

Session 2

INSERT INTO t (s_id) VALUES (1); -- wants FOR KEY SHARE on row s.id=1 (deadlock detected)

该场景的特殊性体现在两方面:纯插入类 SQL 会隐性锁定外键主表数据行;从业务 SQL 表层无法直观识别锁操作。

优化方案

  • 规避多会话反向加锁、交叉插入外键数据的设计,从源头杜绝死锁;
  • 统一全应用的加锁顺序,例如按照主键升序对主表数据行加锁,固定单向加锁逻辑;
  • 死锁会以报错形式抛出,业务代码需增加异常重试逻辑。

三、两个 INSERT 之间也可能发生死锁

很多人认为只有 UPDATE / DELETE 才会死锁。实际上两个纯 INSERT 事务,同样可能死锁。

Session 1

BEGIN;
INSERT INTO t (id) VALUES (1);

Session 2

BEGIN;
INSERT INTO t (id) VALUES (2);

Session 1

INSERT INTO t (id) VALUES (2); -- waits for Session 2 to commit

Session 2

INSERT INTO t (id) VALUES (1); -- deadlock detected

主键与唯一约束会对重复数据进行校验。若目标数据正被其他事务插入,当前插入语句会进入等待状态,等待对方事务执行完毕。若对方事务提交,则判定为唯一约束冲突;若对方事务回滚,则当前插入正常执行。

上述案例中,两个会话互相等待对方事务提交,形成循环等待,最终触发死锁。

优化方案

  • 使用 SERIAL / IDENTITY / Sequence 生成唯一 ID,从根源避免多会话并发插入相同数据;
  • 应用层必须支持死锁重试。

四、唯一不会主动让步的 Autovacuum

通常情况下 Autovacuum 获取的是SHARE UPDATE EXCLUSIVE。当与其他语句发生冲突时 Autovacuum 通常会自动取消。因此很多人会认为 Autovacuum 不会真正影响业务,但实际上存在一个例外。

当 PostgreSQL 检测到 relfrozenxid 接近 autovacuum_freeze_max_age 时,会启动一种特殊的 Autovacuum(to prevent wraparound),这种 Autovacuum 不会自动取消。

实际可能出现以下执行流程:

  1. 表接近事务 ID 回卷风险
  2. Wraparound Autovacuum 启动
  3. ALTER TABLE 请求 ACCESS EXCLUSIVE
  4. ALTER TABLE 等待 Autovacuum
  5. 后续 SELECT 全部进入阻塞队列

该场景结合前文链式阻塞问题后,极易快速引发严重故障。

优化方案

  • 监控 pg_stat_activity 视图,发现防事务 ID 回卷的清理进程时,等待进程执行完成再开展其他操作;
  • 定期查询数据表老化状态,提前预判风险,默认阈值为 2 亿事务:
SELECT relname, age(relfrozenxid)
FROM pg_class
WHERE relkind = 'r'
ORDER BY age(relfrozenxid) DESC;
  • 规划表结构变更等 DDL 操作前,先检查表老化值。若接近阈值,提前手动执行 VACUUM FREEZE,再执行 DDL 语句。

五、VACUUM 隐藏的 ACCESS EXCLUSIVE 阶段

很多人认为 VACUUM 只会获取SHARE UPDATE EXCLUSIVE,实际上并不完全如此。VACUUM 在最后回收表尾空页时,会执行 truncate,这一阶段需要获取锁 ACCESS EXCLUSIVE。

如果此时存在长时间 SELECT VACUUM 会等待 ACCESS EXCLUSIVE。随后新的 SELECT 会再次触发第一类问题中的“连锁阻塞”。

在流复制备库上,这类问题影响更明显。主库上 SELECT 可以持续等待,但备库上 WAL Replay 无法无限等待。因此当 VACUUM 的 ACCESS EXCLUSIVE WAL 被回放到备库时,如果备库存在冲突查询,WAL Replay 会暂停。一旦超过max_standby_streaming_delay,备库会强制取消冲突查询。这是主备行为之间一个非常重要的差异。

优化方案

  • PostgreSQL 12 及以上版本,可单表关闭清理截断功能,配置vacuum_truncate = false;
  • PostgreSQL 18 及以上版本,支持全局参数vacuum_truncate,统一控制全库截断逻辑;
  • 备库存在长查询业务时,调大max_standby_streaming_delay参数延长等待时长,设置为-1 代表无限等待。

总结

以上五类异常行为,均是 PostgreSQL 锁机制为保障数据正确性而产生的固有表现。机制设计符合规范,但在实际运维中极易形成风险点。

链式阻塞问题结合其他锁异常场景后,风险会快速放大。配置lock_timeout、持续监控pg_stat_activity视图,是保障数据库稳定运行的基础防护手段。

参考资料

  • https://www.postgresql.org/docs/current/explicit-locking.html
  • https://www.postgresql.org/message-id/d7df81620708101038k772a2cderb52bb09f5440bd1b@mail.gmail.com
  • https://leosjoberg.com/blog/lock-propagation-postgres/
  • https://xata.io/blog/migrations-and-exclusive-locks

作者:Shinya Kato

原文链接:

https://dev.to/shinyakato_/5-postgresql-locking-behaviors-that-trip-people-up-4k7n

PostgreSQL数据类型怎么选才高效不踩坑? PostgreSQL 提供了丰富的原生数据类型,覆盖数值、字符、日期、几何、网络等多个场景。这些类型的设计遵循 SQL 标准,同时扩展了PostgreSQL特有的功能(如几何类型、JSONB)。理解数据类型是设计合理表结构的基础——选择合适的类型能提升存储效率、避免数据错误、优化查询性能。 阅读详情

相关推荐

PostgreSQL锁表问题诊断与高效解决方案

本文深入探讨了PostgreSQL锁表问题的诊断与解决方案。通过分析锁机制原理,提供核心查询语句快速定位阻塞进程,并介绍pg_cancel_backend等紧急解锁方法。文章强调从事务优化、索引设计及配置调优等根本层面预防锁表,帮助运维人员高效处理数据库并发瓶颈,保障系统稳定运行。

weixin_29238147的博客 560

SpringBoot切换PostgreSQL踩坑指南

4、mysql一般用tinyint类型和java的Boolean字段对应并且在查询和更新时支持自动转换,但是postgres是强类型不支持,如果想无缝迁移postgres内部就新增自动转换的隐式函数,但是缺点是每次部署postgres后都要去执行一次脚本。这个可以说是最坑的, 因为mysql是支持自动类型转换的。如果不想这样,只能修改代码的所有表对象的字段类型和传参类型保证与postgres数据库的字段类型对应,但是有些依赖的框架底层自己操作数据库可能就无法修改源码了,只能修改数据库表字段类型了。

2501_92606851的博客 1011

PostgreSQL 核心原理:行锁、表锁、咨询锁与死锁详解(锁机制)

如果需要启动PostgreSQL数据库,可进入PostgreSQL的安装目录,在cmd窗口下执行:pg_ctl.exe start -D ..\data 。即可重新启动服务 。执行结果如下图:

数据知道的博客 3万+

面试:详细介绍PostgreSQL锁类型、锁机制

面试:详细介绍PostgreSQL锁类型、锁机制

chenoracle的博客 1489

实战对比:VINS和ORBSLAM3在无人机避障中的表现(含实测数据)

本文通过实战测试,深度对比了VINS和ORBSLAM3两种主流视觉SLAM算法在无人机避障中的表现。测试聚焦于光照变化、动态遮挡和快速运动三大挑战,提供了详细的实测数据与性能分析。结果表明,VINS在计算效率和实时性上占优,而ORBSLAM3在定位精度和地图管理方面更稳健,为不同应用场景下的工程选型提供了清晰依据。

醉三国 628

编程_三大编程思想:POP、OOP、AOP

简单介绍POP、OOP、AOP三大编程思想的区别和优缺点~

mikimo的博客 3899

PostgreSQL LOCK(锁)

PostgreSQL锁机制实战手册摘要 PostgreSQL采用MVCC机制实现读写不阻塞,但写操作仍需锁机制。本手册全面介绍PostgreSQL锁类型(行级、表级)、使用场景与优化策略。核心内容包括: 锁类型:详细解析行级锁(FOR UPDATE/SHARE等)和表级锁各模式的特点与冲突情况 应用策略:对比悲观锁与乐观锁的实现方案,提供代码示例 死锁处理:分析死锁检测机制,提供统一加锁顺序等解决方案 监控诊断:给出锁查询SQL和进程终止方法 性能优化:推荐NOWAIT、SKIP LOCKED等技巧减少锁冲

likuoelie的博客 1168

CentOS7 编译升级GCC至9.3.0

1)下载GCC9.2.0源码并解压 从GCC官方FTP下载地址可以看到GCC最新版本为9.3.0。由于官网下载速度慢,实际上用清华大学的镜像站进行下载,代码如下: wget -c /opt/tmp/ https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.gz #考虑到安装失败的可能性,创建一个临时文件夹来安装GCC...

haha123486的博客 1万+

PostgreSQL 锁等待排查

在数据库中,常用 锁 和 MVCC 来保障事务的一致性及提高并发性。锁问题的定位和排查也是数据库运维人员必会的技能,本篇文章介绍 PostgreSQL 如何排查定位锁堵塞问题。

分享既学习 2960

手把手教你用稚晖君Dummy机械臂实现位置控制:代码解析与调试技巧

本文深入解析了稚晖君Dummy机械臂实现高精度位置控制的代码核心与调试技巧。从CAN总线通信协议、三种位置控制模式(基础、带时间约束、带速度限制)的解析入手,详细阐述了命令帧结构、状态同步机制及单位换算。文章还提供了从通信测试、PID参数整定到异常处理、性能优化的完整实战调试流程,并探讨了多轴协调、自适应控制等进阶话题,旨在帮助开发者快速掌握该机械臂的精准运动控制。

weixin_29164091的博客 416

CVAT自动标注避坑指南:从nuctl安装到YOLOv5模型部署的完整流程

本文详细介绍了在CVAT中部署YOLOv5自动标注功能的完整流程与避坑指南。重点解决了从nuctl工具安装、项目创建时因网络问题导致的镜像拉取失败,到最终模型函数部署与CVAT集成的关键步骤。针对国内网络环境,提供了实用的镜像替换方案,帮助用户顺利完成基于CPU的自动化标注环境搭建。

pytorch8learner的博客 229

postgresql锁处理

postgresql锁处理 转自:pg中关于AccessShareLock和ExclusiveLock的问题中德哥的回答 要搞清楚锁,首先要搞清楚,PG是有很多可以加锁的对象的,每种对象下面,再去看它的锁冲突。 可以加锁的对象: LOCKTAG_RELATION, /* whole relation */ /* ID in...

sunbocong的博客 2915

5GS 协议栈 — PFCP 协议 — URR 用量上报规则

目录 文章目录目录URR 用量上报规则UEE 的参数Usage Report 的参数示例 URR 用量上报规则 29244 5.2.2 Usage Reporting Rule URR 的作用? 用来告诉 UPF 如何对 PDR 识别的 SDF 或 Application 业务进行使用量统计信息的上报。CP 收到 Report Information 后,可用于计费或者管控(e.g. 超量限速)等用途。 URR 在哪个流程里下发的? N4 会话建立流程。 N4 会话修改流程。 URR 是怎么工作

烟云的计算 4592

PostgreSQL:锁问题排查与处理指南

在使用这些函数之前,确保你有足够的权限(通常是超级用户或具有相应权限的用户),并且要谨慎使用,不要意外终止正常的事务。通过这些方法,您可以有效地排查和处理 PostgreSQL 中的锁相关问题,并尽量减少锁对数据库性能的影响。表中包含了许多关于锁的信息,例如锁的类型、数据库 ID、关系 ID(表)、事务 ID、会话 ID 等。如果发现某个事务(进程)长时间持有锁并阻塞了其他事务,你可以选择终止该事务。在应用程序中,可以设置锁的超时时间,以避免长时间等待锁而导致的性能问题。来查看当前数据库中的锁信息。

喝醉酒的小白 2346

YOLOv13改进策略【Backbone/轻量化】| 替换骨干网络 CVPR-2024 StarNet,超级精简高效的轻量化模块

本文记录的是。StarNet设计简洁,没有复杂的设计和精细调整的超参数,仅是一个 4 阶段的分层架构。并且其中能够在低维空间计算的同时考虑极高维的特征这一特性,进而提高模型精度。本文在替换骨干网络中配置了原论文中的starnet_s1starnet_s2starnet_s3和starnet_s4七种模型,以满足不同的需求。

Limiiiing的博客 672

Transformer时间序列预测-多变量输入-单变量输出+多变量输出,完整代码数据,可直接运行

Transformer时间序列预测-多变量输入-单变量输出+多变量输出,完整代码数据,可直接运行

9794

LangGraph从开发到生产部署:踩了4个坑才知道“本地跑通了“和“上线能用了“差多远

LangGraph 是LangChain 生态中专门用于构建、编排与执行多步骤、多代理(Multi-Agent)复杂 AI 工作流的可视化 / 代码化开发平台,核心解决传统 LLM 应用 “单轮对话、线性执行、无状态管理” 的局限性,支持构建具备循环、分支、状态持久化、多代理协作的高级 AI 系统(如自主 Agent、工作流引擎、复杂 RAG 增强系统)。它是 LangChain 官方推出的 “工作流编排层”,既提供Python 代码 SDK(核心开发方式),也配套。

专注 Java / Python 开发,AI 大模型应用学习,持续输出源码教程,实战项目案例,学习笔记,拒绝空话,只写能直接跑的代码与可落地方案,关注我,一起少走弯路。 1413

贝叶斯统计 [韦来生编]

贝叶斯(Bayes)统计是近几十年来迅速发展起来的数理统计的一个重要分支。贝叶斯方法与经典统计方法的主要不同之处是进行统计推断时除了利用样本信息外,还要利用参数的先验信息,因此可以提高统计推断或统计决策的效果。它在经济、金融、生物、医学、自然科学和社会科学等许多领域具有广泛的应用。贝叶斯方法的研究已渗透到了统计学的几乎所有领域。作者在给中国科学技术大学概率论与数理统计专业本科生开设的“数理统计”课程中有一章专门讲授“贝叶斯方法和统计决策理论”,近十年来也给中国科学技术大学概率统计专业研究生开设过几次“贝叶斯分析”课。本书是在对过去讲稿的内容作了适当的增减和调整的基础上完成的。  本书共分六章。第1章是绪论,介绍了贝叶斯统计的若干基本概念,同时对必要的数理统计的基础知识有重点地作了回顾。第二章介绍了确定先验分布的若干可供选择的方法。第三章介绍了几类常见统计模型参数的后验分布的主要结果和计算方法。第四章和第五章分别介绍了“贝叶斯统计推断”和“贝叶斯统计决策”的内容。第六章介绍了贝叶斯统计计算的若干方法,包括蒙特卡洛方法和马尔可夫链蒙特卡洛(MCMC)方法以及相关统计软件的简介。本书的每一章附右大量的例题和习题,书末附有常用的几个表格和部分习题解答供读者查用。  大约可在54学时内讲授本书的第1章至第六章的主要内容,教师可根据学时需要选讲本书第1章至第六章的部分内容。书中标“*”号的章节可略去不讲,留给读者作为阅读材料。第六章例题中的R代码和部分例题的数据文件等可从作者个人主页下载。  作者在编写本书的过程中参考了J.O.Berger教授的《统计决策论及贝叶斯分析》和茆诗松教授编写的《贝叶斯统计》等书中的一些内容,以及《贝叶斯分析》一书中由张伟平博士编写的有关贝叶斯统计计算的一些内容。在此表示衷心感谢。  本书编写准备过程中,中国科学技术大学统计与金融系的几个研究生帮助完成了本书部分中文的录入和排版,作者对他们的辛勤工作表示真诚的感谢。高等教育出版社为本书的出版给予了大力支持。在此一并致谢。

(四)从“入门迷茫”到“精通实战”——PostgreSQL从入门到精通实战指南

摘要:PostgreSQL新手入门与实战指南 本文以开发者视角分享了从MySQL转向PostgreSQL的学习历程,重点介绍了PostgreSQL的核心优势、与MySQL的关键差异,以及实际开发中的安装配置和基础操作指南。文章详细对比了两种数据库在数据类型、语法、并发控制等方面的区别,并提供了PostgreSQL 16在Windows系统的安装步骤和基础SQL操作示例,特别强调了自增主键、分页查询等常见操作的语法差异。通过实战案例展示了表创建、数据增删改查等基本操作,帮助Java开发者快速掌握Postgre

修行者Java的博客 508

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

PostgreSQL(八)锁的相关操作

PostgreSQL(八)锁的相关操作

ACGkaka的博客 4677

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

时间截断:PostgreSQL 与 MySQL 时间类型避坑指南

从精度、索引、到 Java 入参的完整梳理在日常开发中,时间字段的设计与查询往往最容易踩坑:精度到底选到秒还是毫秒?和差多少?用DATE_TRUNC会不会让索引失效?Java 想按季度查询该怎么传参?本文基于 PostgreSQL 与 MySQL(5.7/8.0)最新行为,一次性把高频问题讲透。

Vic10101的博客 777

项目从 Mysql切换 PostgreSQL 改造及踩坑记录

原项目框架 SpringBoot + MybatisPlus + Mysql。

BASK2312的博客 1970

PostgreSQL timestamp踩坑记录

为什么80%的码农都做不了架构师?>>> ...

weixin_34342905的博客 1万+

Postgresql源码(69)常规锁细节分析

数据结构需要注意的是: - LOCKTAG唯一值组成:四个公共区域可以放四个唯一标识;一个锁类型记录锁住的对象类型;一个锁method(咨询所一类、其他锁一类)。 - 本地锁表:相当于缓存,记录已经申请过得锁,包括fastpath锁和主锁表的锁,都会在本地锁表中记录。 - fastpath - 记录在PGPROC中,使用一个uint64位图(3位一组16组共48位,每组记录一个锁级别)和一个16个oid的数组记录16个表的Oid。 - fastpath进入需要两个条件:1 弱锁、2 共享内存

InternalsOf 1410

PostgreSQL中所的锁

为了确保复杂的事务可以安全地同时运行,PostgreSQL提供了各种级别的锁来控制对各种数据对象的并发访问,使得对数据库关键部分的更改序列化。事务并发运行,直到它们尝试获取互相冲突的锁为止(比如两个事务更新同一行时)。当多个事务同时在数据库中运行时,并发控制是一种用于维持一致性和隔离性的技术,在PostgreSQL中,使用快照隔离来实现多版本并发控制,同时以两阶段锁定 (2PL) 机制为辅。在执行DDL时使用2PL,在执行DML时使用SI。

Vulpes corsac 800
上一篇: PostgreSQL 技术日报 (6月1日)|逻辑复制问题修复,AI 行业动态速览
下一篇: PostgreSQL 技术日报 (6月2日)|逻辑解码优化,PGConfEU 2026征稿收官
IvorySQL
博客等级 码龄5年 745粉丝 565原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值