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

PostgreSQL核心原理之數(shù)據(jù)庫偶爾會卡頓的原因分析

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

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

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

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

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

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

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

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

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

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

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

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

二、“偶爾卡頓”的典型場景與核心原因

2.1 檢查點(Checkpoint)風暴

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

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

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

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

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

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

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

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

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

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

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

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

優(yōu)化建議

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

2.3 事務(wù) ID 回卷(Transaction ID Wraparound)風險

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

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

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

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

優(yōu)化建議:

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

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

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

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

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

即使該事務(wù)不做任何修改,也會阻礙系統(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)化建議

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

2.5 鎖競爭與死鎖

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

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

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

若鎖持有時間過長,或鎖順序不一致,會導致連鎖等待甚至死鎖。

排查工具

-- 查看鎖等待
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í)行耗時操作(如網(wǎng)絡(luò)調(diào)用)
  • 統(tǒng)一訪問順序,避免死鎖

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

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

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

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

會導致 WAL 文件堆積,甚至觸發(fā) max_wal_size 限制,迫使檢查點提前,加劇 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)存爭用(LWLock 等待)

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

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

典型案例

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

優(yōu)化建議

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

2.8 查詢計劃突變(Plan Regression)

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

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

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

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

優(yōu)化建議

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

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

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

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

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

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

相關(guān)文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    PostgreSQL 修改視圖的操作

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

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

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

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

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

最新評論

英吉沙县| 治多县| 安达市| 顺义区| 阿荣旗| 南京市| 彩票| 神农架林区| 新和县| 宜宾市| 岱山县| 水城县| 长岭县| 贞丰县| 绥中县| 安陆市| 阿克| 将乐县| 九龙城区| 鹰潭市| 青川县| 景宁| 平邑县| 剑川县| 黔西| 星子县| 嘉禾县| 周至县| 永定县| 蕲春县| 林甸县| 沅江市| 长沙市| 扬州市| 大悟县| 通辽市| 乌拉特前旗| 广德县| 龙江县| 靖安县| 尼玛县|