PostgreSQL笔记26:MVCC多版本并发控制机制深度解析

SQL Server锁机制深度解析:从SELECT卡顿到死锁排查 数据库锁是保障事务ACID特性的核心机制,其本质是在并发访问共享资源时实施的协调策略。SQL Server采用分层锁粒度(RID/KEY/PAGE/HOBT/OBJECT)与多类型锁(S/U/X/I/Sch-S)组合,通过动态兼容性判断实现读写隔离。理解锁行为的关键在于掌握锁升级阈值、意向锁作用及隔离级别对锁生命周期的影响。典型应用场景包括报表查询阻塞业务写入、批量导入性能瓶颈、高并发热点更新等,而RCSI行版本控制、TABLOCK提示、索引优化和统计信息维护是主流工程解法。本文聚焦SQL Server中T 阅读详情

纲要

  • Heap Tuple 元组内部结构
    • t_xmin / t_xmax / t_ctid / t_infomask / t_hoff
    • cmin / cmax 与 t_cid 共用体
    • NULL 值位图 (t_bits)
  • MVCC 核心操作
    • INSERT 写入流程
    • DELETE 删除流程
    • UPDATE 更新流程(插入+删除组合)
  • CLOG (Commit Log) 提交日志
    • 事务状态:IN_PROGRESS / COMMITTED / ABORTED / SUB_COMMITTED
    • 事务状态查询:pg_xact_status() / txid_status()
    • CLOG 损坏与修复思路
  • Snapshot 快照机制
    • SnapshotData 结构:xmin / xmax / xip 列表
    • pg_current_snapshot() 查看当前快照
  • 可见性判断规则 (HeapTupleSatisfiesMVCC)
    • 基于 t_xmin 状态的分支判断
    • 基于 t_xmax 的删除判断
    • Hint Bits 优化
  • 事务隔离级别
    • READ COMMITTED:每条语句获取新快照(默认)
    • REPEATABLE READ:事务开始时获取快照
    • SERIALIZABLE:严格可串行化
    • READ UNCOMMITTED:在 PostgreSQL 中等同于 READ COMMITTED
  • VACUUM 与死元组清理
  • postgres_fdw 与 pg_dump 中的隔离级别

元组内部结构

在 PostgreSQL 中,每一条数据行(Heap Tuple)除了存储业务数据外,还在行头部(Tuple Header)中存储了大量元数据,用于实现 MVCC 机制。

// 简化自 src/include/access/htup_details.h
typedef struct HeapTupleHeaderData
{
    union
    {
        HeapTupleFields t_heap;
        DatumTupleFields t_datum;
    } t_choice;

    ItemPointerData t_ctid;     /* 当前元组的物理位置 (块号, 偏移量) */

    /* 以下字段用于 NULL 值位图等 */
    uint16      t_infomask2;    /* 属性数量 + 标志位 */
    uint16      t_infomask;     /* 各种标志位 */
    uint8       t_hoff;         /* 头部长度 */
    /* 后面紧跟着 NULL 位图 (t_bits) 和实际数据 */
} HeapTupleHeaderData;

其中 t_choice.t_heap 结构包含:

typedef struct HeapTupleFields
{
    TransactionId t_xmin;       /* 插入此元组的事务 ID */
    TransactionId t_xmax;       /* 删除/更新此元组的事务 ID,0 表示未删除 */
    union
    {
        CommandId   t_cid;      /* 同一事务内的命令序号 (cmin/cmax) */
        TransactionId t_xvac;   /* VACUUM 操作使用 */
    } t_field3;
} HeapTupleFields;

关键字段说明

字段类型说明
t_xminTransactionId创建(插入)此元组版本的事务 ID
t_xmaxTransactionId删除或更新此元组的事务 ID,0 表示当前版本有效
t_ctidItemPointerData当前元组在表中的物理位置,格式为 (块号, 偏移量)
t_cidCommandId同一事务内语句的序列号,用于同一事务内的可见性判断
t_infomaskuint16标志位,记录元组属性(是否有 NULL、是否有变长列、Hint Bits 等)
t_bits可变长度NULL 值位图,每一位对应一列是否为 NULL

NULL 值存储

PostgreSQL 并不在数据区域中直接存储 NULL 值,而是通过元组头部的 NULL 位图(t_bits)来标识。每个 NULL 位图占用 1 bit,按列顺序排列:

  • 位 = 1:该列为 NULL
  • 位 = 0:该列非 NULL

这种设计使得 NULL 值不占用实际数据存储空间,同时也避免了定长字段因 NULL 导致的存储碎片。

cmin / cmax 与 t_cid 共用体

cmin(插入命令 ID)和 cmax(删除命令 ID)用于同一事务内多个语句之间的可见性判断。在源码实现中,t_cid 是一个共用体(union),在同一事务内:

  • 插入操作时,t_cid 记录的是 cmin
  • 删除/更新操作时,t_cid 记录的是 cmax

由于同一元组在同一个事务中不可能同时被插入和删除(除非在同一事务内更新),因此这两个字段可以共用存储空间。

MVCC 核心操作

INSERT 写入

当执行 INSERT 操作时:

  1. 新元组的 t_xmin 设置为当前事务 ID
  2. t_xmax 保持为 0(无效)
  3. t_ctid 指向自身的物理位置
  4. t_cid 记录当前命令序号(cmin)
-- 示例表
CREATE TABLE test (
    id INT,
    info TEXT
);

-- 开启事务
BEGIN;
SELECT pg_current_xact_id();  -- 假设返回 12345

INSERT INTO test VALUES (1, 'hello');

-- 查看元组头信息(需安装 pageinspect 扩展)
SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask
FROM heap_page_items(get_raw_page('test', 0));
执行结果示意:
 lp | t_xmin | t_xmax | t_ctid | t_infomask
----+--------+--------+--------+------------
  1 |  12345 |      0 | (0,1)  |       ...

DELETE 删除

DELETE 操作并不物理移除数据行,而是在目标元组的 t_xmax 字段中记录删除事务的 ID:

  1. 定位目标元组
  2. 将 t_xmax 设置为当前事务 ID
  3. 更新 t_cid 为当前命令序号(cmax)
  4. 元组变为“死元组”(Dead Tuple),通过可见性规则使其对其他事务不可见
-- 继续上述事务,假设当前事务 ID 为 12345
DELETE FROM test WHERE id = 1;

-- 查看元组状态
SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask
FROM heap_page_items(get_raw_page('test', 0));
执行结果示意:
 lp | t_xmin | t_xmax | t_ctid | t_infomask
----+--------+--------+--------+------------
  1 |  12345 |  12345 | (0,1)  |       ...

UPDATE 更新

UPDATE 在 PostgreSQL 中本质上是 DELETE + INSERT 的组合操作:

  1. 将旧元组的 t_xmax 设置为当前事务 ID(标记为删除)
  2. 将旧元组的 t_ctid 更新为指向新元组的物理位置
  3. 插入新元组,t_xmin 设置为当前事务 ID,t_xmax 设置为 0
  4. 新元组的 t_ctid 指向自身
-- 继续上述事务
UPDATE test SET info = 'world' WHERE id = 1;

-- 查看元组状态
SELECT lp, t_xmin, t_xmax, t_ctid, t_infomask
FROM heap_page_items(get_raw_page('test', 0));
执行结果示意:
 lp | t_xmin | t_xmax | t_ctid | t_infomask
----+--------+--------+--------+------------
  1 |  12345 |  12345 | (0,2)  |  (旧元组,指向新元组)
  2 |  12345 |      0 | (0,2)  |  (新元组)

多次更新同一行会产生多个元组版本,形成一条版本链(Version Chain),通过 t_ctid 字段串联。

CLOG 提交日志

CLOG 概述

CLOG(Commit Log)是 PostgreSQL 中记录事务最终状态的核心系统组件。每个事务的状态占用 2 个 bit,支持四种状态:

状态值说明
IN_PROGRESS00事务正在运行中
COMMITTED01事务已提交
ABORTED02事务已回滚
SUB_COMMITTED03子事务已提交

CLOG 以 8KB 页为单位存储,每个页可存储 8192 × 4 = 32768 个事务状态。当可见性判断需要获取事务状态时,如果 t_infomask 中的 Hint Bits 未设置,系统会从 CLOG 中读取。

查询事务状态

PostgreSQL 提供了 pg_xact_status() 函数(旧版本为 txid_status())用于查询事务状态:

-- 查看当前事务 ID
SELECT pg_current_xact_id();

-- 查询指定事务的状态
SELECT pg_xact_status('12345');

CLOG 损坏与修复

CLOG 文件损坏时,可能会出现类似以下错误:

ERROR:  could not access status of transaction 12345
DETAIL:  Could not open file "pg_xact/0001": No such file or directory

修复思路:在紧急情况下,可以通过手动构造 CLOG 文件来恢复数据库访问。基本方法是通过 dd 命令创建对应大小的空文件,但这种方法仅适用于紧急恢复场景,不推荐在生产环境中使用。建议优先从备份恢复。

快照(Snapshot)机制

快照的概念

快照类似于在某个时刻对数据库状态“拍照”。快照一旦生成,就固定了该时刻的可见事务集合,后续查询基于这个快照判断数据的可见性。

快照数据结构

// 简化自 src/include/utils/snapshot.h
typedef struct SnapshotData
{
    SnapshotSatisfiesFunc satisfies;    /* 可见性判断函数 */
    TransactionId xmin;                 /* 所有 < xmin 的事务均可见 */
    TransactionId xmax;                 /* 所有 >= xmax 的事务均不可见 */
    TransactionId *xip;                 /* 快照时刻正在运行的事务 ID 列表 */
    uint32      xcnt;                   /* 运行中事务数量 */
    /* ... 其他字段 */
} SnapshotData;

快照的可见性规则:

  • xid < xmin:事务已完结,可见(若已提交)
  • xmin <= xid < xmax:需检查 xip 列表
  • xid >= xmax:事务尚未开始,不可见

查看当前快照

-- 查看当前快照
SELECT pg_current_snapshot();

-- 输出示例: 12345:12348:12346,12347
-- 格式: xmin:xmax:xip_list
-- xmin = 12345, xmax = 12348, 运行中事务为 12346, 12347

快照格式说明:

  • xmin:最早仍在运行的事务 ID
  • xmax:第一个尚未分配的事务 ID
  • xip_list:快照时刻正在运行的事务 ID 列表(逗号分隔)

可见性判断规则

核心判断逻辑

PostgreSQL 通过 HeapTupleSatisfiesMVCC() 函数判断元组对给定快照是否可见。其核心逻辑可归纳为:

ABORTED

IN_PROGRESS

是

是

否

否

COMMITTED

IN_PROGRESS

是

是

否

否

COMMITTED

ABORTED

开始判断元组可见性

t_xmin 状态?

不可见

t_xmin == 当前事务?

当前命令 < cmin?

不可见

可见

不可见

t_xmax 状态?

t_xmax == 当前事务?

当前命令 >= cmax?

不可见

可见

可见

不可见

可见

Hint Bits 优化

为了减少频繁访问 CLOG 的开销,PostgreSQL 在 t_infomask 中缓存了事务状态的 Hint Bits:

Hint Bit含义
HEAP_XMIN_COMMITTEDt_xmin 事务已提交
HEAP_XMIN_INVALIDt_xmin 事务已回滚
HEAP_XMAX_COMMITTEDt_xmax 事务已提交
HEAP_XMAX_INVALIDt_xmax 事务未提交或不存在

当 Hint Bits 已设置时,可直接判断而无需访问 CLOG,大幅提升性能。

可见性判断示例

-- 创建测试表
CREATE TABLE t2 (id INT);

-- 事务 A: 插入数据并提交
BEGIN;
INSERT INTO t2 VALUES (10);
COMMIT;

-- 事务 B: 查询可见性
BEGIN;
SELECT * FROM t2;  -- 可见 10

-- 事务 C: 插入数据但不提交
BEGIN;
INSERT INTO t2 VALUES (20);
-- 不提交

-- 事务 D: 查询
BEGIN;
SELECT * FROM t2;  -- 只能看到 10,看不到 20
COMMIT;

事务隔离级别

隔离级别概览

PostgreSQL 支持 SQL 标准中定义的四种隔离级别,但 READ UNCOMMITTED 在实现上等同于 READ COMMITTED:

隔离级别脏读不可重复读幻读快照获取时机
READ UNCOMMITTED不可能可能可能每条语句
READ COMMITTED不可能可能可能每条语句
REPEATABLE READ不可能不可能可能(PG 中通过 SSI 避免)事务开始时
SERIALIZABLE不可能不可能不可能事务开始时

READ COMMITTED(默认)

READ COMMITTED 是 PostgreSQL 的默认隔离级别。在该级别下,每条语句执行时都会获取一个新的快照:

-- 查看当前隔离级别
SHOW default_transaction_isolation;

-- 开启事务(默认 RC)
BEGIN;
SELECT pg_current_snapshot();  -- 快照 A
-- 其他事务插入数据并提交
SELECT pg_current_snapshot();  -- 快照 B(与 A 不同)
COMMIT;

REPEATABLE READ

在 REPEATABLE READ 隔离级别下,事务在开始时获取快照,并在整个事务期间保持不变:

-- 开启 RR 事务
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT pg_current_snapshot();  -- 快照 X
-- 其他事务插入数据并提交
SELECT pg_current_snapshot();  -- 快照 X(不变)
COMMIT;

隔离级别与 MVCC 的关系

  • 不同事务间:通过 t_xmin / t_xmax + CLOG + 快照判断可见性
  • 同一事务内:通过 t_cid(cmin / cmax)判断同一事务内不同语句的可见性
  • 隔离级别:决定快照的获取时机和生命周期

VACUUM 与死元组清理

由于 UPDATE 和 DELETE 并不物理移除数据,死元组会持续占用存储空间。PostgreSQL 通过 VACUUM 机制清理死元组:

-- 手动 VACUUM 指定表
VACUUM test;

-- 手动 VACUUM 并回收空间(会持有更强锁)
VACUUM FULL test;

-- 查看表膨胀情况
SELECT
    schemaname,
    tablename,
    pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS total_size,
    n_dead_tup
FROM pg_stat_user_tables
WHERE n_dead_tup > 0;

VACUUM 的核心工作:

  1. 扫描表中的死元组
  2. 将死元组占用的空间标记为可重用
  3. 更新 pg_stat_user_tables 中的统计信息
  4. 更新 t_infomask 中的 Hint Bits

建议:在生产环境中启用 autovacuum,避免死元组堆积导致表膨胀和性能下降。

API 速览

系统信息函数

pg_current_xact_id()

所属:PostgreSQL 系统函数(PG 13+,旧版为 txid_current())

签名:pg_current_xact_id() → xid8

说明:返回当前事务的事务 ID(64 位扩展事务 ID)

SELECT pg_current_xact_id();
-- 示例输出: 12345
pg_current_snapshot()

所属:PostgreSQL 系统函数(PG 13+)

签名:pg_current_snapshot() → pg_snapshot

说明:返回当前事务的快照,格式为 xmin:xmax:xip_list

SELECT pg_current_snapshot();
-- 示例输出: 12345:12348:12346,12347
pg_xact_status()

所属:PostgreSQL 系统函数(PG 13+,旧版为 txid_status())

签名:pg_xact_status(xid xid8) → text

说明:返回指定事务的状态:in progress、committed、aborted

SELECT pg_xact_status('12345');
-- 示例输出: committed
pg_snapshot_xmin(), pg_snapshot_xmax(), pg_snapshot_xip()

所属:PostgreSQL 系统函数(PG 13+)

签名:

  • pg_snapshot_xmin(snapshot pg_snapshot) → xid8
  • pg_snapshot_xmax(snapshot pg_snapshot) → xid8
  • pg_snapshot_xip(snapshot pg_snapshot) → setof xid8

说明:解析快照的各组成部分

SELECT pg_snapshot_xmin(pg_current_snapshot());
SELECT pg_snapshot_xmax(pg_current_snapshot());
SELECT pg_snapshot_xip(pg_current_snapshot());

pageinspect 扩展

所属:PostgreSQL 贡献扩展(需手动安装)

安装:

CREATE EXTENSION pageinspect;

核心函数:

函数说明
get_raw_page(relname text, blkno int)获取指定块的原始页面数据
heap_page_items(page bytea)解析页面中的元组信息
tuple_data_split(reloid oid, t_data bytea, ...)拆分元组数据
-- 查看表 test 第 0 块的所有元组头部信息
SELECT
    lp,
    t_xmin,
    t_xmax,
    t_ctid,
    t_infomask,
    t_infomask2,
    t_hoff
FROM heap_page_items(get_raw_page('test', 0));

隔离级别相关

SHOW default_transaction_isolation

说明:显示当前会话的默认事务隔离级别

SHOW default_transaction_isolation;
-- 输出: read committed
SET TRANSACTION ISOLATION LEVEL

说明:设置当前事务的隔离级别

BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 执行查询...
COMMIT;
SHOW transaction_isolation

说明:显示当前事务的隔离级别(PG 14+)

SHOW transaction_isolation;

Demo 完整示例

环境准备

# 确保 PostgreSQL 已安装并运行
psql --version
# 创建测试数据库
createdb mvcc_demo
psql -d mvcc_demo

启用 pageinspect 扩展

CREATE EXTENSION IF NOT EXISTS pageinspect;

完整演示脚本

-- ============================================
-- 1. 创建测试表
-- ============================================
DROP TABLE IF EXISTS demo;
CREATE TABLE demo (
    id INT PRIMARY KEY,
    name TEXT,
    age INT
);

-- ============================================
-- 2. 插入数据
-- ============================================
BEGIN;
SELECT pg_current_xact_id() AS txid_insert;  -- 记录事务 ID

INSERT INTO demo VALUES (1, 'Alice', 25);
INSERT INTO demo VALUES (2, 'Bob', 30);

-- 查看元组头信息
SELECT
    lp AS line_pointer,
    t_xmin,
    t_xmax,
    t_ctid,
    t_infomask::bit(16) AS infomask_bits
FROM heap_page_items(get_raw_page('demo', 0));

COMMIT;

-- ============================================
-- 3. 更新数据(产生死元组)
-- ============================================
BEGIN;
SELECT pg_current_xact_id() AS txid_update;

UPDATE demo SET age = 26 WHERE id = 1;

-- 再次查看元组头,观察新旧两个版本
SELECT
    lp,
    t_xmin,
    t_xmax,
    t_ctid,
    t_infomask::bit(16) AS infomask_bits
FROM heap_page_items(get_raw_page('demo', 0));

COMMIT;

-- ============================================
-- 4. 删除数据(产生死元组)
-- ============================================
BEGIN;
SELECT pg_current_xact_id() AS txid_delete;

DELETE FROM demo WHERE id = 2;

SELECT
    lp,
    t_xmin,
    t_xmax,
    t_ctid,
    t_infomask::bit(16) AS infomask_bits
FROM heap_page_items(get_raw_page('demo', 0));

COMMIT;

-- ============================================
-- 5. 查看表膨胀情况
-- ============================================
SELECT
    schemaname,
    tablename,
    n_dead_tup,
    n_live_tup,
    pg_size_pretty(pg_total_relation_size('demo')) AS table_size
FROM pg_stat_user_tables
WHERE tablename = 'demo';

-- ============================================
-- 6. VACUUM 清理死元组
-- ============================================
VACUUM demo;

-- 再次查看死元组数量
SELECT
    schemaname,
    tablename,
    n_dead_tup,
    n_live_tup,
    pg_size_pretty(pg_total_relation_size('demo')) AS table_size
FROM pg_stat_user_tables
WHERE tablename = 'demo';

-- ============================================
-- 7. 查看当前快照
-- ============================================
SELECT
    pg_current_snapshot() AS snapshot,
    pg_snapshot_xmin(pg_current_snapshot()) AS xmin,
    pg_snapshot_xmax(pg_current_snapshot()) AS xmax;

运行说明

  1. 在 psql 或任意 PostgreSQL 客户端中执行上述脚本
  2. 观察每个步骤中 heap_page_items 的输出,理解 t_xmin、t_xmax、t_ctid 的变化
  3. 对比 VACUUM 前后 pg_stat_user_tables 中死元组数量的变化

技术点总结

技术点Demo 中的体现
t_xmin / t_xmaxINSERT 设置 t_xmin,UPDATE/DELETE 设置 t_xmax
t_ctid 版本链UPDATE 后旧元组的 t_ctid 指向新元组
死元组DELETE 后元组仍存在于页面中,t_xmax 被设置
VACUUM清理死元组,回收空间
快照pg_current_snapshot() 查看当前快照
pageinspect直接查看页面级别的元组头信息

项目难点与解决方案

核心难点

可见性判断的复杂性:PostgreSQL 的可见性判断需要综合考虑 t_xmin / t_xmax 的状态、CLOG 中的事务状态、当前快照以及 Hint Bits 的缓存状态,逻辑分支较多,容易出错。

解决方案

  • 理解 HeapTupleSatisfiesMVCC() 的核心判断流程
  • 善用 pageinspect 扩展直接观察页面级数据
  • 通过 pg_xact_status() 验证事务状态
  • 关注 t_infomask 中的 Hint Bits,理解其缓存作用

广度

  • 涉及存储引擎(页面/元组结构)
  • 事务管理(CLOG、事务 ID)
  • 并发控制(快照、隔离级别)
  • 性能优化(VACUUM、Hint Bits)

深度

  • 深入到页面级别的元组头结构
  • 理解 CLOG 的存储格式和状态编码
  • 掌握快照数据结构的完整语义

复杂度

  • MVCC 是 PostgreSQL 最核心的机制之一
  • 可见性判断涉及多个系统组件的协同
  • 隔离级别的差异直接影响快照获取策略
  • CLOG 损坏等异常场景需要深度理解才能恢复

官方文档

官方文档

参考链接

总结

PostgreSQL 的 MVCC 机制通过在每个元组头部存储 t_xmin(创建事务 ID)和 t_xmax(删除/更新事务 ID),结合 CLOG(提交日志)中记录的事务最终状态以及事务快照(Snapshot),实现了高效的多版本并发控制。

UPDATE 和 DELETE 操作产生死元组,需通过 VACUUM 机制定期清理以避免表膨胀。事务隔离级别决定了快照的获取时机——READ COMMITTED 每语句获取新快照,REPEATABLE READ 和 SERIALIZABLE 在事务开始时获取快照。理解这一机制是掌握 PostgreSQL 性能调优和问题诊断的基础。

PostgreSQL三十年:从开源内核到国产数据库的自主创新之路 PostgreSQL(简称PG)已经走过了三十年的发展历程,从学术研究项目成长为当今数据库领域的“全能冠军”。根据2023年StackOverflow开发者调研,PostgreSQL在流行度、喜爱度和需求度三项核心指标上均位列第一,被广泛认为是“数据库界的Linux”。其开源、先进、稳定、可扩展的特性,使其不仅成为全球开发者的首选,更成为了中国数据库产业实现“自主可控”的重要基石。围绕PG衍生出的众多国产数据库产品,究竟是简单的“套壳”,还是真正的“自主”创新?这背后反映了中国数据库产业怎样的发展路径和技术 阅读详情

相关推荐

单服务器部署Plone 4的高性能架构:Varnish+RelStorage实战

在Web内容管理系统(CMS)性能优化中,缓存机制与数据库访问层设计是影响响应速度和并发承载能力的核心。Varnish作为高性能HTTP缓存代理,通过精准的Cache Key控制、URL参数清洗和分层缓存策略,显著降低后端负载;RelStorage则将ZODB对象存储迁移至PostgreSQL,结合Memcached实现多级数据加速,解决传统FileStorage的锁竞争与扩展瓶颈。该方案面向资源受限场景,适用于Plone 4等基于Zope的应用托管,兼顾高可用性、可监控性与工程落地性,为中小规模企业门户、

ama7449的博客 331

重磅预告|HOW2026 会前大师特训!深度吃透 PostgreSQL 内核底层逻辑

本培训将通过源代码引导,带领学员深入探讨 PostgreSQL 的共享缓冲区(Shared Buffers)架构:包括其三层设计、命中/未命中/IO 生命周期,以及"钉(Pins)"、分页面 LWLock 和原子性 BM_* 标志如何协同实现页面级的并发控制。我们将追踪"时钟扫描(Clock-sweep)"算法和"缓冲区环(Buffer Rings)"机制,看它们如何防止大扫描和 VACUUM 操作污染缓存。

IvorySQL的博客 387

MindsDB:用SQL驱动机器学习的数据库原生AI平台

机器学习正从训练密集型范式转向推理与集成优先的新阶段,核心诉求是降低AI应用门槛、缩短业务价值交付周期。SQL作为数据领域最通用、最普及的接口语言,天然具备描述性、声明式和跨团队协作优势;将其与机器学习深度耦合,实质是重构ML工作流的数据层、模型层和服务层抽象——消除ETL割裂、封装模型生命周期、实现预测即查询。这种数据库原生AI架构显著提升结构化数据场景下的实时预测效率与运维可控性,广泛适用于销售预测、风控评分、客户流失预警等BI可集成业务。MindsDB正是这一技术路径的典型代表。

weixin_30700099的博客 433

PostgreSQL MVCC 与 VACUUM 运维实战:死元组回收、autovacuum 调参与 XID 回卷防护(Papermark 项目视角)

本文以 PostgreSQL 官方技能文档《[MVCC and VACUUM](https://link.gitcode.com/i/1fb5e7ffd2a08f90170423eb2e0ece4c)》为骨架,系统讲解 MVCC 下死元组(dead tuples)的产生与回收机制、`VACUUM` 与 `VACUUM FULL` 的取舍、autovacuum 触发公式与调参策略,以及围绕 XID

gitblog_00756的博客 185

网易校招系统运维笔试复盘:Linux基础与生产环境搭建全解析

系统运维是保障生产环境稳定运行的核心环节,其职责覆盖Linux进程管理、网络协议栈、数据库优化、自动化脚本编写到监控告警体系构建。在此基础上,围绕“互联网运维”与“国企运维”的差异,以及“数字孪生”在智能运维中的应用,考察的是工程师对完整运维链路和架构设计逻辑的理解。通过从零搭建生产环境的思路,可以串联起需求分析、组件选型、CI/CD流水线、监控容灾等关键能力。掌握这些基础原理和工程实践,对于应对大厂校招笔试以及实际工作都具有重要价值。本文基于网易2023校招系统运维工程师笔试,拆解高频考点、答题框架与时间

weixin_34258838的博客 444

【Java生产级避坑指南】15. 事务隔离级别幻读实锤:PostgreSQL与MySQL差异化防御实战(含完整实验+代码)

幻读是事务隔离级别中经典的数据一致性问题,指同一事务内两次相同查询返回不同结果(新增“幻影”行)。MySQL与PostgreSQL作为主流开源数据库,对幻读的防御机制存在本质差异:MySQL(InnoDB)在可重复读级别通过间隙锁+临键锁实现防御,需显式锁定读;PostgreSQL基于MVCC快照隔离,可重复读级别天然避免幻读,高并发场景更友好。本文通过电商库存统计的真实场景,从零复现两大数据库的幻读现象,详解底层原理(间隙锁、MVCC),提供可直接落地的防御方案(含SQL代码、应用层重试逻辑),并结合业务

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 332

HOW2026 盛会预告|顶级培训+专家智库齐聚,限量好礼等你来!

本培训将通过源代码引导,带领学员深入探讨 PostgreSQL 的共享缓冲区(Shared Buffers)架构:包括其三层设计、命中/未命中/IO 生命周期,以及"钉(Pins)"、分页面 LWLock 和原子性 BM_* 标志如何协同实现页面级的并发控制。我们将追踪"时钟扫描(Clock-sweep)"算法和"缓冲区环(Buffer Rings)"机制,看它们如何防止大扫描和 VACUUM 操作污染缓存。

IvorySQL的博客 352

小企业可用的OpenCV人脸考勤系统实战方案

人脸考勤系统是企业数字化管理的基础技术应用,其核心在于将人脸识别从算法概念转化为稳定、低维护、适配真实办公环境的工程落地。原理上依赖OpenCV等轻量级视觉库实现CPU端高效检测与识别,技术价值体现在规避深度学习部署门槛、兼容老旧硬件、支持中文姓名与复杂光照场景;典型应用场景覆盖20人规模广告、设计、咨询类中小企业,尤其适用于无专职IT人员、预算有限、需快速上线的考勤数字化需求。本文聚焦Python+OpenCV+PostgreSQL技术栈,详解Haar级联调优、LBPH模型训练、多帧防伪验证及零前端管理员

weixin_34072458的博客 401

SQL事务隔离级别如何选择?:90%开发者忽略的脏读、幻读、不可重复读解决方案

掌握SQL事务隔离级别详解,轻松解决脏读、幻读、不可重复读难题。涵盖四大隔离级别的适用场景与性能权衡,提供企业级数据库一致性保障方案。开发必看,值得收藏

AlgoPerch的博客 918

LNA设计学习心得记录----MOS管的选取

LNA设计学习心得---MOS管的选取仿真

weixin_40359668的博客 6132

RT-Thread NANO V4.1.1 在Cortex-M0上移植踩坑记:解决内存分配宏导致的线程创建失败

本文详细记录了RT-Thread NANO V4.1.1在Cortex-M0平台移植过程中遇到的内存分配宏配置问题,导致线程创建失败的解决方案。通过分析内存管理算法宏定义,将RT_USING_SMALL_MEM替换为RT_USING_SMALL_MEM_AS_HEAP,成功解决了线程创建问题,为开发者提供了实用的移植经验。

weixin_29189373的博客 307

Jev 聊天助手完整指南:Android 对话副驾如何读懂聊天、给出 3 条候选回复并安全回填

晚上十点,工作群跳出条消息:「周五前能不能把方案发我?」——回快了吧,显得没谱;回慢了吧,又怕是漏了正事。这种「看懂了字面、拿不准该接什么话」的时刻,正是 [Jev 聊天助手](https://link.gitcode.com/i/77de21e647ba057da003dc83b9841e38)(jev-chat-jarvis)要解决的场景。它是装在 Android 手机上的对话副驾:先在后台读

gitblog_00224的博客 314

手把手教你用Proteus仿真51单片机抢答器:倒计时+蜂鸣器报警完整项目

本文详细介绍了使用Proteus软件仿真51单片机智能抢答器的完整项目流程。通过系统架构设计、核心元件选型(如74LS30用于按键中断编码),结合状态机编程,实现了带可调倒计时、数码管显示和蜂鸣器报警的八路抢答器功能。项目涵盖了从原理图绘制到代码调试的全过程,是学习嵌入式系统开发的绝佳实践。

tcp8optimizer的博客 264

数据库、操作系统、计算机网络核心课程高效复习指南与实战解析

数据库系统、操作系统和计算机网络是计算机科学领域的三大核心基础课程,共同构成了软件工程师的底层能力基石。数据库系统聚焦于数据的存储、管理与高效访问,其核心原理如事务的ACID特性、索引优化与并发控制,是构建可靠数据服务的根本。操作系统作为硬件与应用间的桥梁,通过进程调度、内存管理和文件系统等机制,实现对计算资源的有效抽象与管理,其虚拟内存、进程同步等概念深刻影响着程序性能。计算机网络则定义了数据如何在网络中进行寻址、路由与可靠传输,TCP/IP协议栈的分层模型与关键协议(如TCP三次握手、HTTP)是互联网

weixin_33834137的博客 348

【银河麒麟V10】【桌面】【服务器】系统启动问题

1、如果之前运行好好的,重启后系统报错,一般80%是因为fstab的问题,回想下之前有没有添加过外接存储,修改过/etc/fstab,如果是的话一般是因为存储异常(比如网络存储无法连接,本地存储路径变化)导致系统开机自检失败,导致无法正常启动; 处理方式:进入单用户(单用户进入的几种方式上面有专门文章介绍),修改/etc/fstab,将新增的内容暂时注释掉,然后重启系统,能正常进入系统后再分析失败原因。 ...

桂安俊@KylinOS 3万+

使用PyTorch和TextCNN实现英文长文本诗歌文本分类

在这个过程中,我们了解了如何进行文本数据预处理、构建TextCNN模型,并进行训练与评估。首先,我们需要将文本文件加载到内存中,并将每个诗歌作为一个样本。然后,我们需要将每个样本转换为数字表示,这可以通过将词汇表中的每个词语映射到一个唯一的整数来实现。此外,我们还需要将每个样本的长度统一为固定值,以便于模型输入。通过这个示例,我们可以学习如何构建一个简单但有效的文本分类模型,并在具体的应用场景中进行训练和预测。该模型通过使用多个不同尺寸的卷积核来捕捉文本中的不同长度的信息,并通过最大池化操作提取关键特征。

loop_syntax648的博客 254

MySQL实战指南:从零搭建到索引、事务与性能优化全解析

你是不是也遇到过这样的场景:想学数据库,打开教程,满屏都是“数据库是数据的仓库”、“SQL是结构化查询语言”这样的概念解释,跟着操作几步就卡在环境配置上,好不容易装好了,写个简单查询都报错,最后只能放弃? 或者,你已经工作一两年,日常CRUD没问题,但一遇到复杂查询、性能优化、事务隔离这些稍微深入的问题就心里没底,只能靠搜索引擎和“祖传代码”勉强应付? 如果你有这些困扰,那么这篇文章就是为你准备的。这不是一篇泛泛而谈的“概念大全”,而是一份 从零环境搭建到核心原理实战的完整路径图 。我将以MySQL为例,但

weixin_30781107的博客 324

企业级OpenClaw部署实战:10个关键配置让你从“养虾“到“精通“

OpenClaw(社区昵称"小龙虾")作为2026年开源社区最活跃的AI Agent项目,凭借其多Agent协同架构和企业级安全隔离能力,已成为中大型企业的首选AI基础设施。本文基于真实企业部署经验,系统梳理了企业级OpenClaw部署的10个关键配置:用户ID消息隔离、群组ID消息隔离、多机器人配置、无限量Agent创建、机器人与Agent关联、Agent间调度、权限配置、Hooks任务、多模型切换及一键备份迁移。

program哲学 931

MySQL从入门到精通:实战指南与性能优化全解析

如果你正在学习后端开发、数据分析,或者任何需要存储数据的应用,那么你大概率绕不开一个名字:MySQL。它几乎是所有技术栈的标配,从个人博客到千万级用户的互联网产品,背后都有它的身影。然而,很多初学者在接触MySQL时,会陷入一个误区:以为会写几句 SELECT * FROM users 就是掌握了数据库。结果在实际项目中,面对性能瓶颈、数据不一致、安全漏洞时,往往束手无策。 这篇文章要解决的,正是这个核心痛点: 如何从“会用”MySQL,到真正“精通”MySQL,建立起一套从安装部署到高级优化的完整知识体系

weixin_34117211的博客 631

【思考模型框架】MECE原则,确保分析时,考虑到的所有因素,既不重叠又无遗漏

MECE原则,是Mutually Exclusive and Collectively Exhaustive的缩写,中文译为“相互独立、完全穷尽”。MECE原则,这是一种逻辑思维和组织信息的方法,旨在确保分析时既没有遗漏也没有重复。MECE原则,相互独立、完全穷尽(Mutually Exclusive,Collectively Exhaustive)的原则MECE原则,确保分析时考虑到的所有因素既不重叠又无遗漏。

奶爸的编程之路,也就一周冷个三天 2756

基于 MATLAB 的 FastICA 算法实现语音信号盲分离

FastICA 算法通过最大化信号的非高斯性,找到独立成分,从而实现信号的分离。这些混合的信号被称为盲源信号,我们希望通过分析混合信号,将它们分离出来以便进行进一步的处理和分析。FastICA 是一种常用的盲源信号分离算法,它基于统计学原理,通过寻找独立成分来实现信号的分离。FastICA(独立成分分析)是一种常用的盲源信号分离算法,在语音和图像处理领域都有广泛的应用。本文将介绍如何使用 MATLAB 实现 FastICA 算法来实现语音信号的盲分离,并提供相应的源代码。FastICA 算法原理。

学习使你进步。 2025

Airflow 2.3 深度解析:事件驱动调度与企业级权限升级

Apache Airflow 作为主流工作流编排引擎,其调度稳定性、元数据可观测性与细粒度权限控制是中大型数据平台的核心诉求。传统轮询式调度在 DAG 规模超 200 后易引发数据库锁争用与任务延迟飙升;而 RBAC 权限长期停留在角色级开关,难以满足金融、医疗等场景的字段级审计要求。Airflow 2.3 通过 Redis Pub/Sub 事件总线实现调度范式升级,将任务启动 P95 延迟从 8.2s 降至 1.4s;同时依托 FAB 增强策略引擎,支持基于标签、字段和用户属性的动态权限判定。结合 DAG

weixin_34192816的博客 379

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

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

25万+字干货|Java面试85题图解版:43道高频真题速查手册(八股+源码双吃透)

本文为25万字超全干货的Java面试85题图解完整版手册,精选43道大厂高频面试真题,摒弃传统死记硬背八股文模式,采用三句标准答案、生活化场景比喻、核心结构图解的方式,通俗讲解Java基础、并发、JVM、数据库、框架等核心考点。每道题目配套实战避坑指南、面试官高频追问与源码解析,实现八股背诵与底层源码双向吃透,适合校招、社招程序员考前速刷、长期复盘,轻松攻克Java面试重难点。

折哥|智能物流与Java实战,副高数据库工程师。深耕出版社物流WMS/OMS(线体/立库/VGA),也分享Java进阶与OMS电商对接。Oracle→PG实战派。相信沉淀可迁移能力,分享通用技术,不藏不虚。 796

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

【随时删】实战型的数据库学习宝地!

终于找到学PostgreSQL的宝藏地方了......

陈泽钦的博客 458

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

TimescaleDB time_bucket_gapfill报错原因与License解决方案

time_bucket_gapfill 是 TimescaleDB 提供的关键时序补全函数,用于解决传感器数据断连导致的时间点缺失问题。其底层原理依赖 PostgreSQL 扩展的运行时功能门控机制,自 2.10 版本起被纳入 Timescale License 管控,不再属于社区版默认能力。该设计体现了现代开源数据库‘核心开源 + 商业增值’的双轨演进趋势,技术价值在于将时间序列补全深度内化为查询引擎原生操作,显著优于应用层或纯 SQL 模拟方案。典型应用场景包括 IoT 监控、金融行情填充、工业时序分析

weixin_33755557的博客 356

《2026全新 | Java 100 天进阶之路:从零基础到上岗就业,108篇完整学习地图》

摘要:不背八股文,不堆概念。44篇基础 + 64篇进阶(共108篇),100天助你达到Java就业水平,从容面对技术面试。 👉 零基础入门 / 校招社招突击 / 1-3年Java后端提升 / 想系统复盘全栈知识的开发者。

折哥|智能物流与Java实战,副高数据库工程师。深耕出版社物流WMS/OMS(线体/立库/VGA),也分享Java进阶与OMS电商对接。Oracle→PG实战派。相信沉淀可迁移能力,分享通用技术,不藏不虚。 1万+
上一篇: PostgreSQL笔记25:数据写入与读取流程及IO模型演进
下一篇: PostgreSQL笔记27: 双缓存架构下的内存管理与性能观测实践
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值