PostgreSQL笔记21: 文件系统、Buffer I/O与数据页底层结构解析

PostgreSQL insert 偶发变慢的原因分析 —— 从缓存击穿到系统 I/O 这些 SQL 操作并非批量导入(如 COPY),也不是长事务,而是普通的行级插入,主要涉及订单、账户、日志等高频表。在一次生产环境性能监控中,我们发现数据库中部分 INSERT 操作持续变慢,延迟从毫秒级飙升到秒级,触发告警。驻留率(cached ratio)低于 5%,即大多数页不在 shared_buffers 中。pg_stat_activity 显示 insert 查询运行时间较长,无锁等待。42_pg_buffercache_hot.txt —— 缓冲池中热点表命中率; 阅读详情

纲要

  • PostgreSQL 文件系统基础
    • 不支持裸设备(Raw Device)
    • 支持的文件系统类型:XFS、EXT3、EXT4、ZFS
  • I/O 模型:Buffer I/O 与 Direct I/O
    • Buffer I/O(缓冲I/O):数据必经 OS Page Cache
    • Direct I/O(直接I/O):绕过 OS Page Cache
    • Double Buffering(双缓存)问题
    • PostgreSQL 各版本的 I/O 演进:debug_io_direct(v16)、ReadStream(v17)、AIO + io_method(v18)
  • 数据页(Data Page)结构
    • 默认页大小:8KB
    • 页布局:PageHeaderData(24字节)→ ItemIdData(行指针数组)→ Free Space → Items(元组数据)→ Special Space
    • 页头关键字段:pd_lower、pd_upper、pd_special、pd_pagesize_version
  • 元组(Tuple)结构
    • HeapTupleHeaderData:t_xmin、t_xmax、t_ctid、t_infomask、t_infomask2、t_hoff
    • MVCC 可见性判断依赖 t_xmin / t_xmax
    • t_ctid:元组的物理位置标识,索引扫描的核心依据
    • t_infomask:元组属性标志位
  • 数据页大小对性能的影响
    • OLTP 场景:小数据页(如 4KB)更优
    • OLAP 场景:大数据页(如 16KB、32KB)更优
  • 底层观测工具:pageinspect 扩展

PostgreSQL 文件系统基础

PostgreSQL 不支持裸设备(Raw Device) ,所有数据必须运行于具体的文件系统之上。这一设计决策意味着 PostgreSQL 依赖底层文件系统来管理数据的物理存储。常见的文件系统包括 XFS、EXT3、EXT4、ZFS 等,不同文件系统在批量加载、初始化耗时等场景下各有优劣。

由于 PostgreSQL 运行于文件系统之上,其 I/O 路径必然经过操作系统层面的文件系统缓存(OS Page Cache)。这是理解 PostgreSQL I/O 模型的核心前提。

Buffer I/O 与 Direct I/O

Buffer I/O(缓冲I/O)

PostgreSQL 当前(截至 v17)默认采用 Buffer I/O 模型。当数据库需要读取数据块时,I/O 路径如下:

缓存命中

缓存未命中

缓存命中

缓存未命中

PostgreSQL 共享内存
shared_buffers

直接返回数据

OS Page Cache

返回数据并缓存至 shared_buffers

磁盘 Data Files

数据载入 OS Page Cache

这一模型意味着数据块可能同时存在于 PostgreSQL 的 shared_buffers 和 操作系统的 Page Cache 中。这种现象被称为 Double Buffering(双缓存) 。

双缓存带来的问题包括:

  • 内存浪费:同一份数据在内存中存储两份副本
  • 缓存管理复杂:操作系统刷脏页(Dirty Page)时可能影响数据库性能
  • 内存压力下的不确定性:操作系统内存回收机制可能影响数据库缓存命中率

Direct I/O(直接I/O)

与 Buffer I/O 相对的是 Direct I/O,数据读写绕过 OS Page Cache,直接与存储设备交互。

缓存命中

缓存未命中

PostgreSQL 共享内存
shared_buffers

直接返回数据

磁盘 Data Files

数据直接载入 shared_buffers
绕过 OS Page Cache

Direct I/O 的优势在于消除双缓存,使内存管理更加高效。但 PostgreSQL 长期以来未采用 Direct I/O,主要原因是 OS Page Cache 在某些场景下提供了额外的保护层——例如数据库重启后,数据仍可能从 OS Page Cache 中快速读取,避免昂贵的磁盘 I/O。

PostgreSQL I/O 模型的演进

PostgreSQL 社区一直在 I/O 模型上进行持续迭代:

版本I/O 相关特性说明
v16debug_io_direct实验性 Direct I/O 支持,仅限开发测试
v17ReadStream、向量化 I/O内部 API 重构,为 AIO 铺路
v18AIO + io_method异步 I/O 子系统,支持 io_uring

在 v16 中引入的 debug_io_direct 参数是一个开发者导向的实验性功能,其名称中的 debug_ 前缀意在警示用户不应在生产环境启用。该参数可设置为 wal、data 等值,分别控制 WAL 和数据文件的 Direct I/O 行为。

v17 引入的 ReadStream 框架实现了顺序扫描和 ANALYZE 的流式读取,属于内部 API 层面的重构。

v18 正式引入了异步 I/O(AIO)子系统,通过 io_method 参数控制:

  • worker:使用后台工作进程执行异步 I/O(默认)
  • io_uring:使用 Linux io_uring 接口
  • sync:同步 I/O(v18 之前的行为)

AIO 在 v18 中支持顺序扫描、位图堆扫描和 VACUUM 操作。当 AIO 与 Direct I/O 结合使用时,PostgreSQL 可直接与存储接口交互,充分发挥硬件传输能力。

数据页(Data Page)结构

页大小

PostgreSQL 默认数据页大小为 8KB,该值在编译时确定。编译时可选的页大小包括 1KB、2KB、4KB、8KB、16KB、32KB。

页布局

每个数据页包含五个部分:

组成部分说明
PageHeaderData页头,24 字节,包含页的通用信息
ItemIdData行指针(Line Pointer)数组,每个 4 字节,指向实际元组
Free Space未分配的空闲空间
Items实际元组(Tuple)数据
Special Space索引访问方法专用空间,普通表为空

数据页的布局示意图:

PageHeaderData (24 bytes)

ItemIdData (Line Pointers)

Free Space (未分配空间)

Items (Tuple Data)

Special Space

关键设计:行指针从页头向后增长,元组数据从页尾向前增长。空闲空间位于两者之间。这种设计使得插入新元组时无需移动已有数据,只需在页头追加行指针、在页尾追加元组数据即可。

页头(PageHeaderData)

页头结构定义在 src/include/storage/bufpage.h 中,关键字段如下:

字段类型说明
pd_lsnPageXLogRecPtr该页最近一次 WAL 记录的 LSN
pd_checksumuint16页校验和(若启用数据校验)
pd_flagsuint16标志位
pd_lowerLocationIndex空闲空间起始偏移量
pd_upperLocationIndex空闲空间结束偏移量
pd_specialLocationIndexSpecial Space 起始偏移量
pd_pagesize_versionuint16页大小和版本号
pd_prune_xidTransactionId最旧未清理的 XMAX

通过 pageinspect 扩展的 page_header() 函数可查看页头信息:

-- 创建测试表
CREATE TABLE test_page (id int, name text);

-- 插入测试数据
INSERT INTO test_page VALUES (1, 'hello'), (2, 'world');

-- 查看第 0 号数据页的页头
SELECT * FROM page_header(get_raw_page('test_page', 0));

行指针(ItemIdData)

每个行指针占 4 字节,包含元组的偏移量(offset)和长度(length)。行指针从页头区域向后分配,每个新插入的元组对应一个新的行指针。

元组(Tuple)结构

元组头(HeapTupleHeaderData)

每一行数据(元组)在页内存储时,前面附带一个元组头。元组头定义在 src/include/access/htup_details.h 中,关键字段包括:

字段类型说明
t_xminTransactionId插入该元组的事务 ID
t_xmaxTransactionId删除/更新该元组的事务 ID
t_ctidItemPointerData当前元组或新版本元组的物理位置
t_infomaskuint16元组属性标志位
t_infomask2uint16扩展标志位和属性数量
t_hoffuint8元组头长度(含可能的空值位图等)

元组头通常占用 23 字节(多数架构上),之后是可选的空值位图(Null Bitmap)、可选的 OID 字段,最后是实际用户数据。

关键字段详解

t_xmin 与 t_xmax:PostgreSQL 的 MVCC 机制依赖这两个字段判断事务可见性。插入时设置 t_xmin 为当前事务 ID;删除或更新时,旧元组的 t_xmax 设置为当前事务 ID,同时插入新版本元组。

t_ctid:元组的物理位置标识符,格式为 (block_number, item_index)。例如 (0,1) 表示第 0 个数据页的第 1 个行指针。索引中存储的就是索引键值加对应的 t_ctid,索引扫描时通过 t_ctid 直接定位到数据页中的具体元组。

t_infomask:包含 16 种状态标志位,用于标识元组的各种属性。例如:

  • 是否有空值字段
  • 是否包含变长字段
  • t_xmin 是否已提交/中止
  • t_xmax 是否已提交/中止

通过 pageinspect 观测元组

-- 查看堆页中的所有行指针和元组信息
SELECT lp, lp_off, lp_len, t_xmin, t_xmax, t_ctid, t_infomask, t_infomask2
FROM heap_page_items(get_raw_page('test_page', 0));

heap_page_items() 返回每一行的行指针信息(lp、lp_off、lp_len)和元组头信息(t_xmin、t_xmax、t_ctid、t_infomask 等)。

t_infomask 的二进制位可通过 pageinspect 的辅助函数解码:

-- 解码 infomask 标志位(需 PostgreSQL 17+)
SELECT t_infomask, t_infomask2,
       pg_catalog.pg_decode_tuple_infomask(t_infomask) AS infomask_decoded
FROM heap_page_items(get_raw_page('test_page', 0));

数据页大小与性能

PostgreSQL 数据页大小(BLCKSZ)在编译时设定,默认 8KB。不同工作负载下,不同的页大小表现各异:

工作负载类型推荐页大小原因
OLTP(交易型,频繁增删改查)较小(4KB、8KB)减少单次 I/O 的写放大,随机读写更高效
OLAP(批量加载、大查询)较大(16KB、32KB)减少系统调用开销,顺序扫描吞吐量更高

注意:页大小在编译时确定,无法通过配置文件动态调整。生产环境中更换页大小需要重新编译 PostgreSQL。

pageinspect 扩展

pageinspect 是 PostgreSQL 官方提供的扩展,用于底层数据页的低级别检查。仅限超级用户使用。

启用扩展

CREATE EXTENSION pageinspect;

核心函数

函数说明
get_raw_page(relname text, blkno bigint)读取指定表的主分支数据页
get_raw_page(relname text, fork text, blkno bigint)读取指定分支(main/fsm/vm)的数据页
page_header(page bytea)显示页头信息
page_checksum(page bytea, blkno bigint)计算页校验和
heap_page_items(page bytea)显示堆页的所有行指针和元组
fsm_page_contents(page bytea)显示 FSM 页的内部结构

综合示例

-- 1. 创建测试环境
CREATE EXTENSION IF NOT EXISTS pageinspect;

DROP TABLE IF EXISTS page_demo;
CREATE TABLE page_demo (
    id serial PRIMARY KEY,
    data text
);

-- 2. 插入数据
INSERT INTO page_demo (data) 
SELECT 'row_' || generate_series 
FROM generate_series(1, 100);

-- 3. 查看页头
SELECT * FROM page_header(get_raw_page('page_demo', 0));

-- 4. 查看行指针和元组(仅显示前5行)
SELECT lp, lp_off, lp_len, t_xmin, t_xmax, t_ctid, t_infomask
FROM heap_page_items(get_raw_page('page_demo', 0))
LIMIT 5;

-- 5. 查看页大小(编译时确定)
SHOW block_size;

核心技术总结

  1. PostgreSQL 依赖文件系统:不支持裸设备,所有数据读写必经 OS Page Cache(Buffer I/O 模型)。
  2. 双缓存是当前的主要限制:数据同时存在于 shared_buffers 和 OS Page Cache,造成内存浪费和运维复杂性。
  3. I/O 模型持续演进:v16 引入实验性 debug_io_direct,v17 引入 ReadStream 框架,v18 正式引入 AIO 子系统(io_method)。Direct I/O + AIO 是未来的方向。
  4. 数据页是存储的基本单元:默认 8KB,包含页头、行指针、空闲空间、元组数据和特殊空间。行指针从前向后增长,元组从后向前增长。
  5. 元组头承载 MVCC 核心信息:t_xmin/t_xmax 决定可见性,t_ctid 是物理定位的关键,t_infomask 标识元组属性。
  6. 页大小影响性能:OLTP 场景适合小页,OLAP 场景适合大页。页大小在编译时确定,不可动态调整。
  7. pageinspect 是底层观测利器:提供 get_raw_page()、page_header()、heap_page_items() 等函数,用于调试和理解底层存储结构。

API 速览

pageinspect 扩展 API

所属库:pageinspect(PostgreSQL 官方贡献扩展)

get_raw_page(relname text, blkno bigint) RETURNS bytea

  • 读取指定表主分支(main fork)的原始数据页
  • 参数:relname — 表名;blkno — 页号(从 0 开始)
  • 返回:bytea 类型的原始页数据

get_raw_page(relname text, fork text, blkno bigint) RETURNS bytea

  • 读取指定分支的数据页
  • 参数:fork — 'main'(主数据)、'fsm'(空闲空间映射)、'vm'(可见性映射)、'init'(初始化分支)

page_header(page bytea) RETURNS record

  • 解析页头信息,返回 lsn、checksum、flags、lower、upper、special、pagesize、version、prune_xid

heap_page_items(page bytea) RETURNS SETOF record

  • 解析堆页的所有行指针和元组,返回 lp、lp_off、lp_flags、lp_len、t_xmin、t_xmax、t_ctid、t_infomask 等字段

Demo 简单示例

以下是一个完整的 Node.js 示例,演示如何通过 pageinspect 扩展观测 PostgreSQL 数据页的底层结构。

运行说明

环境要求:

  • Node.js 18+
  • PostgreSQL 14+(已安装 pageinspect 扩展)
  • npm 包:pg

启动步骤:

# 1. 初始化项目
mkdir pg-pageinspect-demo && cd pg-pageinspect-demo
npm init -y
npm install pg

# 2. 创建 demo.js 文件(代码见下文)

# 3. 运行
node demo.js

代码说明

const { Client } = require('pg');

// PostgreSQL 连接配置
const client = new Client({
    host: 'localhost',
    port: 5432,
    database: 'postgres',
    user: 'postgres',
    password: 'your_password'
});

async function runDemo() {
    await client.connect();
    console.log('✅ 已连接 PostgreSQL\n');

    try {
        // 1. 创建 pageinspect 扩展(如未安装)
        await client.query('CREATE EXTENSION IF NOT EXISTS pageinspect;');
        console.log('✅ pageinspect 扩展已就绪\n');

        // 2. 创建测试表
        await client.query(`
            DROP TABLE IF EXISTS page_demo;
            CREATE TABLE page_demo (
                id serial PRIMARY KEY,
                data text
            );
        `);
        console.log('✅ 测试表 page_demo 已创建\n');

        // 3. 插入 50 行数据(确保跨多个数据页)
        await client.query(`
            INSERT INTO page_demo (data)
            SELECT 'row_' || generate_series
            FROM generate_series(1, 50);
        `);
        console.log('✅ 已插入 50 行测试数据\n');

        // 4. 查询数据页数量
        const pageCountResult = await client.query(`
            SELECT relpages 
            FROM pg_class 
            WHERE relname = 'page_demo';
        `);
        const pageCount = parseInt(pageCountResult.rows[0].relpages);
        console.log(`📊 page_demo 表占用 ${pageCount} 个数据页\n`);

        // 5. 遍历所有数据页,查看页头信息
        console.log('--- 页头信息 ---');
        for (let blkno = 0; blkno < pageCount; blkno++) {
            const result = await client.query(`
                SELECT lsn, checksum, flags, lower, upper, special, pagesize, version
                FROM page_header(get_raw_page('page_demo', ${blkno}));
            `);
            const row = result.rows[0];
            console.log(`Block ${blkno}: lower=${row.lower}, upper=${row.upper}, ` +
                       `special=${row.special}, pagesize=${row.pagesize}, version=${row.version}`);
        }

        // 6. 查看第 0 页的行指针和元组(前 5 行)
        console.log('\n--- 第 0 页的行指针与元组(前5行) ---');
        const itemsResult = await client.query(`
            SELECT lp, lp_off, lp_len, t_xmin, t_xmax, t_ctid, t_infomask
            FROM heap_page_items(get_raw_page('page_demo', 0))
            LIMIT 5;
        `);
        console.table(itemsResult.rows);

        // 7. 查看当前 block_size
        const blockSizeResult = await client.query(`SHOW block_size;`);
        console.log(`\n📌 当前 block_size: ${blockSizeResult.rows[0].block_size}`);

    } catch (err) {
        console.error('❌ 错误:', err.message);
    } finally {
        await client.end();
        console.log('\n👋 连接已关闭');
    }
}

runDemo();

PostgreSQL 原生指令对照:

-- 等价的原生 SQL 操作
CREATE EXTENSION pageinspect;

-- 查看页头
SELECT * FROM page_header(get_raw_page('page_demo', 0));

-- 查看行指针与元组
SELECT lp, lp_off, lp_len, t_xmin, t_xmax, t_ctid, t_infomask
FROM heap_page_items(get_raw_page('page_demo', 0));

-- 查看 block_size
SHOW block_size;

技术点总结

  • pageinspect 扩展的安装与使用
  • get_raw_page() 读取原始数据页
  • page_header() 解析页头结构
  • heap_page_items() 解析行指针与元组头
  • 通过 pg_class.relpages 获取表的页数
  • 理解 pd_lower/pd_upper 与空闲空间的关系

官方文档

参考链接

总结

本文系统梳理了 PostgreSQL 存储层的三大核心主题:文件系统与 I/O 模型、数据页结构和元组结构。PostgreSQL 当前(v17)采用 Buffer I/O 模型,存在双缓存问题;v16 起引入实验性 Direct I/O 支持,v18 正式推出 AIO 子系统,标志着 I/O 模型的重大演进。

数据页(默认 8KB)由页头、行指针、空闲空间、元组和特殊空间组成,行指针与元组从两端向中间增长。元组头中的 t_xmin/t_xmax 支撑 MVCC,t_ctid 是索引扫描的物理定位依据。pageinspect 扩展是观测底层存储结构的官方工具。理解这些底层原理,是做好 PostgreSQL 性能调优和运维的基础。

Java I/O流核心原理与性能优化实战 I/O流是计算机系统中数据传输的基础抽象,通过统一的接口处理文件、网络等不同数据源。其核心原理包括字节流/字符流的二进制与文本处理差异,以及缓冲流通过批量传输提升效率的机制。在工程实践中,合理选择I/O类型(如NIO非阻塞模型)和优化策略(如零拷贝技术)能显著提升系统性能,特别是在处理大文件传输或高并发场景时。通过分析PostgreSQL I/O错误等典型问题,开发者可以掌握编码规范、缓冲策略等关键技术要点,有效避免SQL Server校验和错误等常见陷阱。 阅读详情

相关推荐

简单聊聊PostgreSQL buffer与OS cache

作者:吴聪 0、概述 缓存可以说是数据库中相当重要的一部分,很多性能相关的问题都与之息息相关。那么我们今天就聊聊在PostgreSQL中的缓存。 1、为什么需要缓存? 在数据库中似乎我们最关心的是磁盘IO,经常会听到数据库IO存在瓶颈之类的问题。这也是为什么在数据库中我们需要缓存。 打个比方,对于计算机而言,1个CPU周期是0.3ns,如果把这个时间当成是我们平时生活中的1s。那么固态硬盘1次IO的时间大约是50-150μs,这意味着什么呢?相当于我们的2到6天。 这么一对比就可想而知,哪怕你的磁盘IO再快

PostgreSQL China 517

postgresql page页结构

qqq

sjhsxjsdb的博客 910

Java I/O模型穿透指南:从Linux系统调用到WebFlux实战

I/O模型是后端性能的底层基石,其本质是操作系统对文件描述符的调度策略——阻塞/非阻塞由O_NONBLOCK标志控制,同步/异步反映API结果获取方式。理解epoll_wait、read系统调用与JVM线程状态(如WAITING/RUNNABLE)的映射关系,才能真正诊断高并发下的RT毛刺与线程堆积。NIO通过事件驱动提升连接复用率,而WebFlux依赖Reactive生态实现全链路非阻塞;但若混用JDBC等阻塞调用,将触发BlockingOperationError。本文结合strace、jstack、s

as2886089的博客 393

PostgreSQL中page页结构

PostgreSQL中page页结构源码解析 在PG中,磁盘存储和内存中的最小管理单位都是page,也是通常所说的block。一般PG页的大小为8K,在源码编译时可以设置。此后都不...

997

Node.js vs Rails技术选型实战指南:从I/O模型到MVP上线决策

Web后端框架选型本质是运行模型与业务负载的匹配问题。Node.js基于事件循环的异步I/O模型天然适配高并发、低延迟、外部依赖密集型场景;Rails依托多进程+GIL的同步阻塞模型,在复杂业务逻辑、强数据一致性、快速MVP交付等场景中具备显著工程效率优势。二者差异不在抽象性能参数,而在于CPU密集型任务处理能力、错误定位成本、生态契约完备性及团队调试范式适配度。真实项目中,应依据TTFB占比、上线周期、数据模型稳定性、运维监控习惯等5个实操维度动态决策,而非追求单一‘最优解’。本文结合17个生产系统经验,

weixin_30298497的博客 340

PostgreSQL 核心原理:一文掌握数据库的热数据缓存池(共享缓冲区)

PostgreSQL共享缓冲区(Shared Buffer)是提升数据库性能的核心组件,负责缓存8KB数据页以减少磁盘I/O。本文深入解析其设计原理与工作机制,包括: 核心功能:作为热数据缓存池,支持并发访问,结合WAL确保数据一致性 架构设计:采用Buffer Descriptor元数据结构,通过Buffer Tag唯一标识数据页 替换算法:使用Clock Sweep近似LRU效果,兼顾性能与低开销 刷盘机制:由Checkpointer和BgWriter进程异步处理脏页 配置优化:建议shared_buf

数据知道的博客 2647

turbodbc 调优宝典:read_buffer_size、异步 I/O 与 10 大性能选项全解

turbodbc 是一个通过 ODBC 接口访问关系型数据库的 Python 模块,完整兼容 Python 数据库 API 规范 2.0(PEP 249)。它靠"批量传输"而非逐行通信实现高性能,适合 MySQL、PostgreSQL、MSSQL、EXASOL 等数据库。本文带你完整掌握 turbodbc 的 `read_buffer_size`、异步 I/O 等 10 个性能调优选项,让数据读取

gitblog_00563的博客 756

基于卷积神经网络的人脸识别算法

摘要:近年来,随着科学技术的不断发展,人脸识别技术日渐成熟,使得人脸识别技术的使用率不断增大。例如:门禁、ATM机、公安系统以及新兴起的人机交互等领域,都应用到了人脸识别系统。在人脸识别研究领域中,深度学习扮演着重要的角色。由于深度学习的人脸识别技术凭借其识别率高、识别快等特点,逐渐成为整个领域的主流技术。在众多深度学习算法中,以卷积神经网络为代表的人脸识别系统得到了广泛应用,主要研究内容如下:首先,通过对经典损失函数进行研究,对比每种损失函数的特点,然后根据A-Softmax函数进行改进,借助Margin

yyq2263511327的博客 1万+

NVMe SSD数据库场景性能优化全栈深度解析:从MySQL/PostgreSQL调优、WAL隔离到OLTP/OLAP负载特征与fio基准建模

本文全栈解析NVMe SSD在数据库场景中的性能优化方法论,覆盖OLTP/OLAP/Redis等典型负载I/O特征、MySQL InnoDB与PostgreSQL存储参数调优(buffer pool、WAL/redo log、doublewrite、fsync策略)、WAL日志盘隔离架构、RAID卡BBU写缓存影响、Linux I/O调度器与内核调优、fio数据库负载建模与P50/P99/P999延迟实测分析,结合NVMe规范与内核源码深入拆解数据库I/O全路径优化。

专注分享DPU、RDMA智能网卡/SSD(固态硬盘)产品测试与优化 490

SQL注入-靶场通关 Less 1-21

打开Burp工具--打开内嵌浏览器--进入靶场第六关--打开拦截--输入?id=1',如果是正确的,说明不存在注入点,如果错误,说明存在注入点,这里是错误的,需要加上注释--+,在回车看结果是正确的,说明找到了注入点。工具,打开内嵌浏览器,打开拦截,输入http://127.0.0.1/sqli-labs-master/Less-9,然后发送到。id=1'--+,后面都注释了,单引号不闭合,报错说明是数字型SQL注入。设置休眠时间为10s,如果执行SQL语句就会加载,说明正确,存在注入点。

weixin_72104324的博客 1392

别再花钱买插件了!手把手教你实现UE5运行时动态导入FBX模型(附完整源码解析)

本文详细解析了UE5运行时动态导入FBX模型的全过程,从FBX SDK集成配置到核心解析流程,再到引擎资源转换和性能优化。通过多线程加载架构和内存优化技巧,开发者可以高效实现动态模型导入,避免购买昂贵插件。文章还提供了完整源码解析和高级功能扩展,帮助开发者深入理解UE5的底层资源管理机制。

weixin_27033895的博客 379

操作系统缓存:高并发场景下被忽视的磁盘I/O性能优化利器

缓存是提升系统性能的核心技术之一,其基本原理是将高频访问的数据存储在更快的存储介质中,以减少对慢速存储的访问延迟。在计算机系统中,除了应用层缓存如Redis,操作系统内核提供的页缓存(Page Cache)和缓冲区缓存(Buffer Cache)是更底层的优化机制。它们自动将磁盘数据缓存在内存中,旨在弥合内存纳秒级访问与磁盘毫秒级I/O之间的巨大速度鸿沟。这项技术对于处理高并发读、批量数据处理和日志写入等场景具有极高的价值,能显著降低磁盘I/O等待时间,提升吞吐量。在实际工程中,通过优化文件访问模式、合理配

weixin_34326429的博客 957

python零基础入门到精通,python入门到精通教程

坚持到了这儿,恭喜你,表示你有做开发的潜力,其实我想说的上面的内容还是刚刚开始,刚开始大家不需要多么精通了解这些内容,除了Python方面的知识,每个部分掌握一点儿能进行基本开发就好,主要是不断练习,让自己跳出「舒适区」,进入「学习区」,但是又不进入「恐慌区」,不断给自己「喂招」。上述这份完整版的Python全套学习资料已经上传优快云官方,朋友们如果需要可以扫描下方二维码免费获取【保证100%免费】

YYmmsss的博客 3468

pgrust 缓冲管理深度解析:Buffer Manager 与共享缓冲池如何带来极致性能

pgrust 是一个用 Rust 重写 PostgreSQL 的开源项目,其目标不仅是对 C 语言版本的"翻译",更要在性能上全面超越原版。而在这场性能竞赛中,**pgrust 缓冲管理**(Buffer Manager)与**共享缓冲池**(Shared Buffer Pool)正是最核心的引擎之一。可以说,数据库的读写性能,很大程度上就取决于这一层缓存机制设计得有多精妙。本文将从零开始,用通俗

gitblog_00832的博客 350

BetaFlight代码解析(5)— PID控制器

Betaflight的PID控制器是保持飞行器稳定的核心算法,通过比例、积分、微分三组件实时校正姿态误差。该系统还包含前馈、动态D项限制、反重力等高级功能,通过多PID配置文件实现灵活调参,并提供多种调试模式分析性能。这些优化使控制器在保证稳定性的同时提高响应速度,是飞行调优的关键部分。

rainercool的专栏 1497

YOLOv5入门实践(2)——手把手教你利用labelimg标注数据集

YOLOv5入门实践第2步,手把手教你使用labelimg标注数据集

路人贾的博客 1万+

AI时代首先数据库-PostgreSQL实战笔记 27 PostgreSQL数据写入与读取流程解析

一次 UPDATE 从执行到落盘,经历解析、分析、计划、执行、WAL记录、提交与脏页刷盘七个阶段,核心是“日志先行”:数据先在内存中更新,通过 WAL 保证持久性,实际落盘由 Checkpointer 异步完成。而 SELECT 则依赖缓存,若数据页已在 shared_buffers 或 OS page cache 中,可零磁盘读取,性能取决于缓存命中率。写入影响读取(如缓冲区竞争),读取也反哺写入(如减少全表扫描)。本质是:写靠 WAL 保安全,读靠缓存提速度。

源码获取 | 运行部署 | 定制二开修改,如果回复不及时请耐心等待,请见谅。 299

揭秘AI人工智能中Stable Diffusion的模型微调技巧

Stable Diffusion作为一种强大的文本到图像生成模型,在艺术创作、设计、娱乐等多个领域展现出了巨大的应用潜力。然而,其默认的模型输出可能无法满足特定用户或特定场景的个性化需求。本文章的目的在于深入揭秘Stable Diffusion的模型微调技巧,让读者能够根据自己的需求对模型进行定制化调整,生成符合特定风格、主题或要求的图像。范围涵盖了从基础概念到实际操作,从理论原理到项目实战的全方位内容,旨在为读者提供一个系统且深入的学习指南。

大模型应用工坊 950

“PostgreSQL“ 不重启机器就能调整 shared buffer pool 的原理

在整体的数据库系统设计中,关键就是图中的dynamic region,这里为了优化不同进程内存地址不统一的问题,PolarDB for PG通过postmaster启动时御前申请1T的虚拟地址空间,让所有的子进程都继承这段地址,这样所有的内存段迎神到相同的地址后,所有的变了的地址就完全相同了,无需进行重建和解析,直接映射物理的地址。上周三IF-Club直播了PostgreSQL的干货,当时公司在开会所以没有完整听到内容,不过好在拿到了当时直播的PPT,这里对这个部分进行学习,这里和大家进行一个分享。

sql server的专栏 869

ArcGIS Pro 制作这种地图海报

ArcMap 版本与 ArcGIS Pro 版本的制图功能相差太多,无论从美观上还是制图效率都远远优于 ArcMap,用了一段时间的 ArcGIS Pro ,真心推荐有条件的大家赶紧试一试!一个软件也能搞定一张不错的海报哦!----吐槽:好的设计真的是门花时间的活,这个教程大概花了我7小时左右,我都忘了我自己教程中截图多少张了!(可能是我速度太慢了)测试数据:阿里云盘分享-----北极海冰数据.https://www.aliyundrive.com/s/SUhsnqfkmXh。

J_Giser的博客 1430

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

B树与B+树深度解析:从磁盘I/O优化到数据库索引实战

在数据库与文件系统等海量数据存储场景中,磁盘I/O是主要性能瓶颈。为了高效管理磁盘数据,平衡多路搜索树应运而生,它通过增加节点关键字数量来降低树高,从而减少磁盘访问次数。B树和B+树是其中两种核心数据结构,它们在数据组织方式上存在根本差异:B树在每个节点都存储键值对,适合点查询;而B+树将数据全部存储在叶子节点并链接成有序链表,内部节点仅作导航。这种设计使B+树在范围查询和全表扫描时能利用顺序I/O,性能远超B树的随机I/O。因此,B+树成为MySQL等主流数据库索引的标准实现,支撑着高效的范围查询和排序操

weixin_30448603的博客 771

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

B+树索引原理与实现:从磁盘I/O优化到数据库核心应用

在数据库与文件系统设计中,索引是提升数据检索效率的核心机制,其本质是通过特定的数据结构组织数据,减少查询时的计算与I/O开销。B+树作为一种多路平衡搜索树,其设计原理紧密围绕磁盘存储特性展开:通过将数据集中存储在叶子节点、内部节点仅作路由,并利用叶子节点的链表连接,实现了高扇出与低树高,从而将磁盘I/O次数降至最低。这一设计不仅优化了点查询性能,更通过顺序I/O大幅提升了范围查询的效率,成为关系型数据库(如MySQL InnoDB、PostgreSQL)主键索引的标准实现。在实际工程中,B+树通过节点分裂、

angou6476的博客 439

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

VB摄像头监控

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

《The Art of Node》精读:Node.js 异步 I/O、回调与 npm 模块化开发的实战入门指南

> 本文以开源仓库 [art-of-node](https://link.gitcode.com/i/5a156bb7f5b452ec8b76beaba99bb514) 的官方入门文档为主体,系统讲解 Node.js 的核心心智模型:非阻塞 I/O、回调、事件、流,以及以 npm 为中心的模块化开发工作流。读完本篇,你将能够理解 Node 进程如何作为文件系统与网络之间的"代理",掌握回调与事件的

gitblog_00746的博客 235

32丨当Postgres磁盘读引起I/O高的时候,应该怎么办?

在性能分析的人眼里,性能瓶颈就是性能瓶颈。无论这个性能瓶颈出现在代码层、操作系统层、数据库层还是其他层,最终的目的只有一个结果:解决掉! 有人可能会觉得这种说法过于霸道。 事实上,我要强调的性能分析能力,是一套分析逻辑。在这一套分析逻辑中,不管是操作系统、代码还是数据库等,所涉及到的都只是基础知识。如果一个人都掌握这些内容,那确实不现实,但如果是对一个性能团队的要求,我觉得一点也不高。 在性能测试和性能分析的项目中,没有压力发起,就不会有性能瓶颈,也就谈不上性能分析了。所以每个问题的前提,...

ths512的博客 1828

ProxySQL FFTO 协议 Framer 设计解析:MySQL/PostgreSQL 响应分帧的纯化与测试

FFTO(Fast Forward Traffic Observer)是 ProxySQL 在 Fast Forward 模式下被动解析 MySQL 与 PostgreSQL 线上流量、为 `stats_*_query_digest` 采集查询摘要(含耗时、`rows_sent`、`affected_rows`)的核心模块。本文以仓库设计文档 [docs/superpowers/specs/202

gitblog_00457的博客 677

Wand-Enhancer 安装与配置教程:从克隆到首次 Patch 快速上手

Wand-Enhancer 是一款针对 Wand(WeMod)客户端的开源增强工具,能帮你调整本地客户端配置、自动适配新版本客户端,还带一个手机扫码就能用的远程 Web 面板。它适合想自定义 Wand 使用体验、或者想在手机上远程操作 Wand 的用户。下面分四步带你跑起来:环境准备、克隆编译、首次运行、报错排查。 ## 项目速览:Wand-Enhancer 能帮你做什么 Wand-Enhan

gitblog_01065的博客 426
上一篇: PostgreSQL笔记20: 实例、集群、模板数据库与表空间 —— 逻辑体系架构深度解析
下一篇: PostgreSQL笔记22: WAL日志与崩溃恢复原理
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、付费专栏及课程。

余额充值