找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1499

积分

0

好友

190

主题
发表于 5 天前 | 查看: 16| 回复: 0

业务反馈一条简单的 INSERT 语句运行了半小时以上仍未结束,且进程未被阻塞。初步排查排除了常见的锁等待问题,通过检查活动会话,发现多个会话的等待事件为 OidGen

SELECT pid, state, wait_event, wait_event_type, usename,
       EXTRACT(EPOCH FROM (now()-query_start)),
       substr(query, 0, 150)
FROM pg_stat_activity
WHERE state != 'idle'
  AND EXTRACT(EPOCH FROM (now()-query_start)) > 1;

-- 输出显示关键信息:
-- wait_event: OidGen
-- wait_event_type: LWLock
-- query: INSERT INTO public.operation_log (...)

OidGen 等待事件通常与系统对象标识符(OID)的分配有关。当创建新数据库对象(如表、索引)的数量极大时,获取新OID可能变慢。但本次场景是INSERT操作,为何会涉及创建对象?

通过 pstack 抓取其中一个慢查询进程的堆栈,发现调用链清晰指向了Toast处理逻辑:

heap_insert -> heap_toast_insert_or_update -> toast_save_datum -> GetNewOidWithIndex

这表明在插入数据时,由于表存在大字段,触发了 PostgreSQL的Toast机制 以存储溢出数据,而在向Toast表中插入chunk元组时,需要为chunk_id字段(OID类型)生成一个新的、未使用的OID。

-- 查看该表的Toast表结构
\dt+ pg_toast.pg_toast_1143412359
-- 输出包含:
--   Column   | Type | Storage
-- ------------+------+---------
--  chunk_id   | oid  | plain   -- 此字段需要唯一OID
--  chunk_seq  | integer
--  chunk_data | bytea

toast_save_datum 函数中,为新数据分配chunk_id(即OID)的逻辑核心是调用 GetNewOidWithIndex。该函数需要扫描Toast表的索引,以寻找一个未被占用的OID。当Toast表中的数据条目极其庞大时,这个扫描过程会变得非常耗时。

本案例中,问题表的Toast表数据量达到了28亿条:

SELECT count(1) FROM pg_toast.pg_toast_1143412359;
--    count
-- ------------
-- 2882740871

系统OID的最大值约为42亿(2^32)。当可用OID空间紧张时,寻找空闲OID的效率会进一步下降,在极端情况下,甚至可能出现日志告警:“OID candidates have been checked ... times, but no unused OID has been found yet.”

进一步检查表结构发现,该业务表包含了249个字段,且均为text类型。这种设计极易产生大量Toast数据,是导致本次性能问题的根本原因。

解决方案与优化建议

  1. 清理历史数据:最直接的缓解措施是清理 Toast表中的历史冗余数据,减少数据条目,释放OID空间,从而提升GetNewOidWithIndex的扫描效率。
  2. 优化表结构:建议业务侧整改表结构。避免在单表中设计过多(尤其是可变长的)大字段。可以根据业务逻辑,将频繁访问的小字段与不常用的大字段拆分到不同的表中,或考虑使用更合适的存储方式。

总结

本次 INSERT 性能问题并非简单的锁等待,而是由于表设计不合理,导致Toast表膨胀,进而使得为新的Toast数据块分配唯一OID的过程变得极其缓慢。这提醒我们,在设计数据库表结构时,需对可能产生Toast的大字段保持警惕,合理的建模是保障数据库长期稳定高效运行的基础。

参考代码

  • toast_save_datum 函数逻辑可参阅 PostgreSQL 源码:src/backend/access/common/toast_internals.c



上一篇:ChatGPT应用商店正式上线:集成Adobe、Canva等应用实践指南
下一篇:Go1.26 Goroutine调度指标详解:runtime/metrics新增6个关键监控项
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-24 21:13 , Processed in 0.355451 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表