最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PostgreSQL核心原理之?dāng)?shù)據(jù)庫(kù)偶爾會(huì)卡頓的原因分析

 更新時(shí)間:2026年02月03日 10:57:01   作者:數(shù)據(jù)知道  
PostgreSQL功能強(qiáng)大、穩(wěn)定可靠的開源關(guān)系型數(shù)據(jù)庫(kù)系統(tǒng),廣泛應(yīng)用于各種規(guī)模的企業(yè)和項(xiàng)目中,本文將從PostgreSQL的核心原理出發(fā),深入剖析導(dǎo)致“偶爾卡頓”的常見原因,并結(jié)合底層機(jī)制進(jìn)行解釋,幫助 DBA 和開發(fā)者理解問題本質(zhì),從而更有效地排查與優(yōu)化,感興趣的朋友一起看看吧

PostgreSQL 是一個(gè)功能強(qiáng)大、穩(wěn)定可靠的開源關(guān)系型數(shù)據(jù)庫(kù)系統(tǒng),廣泛應(yīng)用于各種規(guī)模的企業(yè)和項(xiàng)目中。然而,在實(shí)際使用過程中,用戶偶爾會(huì)遇到“數(shù)據(jù)庫(kù)卡頓”——即查詢響應(yīng)變慢、連接堆積、甚至整個(gè)實(shí)例暫時(shí)無響應(yīng)的現(xiàn)象。這類問題往往不是單一原因造成的,而是多種因素交織作用的結(jié)果。

本文將從 PostgreSQL 的核心原理出發(fā),深入剖析導(dǎo)致“偶爾卡頓”的常見原因,并結(jié)合底層機(jī)制進(jìn)行解釋,幫助 DBA 和開發(fā)者理解問題本質(zhì),從而更有效地排查與優(yōu)化。

一、PostgreSQL 架構(gòu)簡(jiǎn)述

1.1 關(guān)鍵架構(gòu)組件

在深入問題之前,先快速回顧 PostgreSQL 的關(guān)鍵架構(gòu)組件:

  • 后端進(jìn)程模型:每個(gè)客戶端連接對(duì)應(yīng)一個(gè)獨(dú)立的后端進(jìn)程(backend process),通過共享內(nèi)存通信。
  • 共享緩沖區(qū)(Shared Buffers):用于緩存數(shù)據(jù)頁,減少磁盤 I/O。
  • WAL(Write-Ahead Logging)機(jī)制:所有修改先寫入 WAL 日志,再應(yīng)用到數(shù)據(jù)文件,保障 ACID。
  • MVCC(多版本并發(fā)控制):通過版本鏈實(shí)現(xiàn)讀寫不阻塞,但會(huì)產(chǎn)生“死元組”(dead tuples)。
  • VACUUM 機(jī)制:清理死元組、更新統(tǒng)計(jì)信息、防止事務(wù) ID 回卷(wraparound)。
  • 檢查點(diǎn)(Checkpoint):將臟頁從共享緩沖區(qū)刷入磁盤,確保崩潰恢復(fù)效率。
  • 鎖與等待機(jī)制:包括表級(jí)鎖、行級(jí)鎖、輕量級(jí)鎖(LWLock)等。

這些機(jī)制共同保障了 PostgreSQL 的一致性、可靠性和并發(fā)能力,但也可能在特定條件下成為性能瓶頸。

1.2 卡頓核心原因總結(jié)

PostgreSQL 的“偶爾卡頓”通常不是 bug,而是其穩(wěn)健架構(gòu)在高負(fù)載或配置不當(dāng)下的自然表現(xiàn)。核心原因可歸結(jié)為:

類別根本機(jī)制典型表現(xiàn)
I/O 峰值Checkpoint、VACUUMI/O 飆升,響應(yīng)延遲
MVCC 副作用死元組、長(zhǎng)事務(wù)表膨脹、清理滯后
并發(fā)控制鎖、LWLock等待事件增多
WAL 機(jī)制日志寫入、歸檔主庫(kù)延遲、WAL 堆積
查詢優(yōu)化統(tǒng)計(jì)信息失效執(zhí)行計(jì)劃退化

預(yù)防勝于治療:合理的配置、完善的監(jiān)控、定期維護(hù)(VACUUM/ANALYZE)、良好的應(yīng)用設(shè)計(jì)(短事務(wù)、連接池),是避免“卡頓”的關(guān)鍵。

二、“偶爾卡頓”的典型場(chǎng)景與核心原因

2.1 檢查點(diǎn)(Checkpoint)風(fēng)暴

現(xiàn)象:每隔一段時(shí)間(如 checkpoint_timeout 設(shè)置為 5 分鐘),數(shù)據(jù)庫(kù)突然變慢幾秒到幾十秒,I/O 利用率飆升。

原理:PostgreSQL 在檢查點(diǎn)期間會(huì)將共享緩沖區(qū)中的“臟頁”(被修改但未寫入磁盤的數(shù)據(jù)頁)批量刷入磁盤。如果在兩次檢查點(diǎn)之間積累了大量臟頁(例如高寫入負(fù)載),檢查點(diǎn)過程會(huì)觸發(fā)大量同步 I/O,導(dǎo)致 I/O 隊(duì)列擁堵,進(jìn)而影響其他查詢。

關(guān)鍵參數(shù):

  • checkpoint_timeout:檢查點(diǎn)間隔(默認(rèn) 5min)
  • max_wal_size:WAL 文件最大值,間接控制臟頁積累量
  • checkpoint_completion_target:檢查點(diǎn)平滑完成目標(biāo)比例(建議設(shè)為 0.9)

優(yōu)化建議:增大 max_wal_size(如 4GB~8GB),調(diào)高 checkpoint_completion_target(0.9),讓檢查點(diǎn)更平滑;同時(shí)確保磁盤 I/O 能力足夠(如使用 SSD)。

2.2 AUTOVACUUM 滯后或爆發(fā)式運(yùn)行

現(xiàn)象:某張大表長(zhǎng)時(shí)間未被清理,突然觸發(fā)一次大規(guī)模 VACUUM,CPU 或 I/O 突增,查詢變慢。

原理:PostgreSQL 使用 MVCC,UPDATE/DELETE 不會(huì)立即刪除舊數(shù)據(jù),而是標(biāo)記為“死元組”。若不及時(shí)清理,會(huì)導(dǎo)致:

  • 表膨脹(bloat):物理大小遠(yuǎn)大于邏輯數(shù)據(jù)量
  • 查詢需掃描更多無效數(shù)據(jù)
  • 索引效率下降

autovacuum 進(jìn)程會(huì)自動(dòng)清理,但若配置不當(dāng)(如 autovacuum_vacuum_scale_factor 過大)或系統(tǒng)負(fù)載過高,可能導(dǎo)致清理滯后,最終積壓成“雪崩式”VACUUM。

關(guān)鍵參數(shù):

  • autovacuum_vacuum_scale_factor(默認(rèn) 0.2)+ autovacuum_vacuum_threshold(默認(rèn) 50)
  • autovacuum_max_workers:最大并發(fā) autovacuum 進(jìn)程數(shù)
  • maintenance_work_mem:影響 VACUUM 效率

優(yōu)化建議

  • 對(duì)高頻更新表,設(shè)置更激進(jìn)的 autovacuum 策略(如 scale_factor=0.05)
  • 監(jiān)控 pg_stat_user_tables.n_dead_tup,及時(shí)發(fā)現(xiàn)膨脹
  • 使用 pg_repackVACUUM FULL(謹(jǐn)慎!會(huì)鎖表)處理嚴(yán)重膨脹

2.3 事務(wù) ID 回卷(Transaction ID Wraparound)風(fēng)險(xiǎn)

現(xiàn)象:數(shù)據(jù)庫(kù)突然進(jìn)入只讀模式,或出現(xiàn)“database is not accepting commands to avoid wraparound data loss”錯(cuò)誤。

原理:PostgreSQL 使用 32 位事務(wù) ID(XID),最多支持約 20 億個(gè)事務(wù)。為防止回卷導(dǎo)致數(shù)據(jù)丟失,系統(tǒng)要求所有活躍事務(wù)的 XID 必須在“安全窗口”內(nèi)。若未及時(shí)執(zhí)行 VACUUM 更新 relfrozenxid,系統(tǒng)會(huì)強(qiáng)制凍結(jié)(freeze)舊元組。

當(dāng)接近回卷閾值(約 15 億事務(wù))時(shí),PostgreSQL 會(huì)啟動(dòng)緊急 autovacuum,甚至阻止新寫入。

注意:這不是“偶爾卡頓”,而是嚴(yán)重故障前兆!

優(yōu)化建議:

  • 定期監(jiān)控 age(datfrozenxid),確保 < 10 億
  • 對(duì)大表啟用 autovacuum_freeze_max_age 調(diào)優(yōu)(默認(rèn) 2 億,可適當(dāng)降低)
  • 避免長(zhǎng)事務(wù)(如未提交的 idle in transaction)

2.4 長(zhǎng)事務(wù)或空閑事務(wù)(idle in transaction)

現(xiàn)象:某些查詢長(zhǎng)時(shí)間不返回,其他會(huì)話無法 UPDATE/DELETE 某些行。

原理:PostgreSQL 的 MVCC 依賴于“最老活躍事務(wù)”來判斷哪些元組仍需保留。若存在一個(gè)長(zhǎng)時(shí)間未提交的事務(wù)(即使是 BEGIN; SELECT ...; 后掛起),會(huì)導(dǎo)致:

  • 死元組無法被 VACUUM 清理
  • 表持續(xù)膨脹
  • 鎖等待(如行鎖、謂詞鎖)

即使該事務(wù)不做任何修改,也會(huì)阻礙系統(tǒng)清理。

排查命令

SELECT pid, query, state, now() - xact_start AS xact_age
FROM pg_stat_activity
WHERE state = 'idle in transaction'
ORDER BY xact_age DESC;

優(yōu)化建議

  • 應(yīng)用層避免開啟事務(wù)后長(zhǎng)時(shí)間不提交
  • 設(shè)置 idle_in_transaction_session_timeout(如 5min)自動(dòng)終止空閑事務(wù)

2.5 鎖競(jìng)爭(zhēng)與死鎖

現(xiàn)象:部分查詢長(zhǎng)時(shí)間等待,pg_stat_activity.wait_event 顯示 Lockrelation 等待。

原理:雖然 PostgreSQL 讀寫不阻塞,但在以下情況仍會(huì)加鎖:

  • DDL 操作(如 ALTER TABLE)需要排他鎖
  • SELECT FOR UPDATE 顯式加行鎖
  • 大量并發(fā) UPDATE 同一行

若鎖持有時(shí)間過長(zhǎng),或鎖順序不一致,會(huì)導(dǎo)致連鎖等待甚至死鎖。

排查工具

-- 查看鎖等待
SELECT blocked_locks.pid     AS blocked_pid,
       blocking_locks.pid    AS blocking_pid,
       blocked_activity.query AS blocked_query,
       blocking_activity.query AS blocking_query
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks
    ON blocking_locks.locktype = blocked_locks.locktype
    AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
    AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
    AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
    AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
    AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
    AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
    AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
    AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
    AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
    AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.GRANTED;

優(yōu)化建議

  • 減少事務(wù)粒度,盡快提交
  • 避免在事務(wù)中執(zhí)行耗時(shí)操作(如網(wǎng)絡(luò)調(diào)用)
  • 統(tǒng)一訪問順序,避免死鎖

2.6 WAL 寫入瓶頸與 WAL 歸檔延遲

現(xiàn)象:高寫入負(fù)載下,wal writercheckpointer 進(jìn)程 CPU/I/O 高,主庫(kù)延遲上升。

原理:所有修改必須先寫入 WAL(順序?qū)懀?,再異步刷盤。若:

  • 磁盤寫入速度慢(尤其是 HDD)
  • WAL 歸檔(archive_command)執(zhí)行慢
  • 流復(fù)制備庫(kù)延遲嚴(yán)重

會(huì)導(dǎo)致 WAL 文件堆積,甚至觸發(fā) max_wal_size 限制,迫使檢查點(diǎn)提前,加劇 I/O 壓力。

優(yōu)化建議

  • 使用高速磁盤(NVMe SSD)存放 WAL(pg_wal 目錄)
  • 優(yōu)化 archive_command(如使用 WAL-G、并行歸檔)
  • 監(jiān)控 pg_stat_archiverpg_stat_wal_receiver

2.7 共享內(nèi)存爭(zhēng)用(LWLock 等待)

現(xiàn)象:高并發(fā)下,wait_event 顯示 WALWriteLock、BufferContent、ProcArrayLock 等輕量級(jí)鎖等待。

原理:PostgreSQL 使用輕量級(jí)鎖(LWLock)保護(hù)共享結(jié)構(gòu)(如緩沖區(qū)、WAL 緩沖區(qū)、進(jìn)程數(shù)組)。在極高并發(fā)(數(shù)千連接)下,這些鎖可能成為瓶頸。

典型案例

  • 大量短連接頻繁創(chuàng)建/銷毀 → ProcArrayLock 爭(zhēng)用
  • 高頻小事務(wù) → WALWriteLock 爭(zhēng)用

優(yōu)化建議

  • 使用連接池(如 PgBouncer)減少后端進(jìn)程數(shù)
  • 調(diào)整 wal_buffers(默認(rèn) -1,通常足夠)
  • 升級(jí)到 PostgreSQL 14+(引入 WAL 并發(fā)寫入優(yōu)化)

2.8 查詢計(jì)劃突變(Plan Regression)

現(xiàn)象:某個(gè)原本很快的查詢突然變慢,且每次執(zhí)行都慢(非“偶爾”),但有時(shí)因統(tǒng)計(jì)信息更新又恢復(fù)正常。

原理:PostgreSQL 依賴統(tǒng)計(jì)信息(pg_stats)生成執(zhí)行計(jì)劃。若:

  • 表數(shù)據(jù)分布突變(如新增大量數(shù)據(jù))
  • ANALYZE 未及時(shí)執(zhí)行
  • 參數(shù)化查詢因綁定變量值不同選擇不同計(jì)劃

可能導(dǎo)致優(yōu)化器選擇低效計(jì)劃(如嵌套循環(huán)代替哈希連接)。

優(yōu)化建議

  • 定期 ANALYZE,或啟用 track_counts = on
  • 對(duì)關(guān)鍵查詢使用 PREPARE 或 plan caching
  • 使用 pg_hint_plan 強(qiáng)制計(jì)劃(臨時(shí)手段)
  • 升級(jí)到 PostgreSQL 16+(支持 plan invalidation 自動(dòng)刷新)

三、如何系統(tǒng)性排查“偶爾卡頓”?(重要)

  • 監(jiān)控基礎(chǔ)指標(biāo)
    • CPU、內(nèi)存、I/O(iostat, iotop)
    • PostgreSQL:pg_stat_statements(慢查詢)、pg_stat_activity(活躍會(huì)話)、pg_stat_bgwriter(緩沖區(qū)寫入)
  • 抓取卡頓時(shí)的快照
-- 活躍會(huì)話與等待事件
SELECT pid, wait_event_type, wait_event, query, state FROM pg_stat_activity WHERE state <> 'idle';

-- 鎖等待
SELECT * FROM pg_locks WHERE granted = false;

-- 檢查點(diǎn)與 bgwriter 統(tǒng)計(jì)
SELECT * FROM pg_stat_bgwriter;
  • 啟用日志診斷
    • log_min_duration_statement = 1000(記錄慢查詢)
    • log_checkpoints = on
    • log_autovacuum_min_duration = 0(記錄所有 autovacuum)
  • 使用專業(yè)工具
    • pgBadger:日志分析
    • pg_top / htop:實(shí)時(shí)進(jìn)程監(jiān)控
    • perf / flamegraph:CPU 火焰圖(需編譯帶符號(hào)的 PostgreSQL)

到此這篇關(guān)于PostgreSQL核心原理之?dāng)?shù)據(jù)庫(kù)偶爾會(huì)卡頓的原因分析的文章就介紹到這了,更多相關(guān)postgresql數(shù)據(jù)庫(kù)卡頓內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • PostgreSQL psql 常用命令總結(jié)

    PostgreSQL psql 常用命令總結(jié)

    psql是PostgreSQL的一個(gè)命令行交互式客戶端工具,它具有非常豐富的功能,類似于Oracle的命令行工具sqlplus,本文給大家總結(jié)下PostgreSQL 中常用 psql 常用命令以便后續(xù)查閱,感興趣的朋友跟隨小編一起看看吧
    2023-07-07
  • PostgreSQL數(shù)據(jù)庫(kù)中窗口函數(shù)的語法與使用

    PostgreSQL數(shù)據(jù)庫(kù)中窗口函數(shù)的語法與使用

    這PostgreSQL中提供了窗口函數(shù),一個(gè)窗口函數(shù)在一系列與當(dāng)前行有某種關(guān)聯(lián)的表行上進(jìn)行一種計(jì)算。下面這篇文章主要給大家介紹了關(guān)于PostgreSQL數(shù)據(jù)庫(kù)中窗口函數(shù)的語法與使用的相關(guān)資料,需要的朋友可以參考下
    2019-03-03
  • Abp.NHibernate連接PostgreSQl數(shù)據(jù)庫(kù)的方法

    Abp.NHibernate連接PostgreSQl數(shù)據(jù)庫(kù)的方法

    這篇文章主要為大家詳細(xì)介紹了Abp.NHibernate連接PostgreSQl數(shù)據(jù)庫(kù)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • PostGresql 實(shí)現(xiàn)四舍五入、小數(shù)轉(zhuǎn)換、百分比的用法說明

    PostGresql 實(shí)現(xiàn)四舍五入、小數(shù)轉(zhuǎn)換、百分比的用法說明

    這篇文章主要介紹了PostGresql 實(shí)現(xiàn)四舍五入、小數(shù)轉(zhuǎn)換、百分比的用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • PostgreSQL表操作之表的創(chuàng)建及表基礎(chǔ)語法總結(jié)

    PostgreSQL表操作之表的創(chuàng)建及表基礎(chǔ)語法總結(jié)

    在PostgreSQL中創(chuàng)建表命令用于在任何給定的數(shù)據(jù)庫(kù)中創(chuàng)建新表,下面這篇文章主要給大家介紹了關(guān)于PostgreSQL表操作之表的創(chuàng)建及表基礎(chǔ)語法的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-05-05
  • PostgreSQL表膨脹問題解析及解決方案

    PostgreSQL表膨脹問題解析及解決方案

    表膨脹是指表的數(shù)據(jù)和索引所占文件系統(tǒng)的空間在有效數(shù)據(jù)量并未發(fā)生大的變化的情況下不斷增大,這種現(xiàn)象會(huì)導(dǎo)致關(guān)系文件被大量空洞填滿,從而浪費(fèi)大量的磁盤空間,本文給大家介紹了PostgreSQL表膨脹問題解析及解決方案,需要的朋友可以參考下
    2024-11-11
  • PostgreSQL修改用戶密碼的多種方式

    PostgreSQL修改用戶密碼的多種方式

    在使用PostgreSQL數(shù)據(jù)庫(kù)時(shí),忘記數(shù)據(jù)庫(kù)密碼可能會(huì)影響到正常的開發(fā)和維護(hù)工作,本文將詳細(xì)給大家介紹了PostgreSQL修改用戶密碼的多種方式,并有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2025-05-05
  • PostgreSQL 修改視圖的操作

    PostgreSQL 修改視圖的操作

    這篇文章主要介紹了PostgreSQL 修改視圖的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • PostgresSql 多表關(guān)聯(lián)刪除語句的操作

    PostgresSql 多表關(guān)聯(lián)刪除語句的操作

    這篇文章主要介紹了PostgresSql 多表關(guān)聯(lián)刪除語句的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • PostgreSQL數(shù)據(jù)類型格式化函數(shù)操作

    PostgreSQL數(shù)據(jù)類型格式化函數(shù)操作

    這篇文章主要介紹了PostgreSQL數(shù)據(jù)類型格式化函數(shù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12

最新評(píng)論

沙湾县| 获嘉县| 韶山市| 大化| 祁门县| 景洪市| 津南区| 兰西县| 峡江县| 万州区| 昭苏县| 绥阳县| 紫金县| 微山县| 郓城县| 全椒县| 杨浦区| 德钦县| 佛冈县| 鹤岗市| 丽江市| 定陶县| 湘潭市| 文水县| 霸州市| 河间市| 麻城市| 赣州市| 临江市| 崇文区| 镇安县| 龙南县| 平罗县| 洞口县| 台东市| 石棉县| 白山市| 布拖县| 台东县| 秦皇岛市| 平江县|