13 PostgreSQL 面试考点精编(全量 1039 问)

13 PostgreSQL 面试考点精编(全量 1039 问)

基于德哥(digoal)博客 201902–202609 共 92 个月、5741 篇文章,逐篇精读技术主线 2682 篇, 提炼出 1039 条问答,按「传统 PG 技术 → AI 向量数据库 → 国产数据库内核」三大块组织。 与 201901 已有内容去重,并标注关键版本演进点。每条附来源文件路径,便于回溯原文。


第1部分:传统 PostgreSQL 技术(高频必考)

1.1 SQL 特性与新版本能力(211 条)

Q:PostGIS 的坐标系统(BD09、GCJ02、WGS84)转换怎么做?

WGS84 是 GPS 使用的世界坐标系;GCJ02 是国测局“火星坐标”,国内地图(高德、腾讯)使用,在 WGS84 基础上加密偏移;BD09 是百度在 GCJ02 上再加密的坐标系。PostGIS 中转换用 ST_Transform 在不同 SRID 间转换,但 BD09/GCJ02 的加密偏移无公开公式,需用插件或自定义函数实现近似转换(如扩展里提供的转换函数),不能简单用 ST_Transform 处理。

关键词:PostGIS,BD09,GCJ02,WGS84,坐标系,ST_Transform | 来源:202103/20210313_18.md

Q:PostgreSQL 12 支持哪些 SQL/JSON 标准特性?

PG12 开始支持 SQL 2016 标准的 SQL/JSON 特性,包括 JSON_EXISTS、JSON_QUERY、JSON_VALUE 等以 jsonpath 为基础的 SQL 标准接口。jsonpath 是 SQL/JSON 的核心路径语言,用 $ 表示根、.key 取对象成员、[*] 取数组元素,配合 exists、type、size 等方法。这套标准让 JSON 查询能力从 PG 自定义操作符向 SQL 标准对齐,后续 PG15/16 又补充了 JSON_TABLE、JSON 构造器和更多 jsonpath 方法。

关键词:SQL/JSON,jsonpath,JSON_EXISTS,JSON_QUERY,JSON_VALUE,PG12 | 来源:201903/20190331_06.md

Q:PostgreSQL 12 的 COPY FROM 支持 WHERE 过滤吗?怎么用?

支持。PG12 扩展了 COPY FROM 语法,可以在导入时加 WHERE condition 过滤记录,例如 COPY t_from FROM ‘/tmp/t_to’ WHERE id<100,只导入满足条件的行。在此之前要实现过滤只能先预处理输入文件,或全量导入后再在库里删除。它支持随机采样、按数据列条件过滤等,对大多数简单场景是低开销的替代方案,只对 FROM 方向有效。

关键词:COPY,WHERE,过滤,导入,PG12 | 来源:201903/20190331_11.md

Q:PostgreSQL 12 的 CTE materialized 控制是什么?

PG12 起 CTE 支持用户用 MATERIALIZED / NOT MATERIALIZED 关键字控制是否物化。此前(PG11 及更早)WITH 子查询总是被物化(先算完存临时结果),PG12 默认改为让优化器内联优化,但允许用户显式指定。MATERIALIZED 强制物化(隔离优化、避免多次重算),NOT MATERIALIZED 允许内联。这对控制复杂 CTE 的执行计划和性能很有用。

关键词:CTE,MATERIALIZED,NOT MATERIALIZED,PG12 | 来源:201903/20190309_04.md

Q:PostgreSQL 12 的 DROP OWNED BY 是什么?

DROP OWNED BY 用户名 删除该用户拥有的所有对象(表、视图、函数、序列等),但不删除用户本身。它常用于清理用户、回收权限前的对象转移,配合 REASSIGN OWNED(转移对象所有权给其他用户)和 DROP USER 完成用户下线流程。注意 DROP OWNED 会真正删除对象,需谨慎确认。

关键词:DROP OWNED BY,REASSIGN OWNED,用户清理,PG12 | 来源:201903/20190330_09.md

Q:PostgreSQL 12 的 SQL 采样比例设置(log sample)是什么?

PG12 支持对事务采样记录日志,用 log_transaction_sample_rate 设置采样比例,只记录部分事务的 SQL 日志,减少全量 SQL 日志的开销。PG13 又增加 log_min_duration_sample,对超过指定耗时的语句按比例采样。这些让慢查询/审计日志在“完整记录”和“性能开销”之间平衡。

关键词:log_transaction_sample_rate,log_min_duration_sample,SQL采样,PG12 | 来源:201904/20190405_09.md

Q:PostgreSQL 12 的 SSL clientcert verify-full 是什么?

PG12 的 pg_hba.conf clientcert 选项新增 verify-full,要求客户端证书的 CN 必须与登录用户名完全匹配(verify-ca 只验证 CA 签发)。verify-full 提供更强的身份绑定,防止持有合法 CA 证书但身份不符的客户端登录,是 mTLS 认证的安全增强。

关键词:clientcert,verify-full,SSL,mTLS,PG12 | 来源:201904/20190405_02.md

Q:PostgreSQL 12 的 data_sync_retry 是什么?

data_sync_retry 是 PG12 引入的参数,解决 OS 层 write back failed status 不可靠的问题,控制 fsync 失败后的重试行为。底层存储(如 NFS、某些 SAN)的写回失败状态可能不可靠,data_sync_retry 让 PG 在 sync 失败时重试而非立即 panic,提升可靠性。

关键词:data_sync_retry,fsync,写回失败,PG12 | 来源:201903/20190309_03.md

Q:PostgreSQL 12 的 integerset 数据结构(Simple-8b)是什么?

PG12 引入 integerset 数据结构,用于高效存储 64 位整数集合,内部采用 Simple-8b 压缩算法(把多个小整数打包到一个 64 位字里)。它用于 GIN 索引 posting list 等需要存储大量有序整数的场景,比普通数组更省空间、更快。这是存储引擎底层的数据结构优化。

关键词:integerset,Simple-8b,64位整数,PG12 | 来源:201903/20190331_04.md

Q:PostgreSQL 12 的 parallel 递归查询支持吗?

PG12 时期递归查询(WITH RECURSIVE)不支持并行执行,是并行计算的限制之一。递归 CTE 的 work table 迭代有先后依赖关系,每轮必须基于上一轮结果,难以并行化。相关并行优化(如并行 CTE、并行递归)是持续研究方向,PG18 才在窗口/递归性能上有提升。递归查询的并行化至今仍是 PG 的短板。

关键词:递归查询,并行,parallel,限制 | 来源:201903/20190318_04.md

Q:PostgreSQL 12 的 pgbench 一条 SQL 最多绑定 256 个变量是什么?

PG12 起 pgbench 自定义压测脚本的一条 SQL 最多可绑定 256 个变量,替代此前较少的上限。这让复杂压测脚本(多参数 SQL、多条件查询)能绑定更多变量,模拟更真实的业务 SQL。变量通过 :varname 引用,\set 赋值。

关键词:pgbench,256变量,绑定,PG12 | 来源:201903/20190331_07.md

Q:PostgreSQL 12 的 psql help 支持 manual url 显示是什么?

PG12 的 psql \help 支持显示 manual url 链接(在线文档地址),让用户从命令行直接跳转到对应 SQL 命令的官方文档。这方便查阅命令的详细说明和示例,提升 psql 的使用体验。

关键词:psql,help,manual url,PG12 | 来源:201903/20190331_09.md

Q:PostgreSQL 12 的 ssl_min/max_protocol_version 是什么?

PG12 起支持 ssl_min_protocol_version 和 ssl_max_protocol_version 参数,控制允许的 SSL/TLS 协议版本范围(如 TLSv1.2、TLSv1.3),禁用不安全的旧协议(SSLv3、TLSv1.0)。这用于强制使用安全协议,满足安全合规要求,防止降级攻击。

关键词:ssl_min_protocol_version,ssl_max_protocol_version,TLS,PG12 | 来源:201909/20190908_03.md

Q:PostgreSQL 14 的 COPY 支持 visibility map 及时更新是什么?

PG14 的 COPY 导入时及时更新 visibility map(可见性映射),标记全可见页,减少后续 vacuum 的工作量。visibility map 记录哪些页对所有事务可见,vacuum 据此跳过已全可见的页。COPY 导入的新数据页都是全可见的,及时更新 VM 让 vacuum 更快,也利于 index-only scan。

关键词:COPY,visibility map,VM,PG14 | 来源:201903/20190331_11.md

Q:PostgreSQL 14 的 Unicode 组合字符性能优化是什么?

PG14 优化了后端 Unicode 分解/重组(decomposition/recomposition)的性能。Unicode 规范化(如 NFC)涉及字符分解和重组,是 collate、大小写转换、normalize 的底层操作,某些语言文本处理时开销较大。优化后这部分性能提升,改善国际文本的处理速度。

关键词:Unicode,decomposition,recomposition,PG14 | 来源:202010/20201024_01.md

Q:PostgreSQL 14 的 abstract Unix-domain socket 是什么?

PG14 支持 abstract Unix-domain socket(Linux 特有的抽象命名空间 socket),用 @ 前缀命名,不占用文件系统路径。相比传统 Unix socket 需要文件路径,abstract socket 不受路径长度、文件权限限制,关闭时自动清理,适合容器化环境(socket 文件不落地)。这增强了 Linux 上 socket 的灵活性和安全性。

关键词:abstract socket,Unix-domain,Linux,PG14 | 来源:202011/20201126_01.md

Q:PostgreSQL 14 的 bit_count 和 bit_xor 是什么?

bit_count(x) 计算整数的二进制表示中 1 的个数(PG14),bit_xor 是位异或聚合函数(PG14 新增)。bit_count 用于统计置位位数(如权限位、特征位统计);bit_xor 对一组值做异或聚合,可用于校验、去重(异或相同值抵消)等场景。它们补齐了 PG 的位运算函数族。

关键词:bit_count,bit_xor,位运算,PG14 | 来源:202103/20210324_03.md

Q:PostgreSQL 14 的 check_client_connection_interval 是什么?

check_client_connection_interval 是 PG14 协议层的心跳检测参数,运行长查询时周期性检查客户端连接是否还存活(检测 POLLHUP/POLLRDHUP),若客户端已离线可快速中断还在运行的长 SQL。此前客户端断开后,服务端可能还在空跑长查询浪费资源,直到查询结束才感知。该参数让服务端及时回收客户端已断开的查询。

关键词:check_client_connection_interval,心跳,长查询,PG14 | 来源:202104/20210403_01.md

Q:PostgreSQL 14 的 compute_query_id 与 pg_stat_statements 什么关系?

pg_stat_statements 依赖 query id 来聚合相同 SQL 的统计。PG14 起 query id 的计算由内核统一提供(compute_query_id 控制),pg_stat_statements 复用内核的 query id 而非自己再算一遍。统一 query id 后,多个需要 SQL 指纹的组件(统计、审计、监控)共享一致的 ID,能跨视图关联,也避免了重复计算开销。

关键词:compute_query_id,pg_stat_statements,query id,PG14 | 来源:202104/20210408_04.md

Q:PostgreSQL 14 的 hash 函数生成代码增强(PerfectHash)是什么?

PG14 用 src/tools/PerfectHash.pm 生成完美的 hash 函数,用于内部查找表(如关键字的 hash 查找),减少 hash 冲突、提升查找效率。PerfectHash 为静态键集生成无冲突的哈希函数,相比通用 hash 表更快、更省空间,是内核内部性能优化。

关键词:PerfectHash,hash函数,PG14 | 来源:202010/20201010_02.md

Q:PostgreSQL 14 的 log_connections 打印 pg_hba 行号有什么作用?

PG14 的 log_connections 增强,打印连接命中了 pg_hba.conf 的第几行规则、使用什么认证方法,方便判断客户端是通过哪条规则认证进来的。当有多条 pg_hba 规则时,连接可能命中错误的规则导致认证异常,打印行号和认证方法让 DBA 能快速定位问题规则,是连接排障的重要辅助。

关键词:log_connections,pg_hba,认证方法,PG14 | 来源:202104/20210407_07.md

Q:PostgreSQL 14 的 pg_database_owner 默认角色是什么?

pg_database_owner 是 PG14 新增的预定义角色,表示“当前数据库的 owner”,可把权限授予它,从而把权限授予“这个库的 owner”这一抽象身份,而非某个具体用户。这样当库 owner 变更时,权限自动跟随新的 owner,避免逐个改授权。它简化了多租户和数据库 owner 变更场景的权限管理。

关键词:pg_database_owner,默认角色,权限,PG14 | 来源:202103/20210327_01.md

Q:PostgreSQL 14 的 pg_stat_wal 视图是什么?

pg_stat_wal 是 PG14 新增的统计视图,统计 WAL 相关的指标(WAL 生成量、WAL 写、WAL 同步次数和时间、WAL 满页写等)。它让 DBA 能量化 WAL 的活动强度,评估 WAL 吞吐、checkpoint 频率、wal_sync 开销,是分析写放大和复制负载的依据。

关键词:pg_stat_wal,WAL统计,PG14 | 来源:202010/20201003_02.md

Q:PostgreSQL 14 的 pg_wait_for_backend_termination 函数是什么?

pg_wait_for_backend_termination(pid, timeout_ms) 发送终止信号给指定进程,并等待最多 timeout 毫秒,若进程未在超时内终止则返回 false 并告警。这是 kill 会话的增强,此前 pg_terminate_backend 发信号后立即返回,无法知道进程是否真的退出。新函数让会话终止可控、可确认,避免 kill 后残留进程。

关键词:pg_wait_for_backend_termination,terminate,超时,PG14 | 来源:202104/20210408_10.md

Q:PostgreSQL 14 的 pgbench gset 支持 SQL 结果存变量是什么?

pgbench 的 \gset 元命令把上一条 SQL 查询的结果存入 pgbench 变量,PG12 起支持(一条 SQL 最多绑定 256 个变量)。这让压测脚本能根据查询结果动态决定后续操作,模拟依赖查询的业务逻辑,例如先查用户余额再决定转账金额。gset 把 pgbench 从简单压测提升为可编程的业务负载仿真工具。

关键词:pgbench,gset,变量,压测 | 来源:201903/20190331_05.md

Q:PostgreSQL 14 的 pgbench 冒号常量和 permute 随机函数是什么?

PG14 的 pgbench 增强:支持冒号常量(如 :client_id 之外的时间戳常量),以及 permute(i, size, seed) 随机函数,返回 i 经过随机映射后在 [0,size) 的值。permute 用于生成可复现的随机分布(如均匀打散键值),避免压测数据局部热点。这些增强让 pgbench 能模拟更真实的负载分布。

关键词:pgbench,permute,冒号常量,PG14 | 来源:201903/20190331_07.md

Q:PostgreSQL 14 的 psql 快捷命令 df/do 支持参数输入是什么?

PG14 的 psql 快捷命令 \df、\do 支持按参数类型筛选函数和操作符,例如 \df pattern 可加参数类型限定,只列出匹配签名的函数/操作符。此前这些命令只按名字模式过滤,无法按参数类型精确定位重载函数。支持参数输入后,查找某个特定签名的函数/操作符更精确。

关键词:psql,df,do,参数类型,PG14 | 来源:201903/20190331_09.md

Q:PostgreSQL 14 的 query id(SQL 指纹)是什么?

PG14 支持计算 SQL 指纹(query id),把规范化后的 SQL 生成唯一 ID,GUC compute_query_id 控制开关。query id 让同一条 SQL(忽略常量差异)在不同会话、不同统计视图(pg_stat_statements、pg_stat_activity)间关联起来,是 SQL 性能分析、审计、追踪的基础。规范化会把常量替换为占位符,使功能等价的 SQL 归为同一指纹。

关键词:query id,SQL指纹,compute_query_id,PG14 | 来源:202104/20210408_04.md

Q:PostgreSQL 14 的 recovery_init_sync_method=syncfs 是什么?

PG14 引入 recovery_init_sync_method 参数,可选 syncfs 方式,在崩溃恢复时用 syncfs 系统调用一次性同步整个文件系统,而非逐个文件 open+fsync。当表很多时,逐个 open 文件非常慢,syncfs 只同步一次,大幅加速恢复。需 Linux 新内核支持。

关键词:recovery_init_sync_method,syncfs,崩溃恢复,PG14 | 来源:202103/20210320_02.md

Q:PostgreSQL 14 的 remove_temp_files_after_crash 是什么?

remove_temp_files_after_crash 是 PG14 的 GUC,控制 backend 崩溃重启后是否自动清理残留的临时文件。排序、hash join 等操作会落盘临时文件,进程崩溃时可能残留,占空间。默认清理这些残留临时文件,避免磁盘被垃圾文件占满。

关键词:remove_temp_files_after_crash,临时文件,PG14 | 来源:202105/20210519_01.md

Q:PostgreSQL 14 的 unistr 和字符串 Unicode 处理常用函数有哪些?

常用 Unicode/字符串处理:unistr() 还原 Unicode 转义;CHR(n) 按码点生成字符;ascii() 取首字符码点;E’…’ 字符串支持 \uXXXX 转义;normalize() 做 Unicode 规范化(NFC/NFD)。这些配合用于国际文本清洗、特殊字符处理、大小写转换(lower/upper/CASEFOLD)。PG14 起 unistr 让 Unicode 转义书写更直接。

关键词:unistr,CHR,Unicode,normalize,字符串 | 来源:202103/20210330_02.md

Q:PostgreSQL 14 的 unistr 和字符集相关的 escape 处理有哪些?

PG14 的 unistr() 还原 Unicode 转义字符串(如 unistr(’\0061’) 返回 ‘a’),配合 E’…’ 字符串的转义、CHR() 按码点生成字符等,构成字符转义处理的完整工具集。它们用于在 SQL 里书写控制字符、不可见字符和特殊 Unicode 字符,是文本清洗和国际字符处理的常用函数。

关键词:unistr,Unicode,escape,CHR,PG14 | 来源:202103/20210330_02.md

Q:PostgreSQL 14 的增量排序(incremental sort)支持窗口函数是什么?

PG14 起窗口函数支持 incremental sort(增量排序)。当数据已按部分排序列有序(如已按 partition by 列有序),只需在每组内对 order by 列做小范围排序,而非全局全量排序。incremental sort 利用已有有序性,减少排序数据量和内存占用,对窗口查询(尤其分区多、每区数据少)有显著加速。

关键词:incremental sort,窗口函数,排序,PG14 | 来源:202009/20200916_01.md

Q:PostgreSQL 15 的 COPY text 格式支持 HEADER 是什么?

PG15 起 COPY 的 text 格式也支持 HEADER 选项,即在 text 格式文件第一行写入列名头。此前 HEADER 主要用于 CSV 格式,text 格式没有表头支持。增加 HEADER 后,text 格式导出的文件自带列名,便于人工查看和工具解析,与 CSV 行为对齐。

关键词:COPY,text格式,HEADER,PG15 | 来源:201903/20190331_11.md

Q:PostgreSQL 15 的 COPY 支持 HEADER match(列名匹配)是什么?

PG15 的 COPY FROM / file_fdw 支持 header match,把文件第一行作为列名,与目标表列名匹配后按名对应导入,而非按位置对应。这避免了源文件列顺序与表不一致时导入错列的问题,导入更稳健。此前 HEADER 只是跳过第一行,列仍按位置对应。

关键词:COPY,HEADER match,列名匹配,file_fdw,PG15 | 来源:201903/20190331_11.md

Q:PostgreSQL 15 的 CustomScan 支持 projections 是什么?

PG15 允许 CustomScan provider 声明是否支持投影(projections),即自定义扫描节点能否只输出需要的列。此前 CustomScan 通常输出整行,投影下推不充分。支持投影后,扩展自定义的扫描节点(如 FDW 的并行扫描、向量扫描)可只返回所需列,减少数据传输和计算,是扩展点性能优化。

关键词:CustomScan,projections,投影,PG15 | 来源:202107/20210707_01.md

Q:PostgreSQL 15 的 MERGE INTO 与 ON CONFLICT 有何区别?

ON CONFLICT(INSERT … ON CONFLICT)只能处理 INSERT 时的唯一约束冲突,语义是“插入冲突则更新”;MERGE 更通用,用 WHEN MATCHED / WHEN NOT MATCHED 分支表达匹配更新、不匹配插入,且 PG17 支持 WHEN NOT MATCHED BY SOURCE 做删除。MERGE 还能关联源表和目标表的多列条件,ON CONFLICT 只能基于唯一约束。对需要“同步源数据到目标表(增删改全量)”的 ETL 场景,MERGE 是标准且更强的选择。

关键词:MERGE,ON CONFLICT,upsert,WHEN NOT MATCHED BY SOURCE | 来源:202203/20220329_02.md

Q:PostgreSQL 15 的 NULLS NOT DISTINCT 和 UNIQUE 约束的关系是什么?

UNIQUE 约束默认把 NULL 视为彼此不同(NULLS DISTINCT),因此允许多行 NULL。PG15 起支持 UNIQUE NULLS NOT DISTINCT,把 NULL 当作普通等价值,只允许一行 NULL。这解决了“业务上希望某列至多一行 NULL”的诉求,是唯一约束对 NULL 语义的可选项扩展。

关键词:NULLS NOT DISTINCT,UNIQUE,NULL语义,PG15 | 来源:201911/20191128_01.md

Q:PostgreSQL 15 的 NUMERIC scale 负数的应用场景是什么?

NUMERIC scale 为负表示小数点左侧舍入,如 NUMERIC(10, -2) 精确到百位,12345 存储为 12300。这用于金额以百/千为单位记账、数量级取整、科学计数等场景,避免应用层手工舍入。PG15 把 scale 范围扩展到 -1000~1000,覆盖更大精度的取整需求。

关键词:NUMERIC,scale负数,取整,PG15 | 来源:202107/20210727_03.md

Q:PostgreSQL 15 的 PG 内置逻辑订阅 worker 统计视图是什么?

PG15 新增 pg_stat_subscription_workers 视图,统计逻辑订阅端的 worker 状态(apply worker、table sync worker 等),观察订阅的并行应用进度、各 worker 的延迟和状态。逻辑订阅可配置多个 apply worker 并行应用变更,该视图让 DBA 能监控并行度和同步进度,是逻辑复制运维的必备视图。

关键词:pg_stat_subscription_workers,逻辑订阅,worker,PG15 | 来源:202111/20211130_01.md

Q:PostgreSQL 15 的 PRNG API 替代 random API 是什么?

PG15 预览引入 PRNG(伪随机数生成器)API,用更好的随机数算法替代原有 random() 的 API。新 API 提供可指定种子、可复现、质量更高的随机数生成,适合测试数据可复现、加密相关(配合更好的熵源)等场景。它解决了 old random API 算法单一、无法注入种子的问题。

关键词:PRNG,随机数,random API,PG15 | 来源:202112/20211202_02.md

Q:PostgreSQL 15 的 analyze 支持 prefetch 加速是什么?

PG15 的 ANALYZE 支持 prefetch 预读,用 maintenance_io_concurrency 控制,提前把要采样的数据页读入 buffer,加速统计信息收集。ANALYZE 需要扫描大量页面,预读能减少随机读等待,缩短大表统计信息收集时间。此前 prefetch 主要用在位图扫描,扩展到维护操作是性能提升。

关键词:ANALYZE,prefetch,maintenance_io_concurrency,PG15 | 来源:202001/20200101_02.md

Q:PostgreSQL 15 的 auxproc 代码独立是什么?

PG15 把辅助进程(auxiliary process,如 bgwriter、checkpointer、walwriter 等)的代码从 postmaster 中独立出来,重构了辅助进程的管理结构。这提升了代码可维护性,为后续辅助进程的扩展和 AIO worker 等新辅助进程的引入奠定基础。

关键词:auxproc,辅助进程,重构,PG15 | 来源:202108/20210806_02.md

Q:PostgreSQL 15 的 in-place tablespace 和 pg_tblspc 相对路径是什么?

PG15 支持 in-place tablespace,允许 pg_tblspc 目录使用相对路径引用表空间,简化表空间的管理和迁移。in-place tablespace 把表空间放在数据目录内或相对位置,便于容器化、可移植部署。此前表空间多通过符号链接指向绝对路径,相对路径让数据目录整体移动时表空间引用仍有效。

关键词:in-place tablespace,pg_tblspc,相对路径,PG15 | 来源:202203/20220317_01.md

Q:PostgreSQL 15 的 log destination 支持 jsonlog 格式是什么?

PG15 起 log_destination 支持 jsonlog 格式,日志以 JSON 结构化输出,便于日志采集系统(ELK、Loki 等)直接解析。此前日志是文本或 CSV 格式,JSON 格式字段化、可扩展,机器解析更友好。这对日志分析、告警、审计场景是重要改进。

关键词:jsonlog,log_destination,结构化日志,PG15 | 来源:202201/20220112_02.md

Q:PostgreSQL 15 的 pg_walinspect 插件是什么?

pg_walinspect 是 PG15 引入的插件,提供 SQL 函数接口解析 WAL 日志内容(类似 pg_waldump 但用 SQL 调用),可查看 WAL 记录的类型、涉及的 relation、LSN 等信息。这让 WAL 内容分析无需命令行工具,直接 SQL 查询,方便排查复制延迟、WAL 膨胀、逻辑解码等问题。

关键词:pg_walinspect,WAL解析,pg_waldump,PG15 | 来源:202204/20220411_01.md

Q:PostgreSQL 15 的 regexp_xxx 系列函数对齐 Oracle 是什么?

PG15 预览增强了 regexp 系列函数,对齐 Oracle 的 REGEXP_SUBSTR、REGEXP_INSTR、REGEXP_COUNT、REGEXP_REPLACE 等语义和参数位置,降低 Oracle 迁移到 PG 的改写成本。PG 原本有 POSIX 正则操作符(、!~)和 regexp_ 函数,但对齐 Oracle 后,去 O 迁移时正则相关代码改动更少。

关键词:regexp,Oracle兼容,REGEXP_SUBSTR,PG15 | 来源:202010/20201031_08.md

Q:PostgreSQL 15 的 unlogged/logged sequence 是什么?

PG15 起 sequence 支持 unlogged 和 logged 两种模式,可显式指定(ALTER SEQUENCE … SET LOGGED/UNLOGGED)。unlogged sequence 不写 WAL、推进更快,但崩溃后值可能回退(可能产生重复值);logged sequence 持久但略慢。临时表上的 sequence 默认 unlogged。这提供了序列性能与持久性的选择。

关键词:sequence,unlogged,logged,PG15 | 来源:202005/20200514_01.md

Q:PostgreSQL 15 的逻辑订阅支持序列变更复制吗?

支持。PG15 起逻辑复制支持订阅序列(sequence)变更,即 sequence 的 nextval 推进可以被复制到订阅端,保持发布端和订阅端的序列值一致。此前序列不参与逻辑复制,主备切换或双向复制时序列值会漂移。PG19 又支持发布端 FOR ALL SEQUENCES 和订阅端 REFRESH SEQUENCES,序列同步更完整,为基于逻辑复制的大版本升级铺路。

关键词:逻辑复制,序列,sequence,FOR ALL SEQUENCES,PG15 | 来源:202005/20200514_01.md

Q:PostgreSQL 16 的 COPY into foreign table 加速(batch insert mode)是什么?

PG16 预览支持 COPY 写入外部表(如 postgres_fdw)时的批量插入模式(batch insert),把逐行 insert 合并为批量传输,减少网络往返次数和远端开销,大幅提升 COPY 到外部表的速度。此前 COPY 外部表逐行走 FDW insert 路径,性能较差,批量模式是 FDW 写入性能的关键优化。

关键词:COPY,外部表,batch insert,postgres_fdw,PG16 | 来源:201903/20190331_11.md

Q:PostgreSQL 16 的 array_shuffle() 和 array_sample() 是做什么的?

array_shuffle() 随机打散数组元素顺序,array_sample(array, n) 从数组随机抽取 n 个元素(不重复)。它们是 PG16 引入的数组随机操作函数,替代手工用 ORDER BY random() 对数组元素排序的繁琐写法,用于随机抽奖、随机采样、洗牌等场景,简洁高效。

关键词:array_shuffle,array_sample,数组随机,PG16 | 来源:202304/20230410_03.md

Q:PostgreSQL 16 的 load_balance_hosts 是什么?

libpq 的 load_balance_hosts 参数(PG16)在配置多个 host 时,按随机顺序尝试连接,实现简单的客户端负载均衡。此前多 host 是按顺序 failover,总是优先连第一个 host。load_balance_hosts 把连接请求随机分散到各 host,配合 target_session_attrs 实现读写分离的负载均衡,避免单点连接压力过大。

关键词:load_balance_hosts,libpq,负载均衡,多host,PG16 | 来源:202303/20230330_02.md

Q:PostgreSQL 16 的 pg_buffercache_usage_counts 是什么?

pg_buffercache 插件在 PG16 增强,新增 pg_buffercache_usage_counts 视图统计各 usage count(buffer 的访问热度计数)分布。usage count 反映 buffer 被访问的频率,是 buffer 淘汰策略(时钟扫描)的依据。通过该视图可了解 buffer pool 的热度分布,判断哪些页常驻内存、哪些即将被淘汰,辅助评估 shared_buffers 大小是否合适。

关键词:pg_buffercache,usage count,buffer热度,PG16 | 来源:202304/20230410_05.md

Q:PostgreSQL 16 的 pg_dissect_walfile_name() 函数是什么?

pg_dissect_walfile_name(wal文件名) 解析 WAL 文件名,返回该 WAL 是第几个 WAL segment 以及 timeline 是多少。WAL 文件名编码了时间线(timeline)、日志段号、段大小等信息,此前需手工解析。该函数让 WAL 文件名的解析标准化,便于备份恢复、归档管理和位点计算时编程处理。

关键词:pg_dissect_walfile_name,WAL文件名,timeline,segment,PG16 | 来源:202212/20221222_01.md

Q:PostgreSQL 16 的 pg_hba.conf 通配符/正则是什么?

PG16 预览支持 pg_hba.conf 中 user、database 字段使用通配符和正则表达式,例如匹配所有以 app_ 开头的数据库或用户组。此前这些字段只支持精确名、all 或逗号列表,无法按模式匹配。这让访问控制规则更灵活,便于按命名规范批量授权,减少规则条数。

关键词:pg_hba.conf,通配符,正则,user,database,PG16 | 来源:202210/20221024_01.md

Q:PostgreSQL 16 的 pg_stat_io 视图增强(hits、IO timing)是什么?

PG16 增强 pg_stat_io:增加 shared buffer hits 统计(缓冲命中次数),以及 reads、writes、extends、fsyncs 的 I/O 耗时(IO timing)。这让 DBA 能同时看到 I/O 的次数和耗时,区分“命中高但慢”与“命中低但快”,更准确评估存储性能和 buffer 效率,是 I/O 诊断的核心视图。

关键词:pg_stat_io,hits,IO timing,buffer,PG16 | 来源:202303/20230331_08.md

Q:PostgreSQL 16 的 prepared statement 的 custom_plans/generic_plans 统计是什么?

PG14 起能统计 prepared statement 的 custom_plans 和 generic_plans 次数,即每次重新规划(custom)还是复用通用计划(generic)的次数。通过 pg_prepared_statements 等视图可看到某条 prepared statement 的计划使用模式。这帮助判断绑定变量是否在高效复用计划,还是因数据倾斜频繁重新规划,是计划缓存调优的依据。

关键词:custom_plans,generic_plans,prepared statement,计划缓存 | 来源:202007/20200720_01.md

Q:PostgreSQL 16 的 psql 扩展查询协议命令是什么?

PG16 的 psql 新增命令支持使用扩展查询协议(extended query protocol),即显式使用 prepared statement 的 parse/bind/execute 流程,PG18 又增强了 psql 对 bind、parse、bindx、close 等 prepared statement 元语的支持。这让脚本化测试能精确模拟驱动层的绑定变量行为,便于调试参数化查询和执行计划。

关键词:psql,扩展查询协议,prepared statement,PG16 | 来源:201903/20190331_09.md

Q:PostgreSQL 16 的 scram_iterations 参数是什么?

scram_iterations 控制 SCRAM-SHA-256 认证中密码哈希迭代次数(默认 4096),PG16 起可配置。增大迭代次数提升暴力破解难度(密码破解成本随迭代次数线性增长),代价是登录时认证计算更慢。它是密码安全与登录性能之间的权衡,配合更严格的密码策略可增强账户安全。

关键词:scram_iterations,SCRAM,认证,暴力破解,PG16 | 来源:202303/20230327_01.md

Q:PostgreSQL 16 的 string_agg / array_agg 支持并行有什么意义?

PG16 之前 string_agg、array_agg 等有序聚合不支持并行执行,是并行聚合的短板。PG16 起支持并行,让这类聚合也能利用多 worker 并行计算再合并,在大数据量聚合场景下显著提速。实现上需要处理并行聚合的合并顺序,保证 string_agg 的结果顺序符合 ORDER BY 要求。这补齐了并行聚合对有序聚合函数的覆盖。

关键词:string_agg,array_agg,并行聚合,PG16 | 来源:202301/20230125_03.md

Q:PostgreSQL 17 的 –copy-file-range 选项(pg_upgrade)是什么?

pg_upgrade 新增 –copy-file-range 选项,升级时用 copy_file_range 系统调用复制数据文件,利用文件系统的 reflink/COW 能力,大文件复制更快、更省空间。相比传统逐块拷贝,copy_file_range 在内核态完成,减少用户态拷贝开销,是升级提速的优化。

关键词:pg_upgrade,copy-file-range,reflink,PG17 | 来源:202403/20240306_01.md

Q:PostgreSQL 17 的 ALTER SYSTEM 可设置未识别的自定义 GUC 是什么?

PG17 起 ALTER SYSTEM 允许设置未识别的自定义 GUC(扩展自定义参数),此前 ALTER SYSTEM 只接受内核已知参数,扩展参数需另想办法持久化。支持后,可通过 ALTER SYSTEM SET 持久化扩展参数到 postgresql.auto.conf,与内核参数统一管理。配合 allow_alter_system GUC 可控制是否允许 ALTER SYSTEM 修改配置。

关键词:ALTER SYSTEM,自定义GUC,allow_alter_system,PG17 | 来源:202403/20240329_01.md

Q:PostgreSQL 17 的 ALTER TABLE SET ACCESS METHOD 支持 DEFAULT 是什么?

PG17 的 ALTER TABLE … SET ACCESS METHOD 支持 DEFAULT 选项,把表重置为默认访问方法(heap)。此前设置访问方法需显式指定,DEFAULT 让重置更直观。这配合可插拔存储引擎(table AM)使用,方便在不同 AM 间切换(如 heap 与压缩/列存 AM)。

关键词:SET ACCESS METHOD,DEFAULT,table AM,PG17 | 来源:202103/20210327_01.md

Q:PostgreSQL 17 的 COPY LOG_VERBOSITY 是什么?

PG17 的 COPY 支持 LOG_VERBOSITY 选项,控制错误/跳过行时打印的信息详细程度(verbose/notice/error 等),配合 SAVE_ERROR_TO 使用。PG18 又支持 silent,对跳过的错误行保持静默。这让 COPY 导入的错误输出可控,批量导入大量脏数据时不刷屏,只记录需要的错误信息。

关键词:COPY,LOG_VERBOSITY,silent,PG17 | 来源:201903/20190331_11.md

Q:PostgreSQL 17 的 COPY SAVE_ERROR_TO 是什么?解决什么问题?

COPY FROM 新增 SAVE_ERROR_TO 选项,导入遇到错误行时不再整体失败,而是把出错的数据保存到指定表(需提前建好)并继续导入其余行。这解决了 PG 长期被吐槽的「COPY 遇到一条坏数据就全盘报错、无法跳过错误行」的痛点。配合 LOG_VERBOSITY 可控制是否打印错误详情,PG18 又支持 LOG_VERBOSITY=silent 对跳过错误保持静默。适用于清洗不干净的外部数据批量入库。

关键词:COPY,SAVE_ERROR_TO,错误行,LOG_VERBOSITY,PG17 | 来源:202401/20240125_01.md

Q:PostgreSQL 17 的 RETURNING 支持 MERGE 是什么?

PG17 的 MERGE 语句支持 RETURNING 子句,返回被 UPDATE/INSERT/DELETE 处理的行。这让 MERGE 也能像普通 DML 一样输出变更结果,配合 CTE 或应用获取影响的行。此前 MERGE 不支持 RETURNING,需额外查询确认结果,新特性补齐了 MERGE 的结果回传能力。

关键词:MERGE,RETURNING,PG17 | 来源:202203/20220329_02.md

Q:PostgreSQL 17 的 SQL/JSON 函数和 jsonpath 方法增强了什么?

PG17 实现了更多 jsonpath 方法(Implement various jsonpath methods),如 .type()、.size()、.double()、.ceiling()、.floor()、.abs() 等,让 jsonpath 表达更丰富。配合 SQL/JSON 函数(JSON_EXISTS/QUERY/VALUE)和 JSON_TABLE,PG 的 JSON 查询能力向 SQL/JSON 标准全面靠拢,减少与 Oracle/标准 SQL 的差异。

关键词:jsonpath方法,SQL/JSON,JSON_TABLE,PG17 | 来源:202204/20220408_09.md

Q:PostgreSQL 17 的 alter table 部分属性 hook 是什么?

PG17 增加 ALTER TABLE 部分属性的 hook 接口,允许扩展在表结构变更(如改特定属性)时插入自定义逻辑,用于定制化审计。hook 是 PG 的扩展机制,在核心流程的特定点调用扩展回调。ALTER TABLE hook 让表结构变更可被追踪、审计、拦截,是安全审计和合规场景的扩展点。

关键词:ALTER TABLE,hook,审计,PG17 | 来源:202308/20230817_01.md

Q:PostgreSQL 17 的 backtrace_on_internal_error 是什么?

backtrace_on_internal_error 是 PG17 新增 GUC,在发生 XX000 内部错误时自动打印 backtrace(调用栈),帮助定位内核 bug 的触发路径。此前内部错误只有错误码和消息,无调用栈,提交 bug 报告时信息不足。开启后能捕获崩溃/内部错误的调用栈,是内核调试和问题反馈的重要辅助。

关键词:backtrace_on_internal_error,XX000,调用栈,PG17 | 来源:202401/20240101_03.md

Q:PostgreSQL 17 的 builtin collation provider 是什么?

PG17 新增 builtin collation provider,提供一种内置的、不依赖 libc 也不依赖 ICU 的排序规则。它解决了 ICU 库版本变化导致排序不稳定、以及不同环境下排序结果不一致的问题。builtin provider 提供稳定、可迁移的排序行为,适合对排序确定性要求高的场景(如索引一致性、跨环境迁移)。

关键词:builtin,collation provider,排序,PG17 | 来源:202403/20240314_06.md

Q:PostgreSQL 17 的 event_triggers GUC 是什么?

event_triggers 是 PG17 新增的 GUC,可临时禁用事件触发器(set event_triggers = off),用于在需要绕过 DDL 事件触发逻辑的维护操作中。事件触发器会在 DDL 时执行自定义逻辑,有时会干扰批量 DDL 或迁移;临时关闭可避免干扰,完成后重新开启。这提供了对事件触发器的运行时控制。

关键词:event_triggers,事件触发器,GUC,PG17 | 来源:202309/20230926_01.md

Q:PostgreSQL 17 的 identity columns in partitioned tables 与 serial 的区别?

identity column(GENERATED ALWAYS AS IDENTITY)是 SQL 标准的自增列,用 sequence 实现但语义更规范、不能轻易被显式插入覆盖(BY DEFAULT 除外);serial 是 PG 传统的语法糖,等价于 int + sequence + default nextval,历史包袱较重。PG17 让 identity 列可用于分区表。推荐新表用 identity 替代 serial,符合标准且更安全。

关键词:identity,serial,自增列,GENERATED AS IDENTITY | 来源:202401/20240118_02.md

Q:PostgreSQL 17 的 pg_basetype 函数是什么?

pg_basetype(oid) 用于获取 domain 类型的基本类型,例如一个 email domain 基于 text,pg_basetype 返回 text 的 OID。domain 是带约束的别名类型,很多操作需要知道其底层基类型。PG17 提供该函数简化了 domain 到基类型的解析,方便在元数据处理、类型兼容判断时使用。

关键词:pg_basetype,domain,基类型,PG17 | 来源:202404/20240401_03.md

Q:PostgreSQL 17 的 pg_basetype 和 domain 类型系统什么关系?

domain 是带约束的别名类型,底层有基类型(basetype)。pg_basetype 函数返回 domain 的基类型 OID,用于类型系统里从 domain 解析到真正的存储类型。这在元数据处理、类型兼容判断、动态 SQL 生成时有用——需要知道 domain 底层是什么类型才能做正确操作。

关键词:pg_basetype,domain,基类型,类型系统,PG17 | 来源:202404/20240401_03.md

Q:PostgreSQL 17 的 pg_input_is_valid 和 pg_input_error_info 是什么?

PG17 预览新增 pg_input_is_valid(text, type) 检测字符串能否自动转换为目标类型,pg_input_error_info 返回转换失败的具体错误信息。这替代了手工 try-cast 或正则预校验,用于数据清洗、导入前预检、动态类型判断等场景,让“这个值能不能转成 date/int”的判断变得简单可靠。

关键词:pg_input_is_valid,pg_input_error_info,类型转换,预检,PG17 | 来源:202310/20231016_04.md

Q:PostgreSQL 17 的 pg_replication_slots.conflict_reason 是什么?

PG17 的主库 pg_replication_slots 视图新增 conflict_reason 字段,跟踪逻辑复制冲突原因(如 update/delete 冲突、行不存在等)。当逻辑复制订阅端报冲突时,发布端能记录冲突类型,帮助定位数据不一致的来源。这增强了逻辑复制的冲突诊断能力,配合订阅端冲突检测使用。

关键词:pg_replication_slots,conflict_reason,逻辑复制冲突,PG17 | 来源:202401/20240104_03.md

Q:PostgreSQL 17 的 plpgsql 支持 %TYPE %ROWTYPE 数组变量,如何用?

PG17 起 plpgsql 可声明与列类型绑定的数组变量,例如 DECLARE v_arr mytable.col%TYPE[]; 或 v_rows mytable%ROWTYPE[];。这样数组元素类型随表结构自动变化,无需硬编码类型名。它让函数处理表数据时更健壮,表结构变更(改列类型)后函数无需改动。

关键词:%TYPE,%ROWTYPE,数组,plpgsql,PG17 | 来源:202008/20200814_02.md

Q:PostgreSQL 17 的 table AM 增强与 undo-based AM 有什么关系?

PG17 频繁提交 table access method 相关 patch,包括自定义 reloptions、SET ACCESS METHOD 支持 DEFAULT 等,说明 undo-based table access methods(如 zheap)在持续推进。undo-based AM 用 undo 日志替代 vacuum 清理死版本,是 PG 摆脱 vacuum 膨胀问题的长期方向。这些 patch 为未来 undo AM 落地铺路。

关键词:table AM,undo,zheap,PG17 | 来源:202403/20240326_03.md

Q:PostgreSQL 17 的 table AM 自定义 reloptions 是什么?

PG17 增强 table access method(表访问方法)框架,支持自定义 reloptions(表级选项),让自定义存储引擎能定义自己的表参数。table AM 是 PG 可插拔存储引擎的接口(如 heap、zheap 尝试的 undo-based AM)。自定义 reloptions 让新 AM 有更完整的配置能力,是存储引擎可插拔化的一步。

关键词:table AM,reloptions,可插拔存储,PG17 | 来源:202404/20240409_05.md

Q:PostgreSQL 17 的 transaction_timeout 参数是做什么的?

transaction_timeout 用于限制单个事务的最长持续时间,超过设定值(如 10s)事务会被自动中止,防止长事务长期占用资源、阻塞 vacuum、拖慢快照清理。它与 statement_timeout(单条语句)、idle_in_transaction_session_timeout(事务内空闲)互补,分别针对事务总时长、语句时长和空闲等待。PG17 引入,适合为失控的长事务兜底,避免业务 bug 造成连接和锁堆积。

关键词:transaction_timeout,长事务,超时,PG17 | 来源:202401/20240125_01.md

Q:PostgreSQL 17 的 uuid 相关函数增强了什么?

PG17 增强 UUID 功能:支持提取 UUID 值内的时间戳(解析 UUID v1 的时间位),以及生成指定版本(v1/v4 等)的 UUID 函数。这方便在 UUID 上做时间范围分析、判断 UUID 版本。配合 pg_idkit 插件可获得各种 UUID 生成方法(UUIDv4/v7、ULID、NanoID 等)的大集合。

关键词:uuid,时间戳提取,pg_idkit,PG17 | 来源:202312/20231224_01.md

Q:PostgreSQL 17 的自定义等待事件是什么?

PG17 支持自定义等待事件,允许扩展定义自己的 wait event 名称和含义,纳入 pg_stat_activity 的 wait_event 体系。此前等待事件由内核固定定义,扩展无法新增。支持后,扩展的阻塞点能被监控工具识别,提升可观测性。配合 pg_wait_events 视图可查看所有等待事件的定义。

关键词:自定义等待事件,wait_event,pg_wait_events,PG17 | 来源:202308/20230822_01.md

Q:PostgreSQL 18 的 CREATE FOREIGN TABLE 支持 LIKE 语法是什么?

PG18 的 CREATE FOREIGN TABLE 支持 LIKE 语法,可以基于已有表(含外部表)的结构创建新的外部表,继承列定义。此前 LIKE 只支持普通表,外部表需手工罗列列。支持后,创建结构相同的外部表更便捷,尤其做 FDW 分片、多外部表对齐结构时。

关键词:CREATE FOREIGN TABLE,LIKE,外部表,PG18 | 来源:201903/20190320_01.md

Q:PostgreSQL 18 的 NUMA 感知和 AIO 是配套的存储演进吗?

两者都是 PG18 向现代硬件架构演进的组成部分:AIO/io_uring 解决 I/O 阻塞(异步 I/O),NUMA 感知解决多路服务器跨节点内存访问延迟。它们共同目标是让 PG 更好地利用 NVMe、多路 CPU、大内存等现代硬件,提升高并发和大数据量下的吞吐。PG19 继续推进 AIO worker 池调优和 io_uring 优化,是持续演进的方向。

关键词:NUMA,AIO,存储演进,PG18 | 来源:202504/20250408_01.md

Q:PostgreSQL 18 的 NUMA 感知能力是什么?

PG18 预览引入 NUMA(非一致性内存访问)感知能力,让 PG 能识别 CPU 与内存节点的拓扑,把相关内存分配和进程调度贴近所在 NUMA 节点,减少跨节点内存访问延迟。在多路服务器上,跨 NUMA 访问内存明显更慢,NUMA 感知能提升大规模并行和大内存场景的性能,是 PG 向现代硬件架构适配的一步。

关键词:NUMA,内存访问,多路服务器,PG18 | 来源:202504/20250408_01.md

Q:PostgreSQL 18 的 NUMERIC scale 支持 -1000 到 1000 是什么意思?

PG15 起 NUMERIC(precision, scale) 的 scale 支持范围扩大到 -1000 到 1000(此前 scale 不能为负)。scale 为负数时表示小数点左侧舍入,如 scale=-2 表示精确到百位。这增强了对大数、货币精度、科学计数等场景的表达能力,让 NUMERIC 的精度控制更灵活。

关键词:NUMERIC,scale,精度,PG15 | 来源:202107/20210727_03.md

Q:PostgreSQL 18 的 OAuth 认证与 OAuth HBA 选项是什么?

PG18 支持 OAuth 2.0 认证,PG19 又增强 OAuth 认证,细化 HBA 级别的选项配置和调试机制。HBA 里可配置 OAuth 的 IdP、client、scope 等选项,控制 OAuth 认证的细节,并提供调试信息输出。这让 OAuth 认证可精细配置、可排障,满足企业 SSO 集成的合规和运维需求。

关键词:OAuth,HBA,认证,SSO,PG18 | 来源:202502/20250221_03.md

Q:PostgreSQL 18 的 OID 64 位与 pg_upgrade 的关系?

OID 升级到 64 位是 PG 底层对象标识的重大变更,涉及系统表和 catalog 结构,pg_upgrade 跨版本升级时需处理 OID 宽度变化。这是 PG 长期演进的一部分,与“高 churn 场景 OID 耗尽”的痛点相关。用户需关注升级路径和相关工具的兼容性。

关键词:OID,64位,pg_upgrade,PG19 | 来源:202403/20240306_01.md

Q:PostgreSQL 18 的 OLD/NEW RETURNING 支持什么?

PG18 预览在 DML 的 RETURNING 子句中支持 OLD 和 NEW 别名,可以在 UPDATE/DELETE 时同时返回更新前(OLD)和更新后(NEW)的值,例如 UPDATE t SET x=x+1 RETURNING OLD.x, NEW.x。此前 RETURNING 只能访问新值,无法拿到旧值,需借助触发器或额外的 UPDATE…RETURNING 绕道。这对审计、变更数据捕获(CDC)和乐观锁校验很有用。

关键词:RETURNING,OLD,NEW,UPDATE,DELETE,PG18 | 来源:202401/20240125_01.md

Q:PostgreSQL 18 的 SIMD 提升 JSON 字符串转义性能是什么?

PG18 预览用 SIMD(单指令多数据)指令优化 JSON 字符串转义/反转义,利用 CPU 向量指令一次处理多个字符,批量检测需转义的字符,替代逐字符扫描。这对 JSON 序列化/解析这类字符密集操作有明显加速,降低 CPU 开销,是 PG 利用现代 CPU 指令集的优化之一。

关键词:SIMD,JSON转义,性能,PG18 | 来源:202408/20240808_02.md

Q:PostgreSQL 18 的 WITHOUT OVERLAPS 唯一约束和 PERIOD 外键约束是什么?

WITHOUT OVERLAPS 让 PRIMARY KEY 或 UNIQUE 约束对 range 类型表达“值不相交”,例如唯一约束 (room_id, during WITHOUT OVERLAPS) 表示同一房间的时间范围不允许重叠,替代了传统用 exclude 约束的写法。PERIOD 外键约束则要求外键的时间范围必须被主键已有值的范围覆盖。这两个是 SQL:2023 时态约束特性,PG18 正式引入,把时态数据的完整性约束从手工 exclude 语法升级为标准语法。

关键词:WITHOUT OVERLAPS,PERIOD,时态约束,range,外键,PG18 | 来源:202509/20250926_09.md

Q:PostgreSQL 18 的 array_sort 函数是什么?

array_sort 是 PG18 预览新增的数组排序函数,对数组元素按默认排序规则排序返回,替代此前需 unnest 展开再排序再聚合的繁琐写法。它支持对整数、文本等类型数组排序,让数组内排序一行搞定,提升可读性和性能。

关键词:array_sort,数组排序,PG18 | 来源:202504/20250403_02.md

Q:PostgreSQL 18 的 async IO 与 effective_io_concurrency 的关系?

effective_io_concurrency 是同步预取(prefetch)的并发度参数,位图扫描时提前发多个 I/O 请求;而 async IO(io_uring)是真正的异步 I/O 框架,进程发出 I/O 后不阻塞等待。两者目标都是提升 I/O 并行性,但机制不同:预取是“提前读”,异步 I/O 是“非阻塞提交”。PG18 提高 effective_io_concurrency 默认值到 16 与 AIO 框架引入并行推进。

关键词:async IO,effective_io_concurrency,预取,PG18 | 来源:202503/20250313_02.md

Q:PostgreSQL 18 的 check/foreign key 约束 NOT ENFORCED 是什么?

PG18 预览支持为 check 和 foreign key 约束引入 NOT ENFORCED(假设为真、不强制校验)选项,即声明约束但不实际执行检查。这主要用于数据仓库或已清洗数据的场景:约束仅作为元数据/查询优化提示存在,减少写入时校验开销。它借鉴了其他数据库(如 Snowflake、Postgres 分支)的做法,社区对此有“妥协”讨论,因为不强制校验意味着约束可能被违反,只适合可信数据源。

关键词:NOT ENFORCED,check约束,外键,PG18 | 来源:202401/20240125_01.md

Q:PostgreSQL 18 的 copy 物化视图 to 是什么?

PG18 预览支持 COPY (SELECT … FROM 物化视图) TO 或直接 copy 物化视图导出,把物化视图内容作为 COPY 数据源。此前 COPY 只能作用于表或查询,物化视图需额外 SELECT。该特性让物化视图的导出(备份、交换、离线分析)更直接。

关键词:COPY,物化视图,导出,PG18 | 来源:201903/20190331_11.md

Q:PostgreSQL 18 的 effective_io_concurrency 默认值调整意味着什么?

PG18 预览把 effective_io_concurrency 和 maintenance_io_concurrency 默认值从 1 提高到 16,适配现代 SSD/NVMe 的高并发 I/O 能力。effective_io_concurrency 控制位图堆扫描时预取的并发 I/O 数,maintenance_io_concurrency 控制维护操作(如 vacuum、analyze)的预取。默认值提高让新装库在 SSD 上自动获得更好的 I/O 并行性,但机械盘环境可能需调回较低值。

关键词:effective_io_concurrency,maintenance_io_concurrency,预取,PG18,SSD | 来源:202503/20250313_02.md

Q:PostgreSQL 18 的 explain 增强 window 函数输出是什么?

PG18 预览增强 EXPLAIN,在窗口函数节点输出更详细的信息(如窗口规格、排序、帧等),让 DBA 能看到窗口计算的执行细节,辅助分析窗口查询的性能瓶颈(如是否额外排序、帧范围多大)。这对优化复杂分析查询(大量窗口函数)很有价值。

关键词:EXPLAIN,window函数,执行计划,PG18 | 来源:202503/20250312_02.md

Q:PostgreSQL 18 的 file_copy_method(COPY/CLONE)是什么?

PG18 预览新增 file_copy_method 参数,支持 COPY(传统拷贝)和 CLONE(写时复制 COW)两种文件复制方式。CLONE 利用文件系统的 reflink(如 XFS/Btrfs 支持),复制文件时不真正拷贝数据块,只在修改时才复制,大幅加速大文件复制(如备份、建库、表空间拷贝),节省磁盘空间和 I/O。

关键词:file_copy_method,CLONE,COW,reflink,PG18 | 来源:202504/20250409_01.md

Q:PostgreSQL 18 的 gamma() 和 lgamma() 函数是什么?

gamma(x) 返回伽马函数值,lgamma(x) 返回伽马函数绝对值的自然对数,是 PG18 预览新增的数学函数。它们补齐了 PG 在特殊函数(gamma 函数是阶乘在实数域的推广)方面的不足,服务于统计分析、科学计算、概率建模等场景。

关键词:gamma,lgamma,伽马函数,PG18 | 来源:202503/20250327_01.md

Q:PostgreSQL 18 的 int 和 bytea 互转是什么?

PG18 预览支持 int 与 bytea 互相转换,例如把整数编码为字节串或从字节串解码出整数,用于二进制数据处理、协议解析、序列化等场景。此前这类转换需要手工写位运算或借助第三方函数。内置转换让 PG 在数据序列化/反序列化、与外部二进制系统对接时更方便。

关键词:int,bytea,转换,序列化,PG18 | 来源:201911/20191108_02.md

Q:PostgreSQL 18 的 log_connections 模块化是什么?

PG18 预览增强 log_connections,精细记录用户连接的各个阶段信息(如连接建立、认证开始/成功/失败、SSL 协商等),模块化输出便于判断连接卡在哪一步。此前 log_connections 只打印连接建立和断开,认证细节要另看日志。模块化后,定位连接慢、认证失败、SSL 握手问题更直观。

关键词:log_connections,连接阶段,认证,PG18 | 来源:202104/20210407_07.md

Q:PostgreSQL 18 的 max_files_per_process 更新与 io_uring 什么关系?

PG18 更新 max_files_per_process 的默认值和逻辑,为异步 IO(io_uring)做准备。io_uring 用固定数量的 ring 提交队列,替代大量打开的文件描述符,减少 fd 占用和系统调用。因此 max_files_per_process 的默认值调整,配合 AIO 框架,让 PG 更高效管理文件。这是 AIO 落地的前置准备工作。

关键词:max_files_per_process,io_uring,AIO,PG18 | 来源:202503/20250325_01.md

Q:PostgreSQL 18 的 min/max_protocol_version 连接协议控制是什么?

PG18 预览新增 min_protocol_version / max_protocol_version,控制允许连接的前后端协议版本范围,提升协议兼容性和安全性。类似 SSL 的 min/max_protocol_version,用于限制连接只能使用指定协议版本,防止过旧或过新的客户端协议接入,便于平滑升级和兼容性管理。

关键词:min_protocol_version,协议版本,PG18 | 来源:201909/20190908_03.md

Q:PostgreSQL 18 的 pg_buffercache_evict 函数是什么?

PG18 预览 pg_buffercache 插件新增 pg_buffercache_evict_relation / pg_buffercache_evict_all 函数,用于主动驱逐 shared buffer 中未 pin 的页(把指定表或所有可驱逐页清出 buffer)。这用于测试 buffer 淘汰、冷热分离、模拟缓存失效等场景,让 DBA 能精确控制 buffer 内容,验证查询在“无缓存”下的真实性能。

关键词:pg_buffercache_evict,shared buffer,驱逐,PG18 | 来源:202504/20250408_09.md

Q:PostgreSQL 18 的 pg_combinebackup 硬链接支持是什么?

pg_combinebackup 用于合并全量+增量备份,PG18 预览支持硬链接(hard link)选项,合并时对未变化的文件用硬链接而非复制,节省空间和时间。这优化了增量备份合并的效率,尤其当多个增量备份共享大量未变数据块时,避免重复拷贝。

关键词:pg_combinebackup,硬链接,增量备份,PG18 | 来源:202503/20250319_01.md

Q:PostgreSQL 18 的 pg_createsubscriber –all 选项是什么?

pg_createsubscriber 用于把物理 standby 转为逻辑订阅者,PG18 预览新增 –all 选项,方便对全实例所有数据库做逻辑订阅,而非逐库指定。这简化了“物理从库平滑切换为逻辑订阅者”的批量操作,配合大版本升级和零停机迁移流程,让全库逻辑复制初始化更省事。

关键词:pg_createsubscriber,–all,物理转逻辑,PG18 | 来源:202503/20250328_07.md

Q:PostgreSQL 18 的 pg_get_acl() 支持 sub-OID(列级权限)是什么?

pg_get_acl() 用于获取对象的 ACL(访问控制列表),PG18 预览支持 sub-OID,能检测列级别的权限。此前 ACL 查询主要针对表级对象,列级权限(GRANT … ON COLUMN)难以通过 pg_get_acl 获取。支持 sub-OID 后,列级权限的审计和查询更完整,补齐了细粒度权限的可观测性。

关键词:pg_get_acl,sub-OID,列级权限,ACL,PG18 | 来源:202407/20240713_02.md

Q:PostgreSQL 18 的 pg_stat_activity 新增 authenticating 状态是什么?

PG18 预览 pg_stat_activity 新增 authenticating 状态,表示会话正在认证过程中,用于检测拒绝服务(DDoS)攻击——大量连接卡在认证阶段说明可能被暴力认证/连接耗尽攻击。此前认证中的连接状态不清晰,难以区分正常连接和恶意连接,新状态让认证阶段的会话可观测、可告警。

关键词:pg_stat_activity,authenticating,DDoS,认证,PG18 | 来源:202407/20240701_04.md

Q:PostgreSQL 18 的 pg_stat_get_backend_io() 函数是什么?

pg_stat_get_backend_io(pid) 是 PG18 预览新增函数,返回指定后端进程的 I/O 统计(读写、扩展、fsync 等次数和时间),把原来只能全局看(pg_stat_io)的 I/O 指标细化到单个会话/进程。这让 DBA 能定位是哪个会话在疯狂读写磁盘,是 I/O 问题排障的有力工具。

关键词:pg_stat_get_backend_io,进程IO统计,PG18 | 来源:202501/20250115_02.md

Q:PostgreSQL 18 的 psql pipeline 流水线模式是什么?

PG18 的 psql 支持 pipeline 流水线模式,允许客户端在一个连接上连续发送多条命令而无需等待每条返回(类似 libpq pipeline mode),减少往返延迟。这对需要连续执行大量独立命令的脚本(如批量建表、批量插入)有显著提速,此前每条命令都要等上一条完成。

关键词:psql,pipeline,流水线,PG18 | 来源:201903/20190331_09.md

Q:PostgreSQL 18 的 range 类型 GiST/B-tree sortsupport 是什么?

PG18 预览为 range 类型增加 GiST 和 B-tree 的 sortsupport 接口,加速 range 值的比较和排序。sortsupport 用更快的底层比较函数替代通用的 SQL 函数调用比较,显著提升 range 列的排序、聚合、索引构建性能。这是 range 类型性能优化的一环。

关键词:range,sortsupport,GiST,B-tree,PG18 | 来源:202001/20200101_07.md

Q:PostgreSQL 18 的 reverse(bytea) 字节流反序函数是什么?

PG18 预览支持 reverse(bytea),对字节串做字节顺序反转,是大端/小端字节序转换的便捷工具。此前 reverse 只支持 text,bytea 需要手工处理。它在二进制协议处理、哈希值存储、字节序调整等场景有用,补全了 bytea 的字符串类操作。

关键词:reverse,bytea,字节序,大端小端,PG18 | 来源:202503/20250314_01.md

Q:PostgreSQL 18 的异步 I/O(AIO / io_uring)框架是什么?

PG18 重磅引入异步 I/O 框架,为基于 io_uring 的异步 I/O 打基础,配套更新 max_files_per_process、改进 buffer manager API。异步 I/O 让 I/O 请求不阻塞后端进程,进程发起读写后可继续执行,完成后回调处理,减少 I/O 等待、提升高并发吞吐。这是 PG 存储引擎现代化的重大演进,PG19 继续做了 AIO worker 池自动调优和 io_uring 内存映射合并。

关键词:AIO,io_uring,异步IO,PG18,PG19 | 来源:202503/20250325_01.md

Q:PostgreSQL 18 的虚拟生成列(virtual generated column)是什么?

PG18 预览支持 virtual generated column,即生成列不物理存储,每次读取时实时计算。相比 stored(写时计算并存储),virtual 省空间,但查询时每次都要计算,且一般不能建索引。virtual 列适合“派生值占用大但很少查询”或“基列频繁更新、不希望冗余存储”的场景,与 stored 形成互补。

关键词:virtual generated column,生成列,PG18,stored | 来源:201911/20191115_02.md

Q:PostgreSQL 19 的 COPY FROM CSV 吃上 SIMD 红利是什么?

PG19 预览让 COPY FROM CSV 数据导入利用 SIMD 指令加速,把 CSV 解析(分隔符识别、转义处理、字段切分)向量化,一次处理多个字节,显著提升批量导入吞吐。CSV 解析是导入的瓶颈之一,SIMD 化让 COPY 导入速度进一步提升,对数据仓库和 ETL 场景是直接的性能红利。

关键词:COPY,SIMD,CSV导入,PG19 | 来源:201903/20190331_11.md

Q:PostgreSQL 19 的 COPY FROM 多行表头是什么?

PG19 预览支持 COPY FROM 命令的多行表头,即 CSV 文件前 N 行都可以作为表头(元信息),而不仅是第一行。这适用于一些导出工具生成的多行表头文件(如带注释、带列分组的多行头)。此前 HEADER 只认一行,多行头需要手工剥离,新特性让 COPY 能直接跳过指定数量的表头行。

关键词:COPY,多行表头,HEADER,PG19 | 来源:201903/20190331_11.md

Q:PostgreSQL 19 的 JSON 变成“数据出口”标准是什么意思?

PG19 预览增强 JSON 的输出能力,从“存储 JSON”进化到“交付 JSON”,让 JSON 成为数据出口的标准格式。例如增强 JSON 构造器、JSON_TABLE、jsonpath,使关系数据能方便地转换为 JSON 输出(API 场景),JSON 数据也能结构化查询。这让 PG 直接服务 API 层,减少应用层的数据格式转换。

关键词:JSON,数据出口,JSON_TABLE,构造器,PG19 | 来源:201903/20190331_06.md

Q:PostgreSQL 19 的 SQL/PGQ 是什么?

SQL/PGQ 是 SQL 标准中属性图查询(Property Graph Query)的语法,PG19 将其并入主干代码,让关系数据库原生支持图查询(MATCH 模式匹配图遍历),图 SQL 回归关系数据库主航道。此前图查询多靠第三方插件(AGE、DuckPGQ)。SQL/PGQ 的引入意味着 PG 无需扩展就能用标准 SQL 语法表达节点、边、路径和模式匹配,是 PG 多模能力(关系+图)的重要里程碑。

关键词:SQL/PGQ,属性图,图查询,MATCH,PG19 | 来源:202203/20220331_04.md

Q:PostgreSQL 19 的 injection_points_list() 函数是什么?

injection_points 是 PG 的代码注入测试框架,用于在指定代码点注入行为(如触发错误、模拟故障)。PG19 预览新增 injection_points_list() 函数列出所有可用的注入点,方便测试人员发现和使用注入点。它服务于内核测试和故障注入(fault injection),让开发者能针对特定代码路径做测试。

关键词:injection_points,代码注入,故障注入,测试,PG19 | 来源:202404/20240409_04.md

Q:PostgreSQL 19 的 pg_dsm_registry_allocations 视图是什么?

PG19 预览新增 pg_dsm_registry_allocations 视图,暴露动态共享内存(DSM)注册表的分配情况,便于观察哪些 DSM 段被谁分配、大小如何。DSM 是并行查询、共享内存扩展(如 pg_stat_statements、动态共享内存)的基础。该视图提升了共享内存子系统的可观测性,辅助定位 DSM 泄漏和内存规划。

关键词:pg_dsm_registry_allocations,DSM,共享内存,PG19 | 来源:202507/20250714_10.md

Q:PostgreSQL 19 的 pg_stash_advice 与 hint 有什么关系?

pg_stash_advice 本质是 PG 社区对“执行计划提示”需求的官方化回应,让 DBA 能对优化器施加建议(类似其他数据库的 hint),固定或引导执行计划。PG 长期靠 GUC、统计信息和改写 SQL 间接影响计划,缺乏直接的 hint 机制。pg_stash_advice 提供了一种可控的计划建议手段,用于优化器估错时的应急和稳定性保障,同时避免传统 hint 的硬编码危害。

关键词:pg_stash_advice,hint,执行计划,优化器,PG19 | 来源:202604/20260406_11.md

Q:PostgreSQL 19 的 pg_stash_advice 和 wait for LSN 分别解决什么?

pg_stash_advice 解决优化器估错时的计划干预(给计划戴紧箍咒,类似 hint);WAIT FOR LSN 解决读写分离的一致性读(等待 LSN 回放)。两者都是 PG19 的重要新特性:前者面向查询优化,后者面向高可用读一致性。都体现了 PG 在“可控性”和“一致性”上的增强。

关键词:pg_stash_advice,WAIT FOR LSN,优化器,一致性读,PG19 | 来源:202604/20260406_11.md

Q:PostgreSQL 19 的 pg_stash_advice 是什么?

pg_stash_advice 是 PG19 预览的特性,为查询计划“戴上紧箍咒”,让 DBA 可以给优化器施加建议/提示,影响执行计划的选择(类似 hint 机制)。它提供了一种受控的优化器干预手段,用于在优化器估错、统计信息不足或特殊场景下固定执行计划,避免频繁更改统计信息或改写 SQL。

关键词:pg_stash_advice,优化器提示,执行计划,PG19 | 来源:202604/20260406_11.md

Q:PostgreSQL 19 的 pg_stat_progress_basebackup 新增 backup_type 字段是什么?

PG19 预览在 pg_stat_progress_basebackup 视图新增 backup_type 字段,区分备份类型(全量备份、增量备份等)。这让 DBA 在观察备份进度时能明确当前是哪种备份,配合 PG17 引入的增量备份能力,更好监控不同备份方式的进度和状态。

关键词:pg_stat_progress_basebackup,backup_type,备份进度,PG19 | 来源:202508/20250808_03.md

Q:PostgreSQL 19 的 regdatabase OID 别名是什么?

PG19 预览新增 regdatabase 类型,作为数据库 OID 的别名,类似 regclass、regtype,可直接用数据库名代替 OID 书写,例如 ‘dbname’::regdatabase 解析为数据库 OID。这让数据库 OID 的表示更友好、可读,与已有的 regclass(表)、regnamespace(模式)等 reg* 类型家族一致。

关键词:regdatabase,OID别名,PG19 | 来源:202507/20250714_05.md

Q:PostgreSQL 的 CASEFOLD() 函数是什么,比 LOWER() 强在哪?

CASEFOLD() 是 PG18 预览的增强版 LOWER(),用于大小写不敏感转换,对多字节字符(如中文、Unicode 扩展字符)支持更好,遵循 Unicode 大小写折叠规则(case folding),能处理 LOWER() 覆盖不到的字符。它适合需要严格大小写不敏感比较、检索和排序的国际文本场景,尤其是多语言内容。

关键词:CASEFOLD,LOWER,大小写不敏感,Unicode,PG18 | 来源:202501/20250126_01.md

Q:PostgreSQL 的 COPY 支持 binary 格式吗?

支持。COPY … WITH (FORMAT binary) 使用二进制格式,直接以类型内部表示传输,比 text/csv 更快、更紧凑,且无精度损失(text 格式的浮点数可能有舍入)。缺点是 binary 格式与 PG 版本和类型实现绑定,跨版本或异构系统不通用,且文件不可读。适合 PG 到 PG 的高性能数据迁移、备份导出。

关键词:COPY,binary格式,FORMAT binary,导出 | 来源:201903/20190331_11.md

Q:PostgreSQL 的 DataSketches 近似算法库是什么?

DataSketches 是近似算法库(源自 Apache),提供 HLL、分位数 sketch、频繁项等近似数据结构,用极小内存估算大数据集指标。PG 集成后,可做近似 distinct、近似分位数、top-k 等,适合海量数据的实时分析(如实时 UV、P99 延迟),在误差可接受范围内大幅节省内存和计算。

关键词:DataSketches,近似算法,sketch,分位数,HLL | 来源:202003/20200324_37.md

Q:PostgreSQL 的 Generated Column(生成列)是什么?分哪两种?

生成列(Generated column)是由表达式计算得到的虚拟列,PG12 起支持 stored 类型,即在写时计算并物理存储,例如 c int GENERATED ALWAYS AS (a+b) STORED。PG18 又预览了 virtual 类型(读时实时计算、不占存储)。生成列的值由数据库自动维护,不能直接 INSERT/UPDATE 写入。stored 生成列可用于索引,适合物化派生值;virtual 生成列省空间但每次读取都需计算。

关键词:Generated column,生成列,stored,virtual,PG12 | 来源:201903/20190330_03.md

Q:PostgreSQL 的 HLL(HyperLogLog)近似计算插件是什么?

HLL 是基数估计算法(HyperLogLog),用很小的固定内存估算去重后元素个数(UV、distinct count),误差约 1% 量级。postgresql-hll 扩展提供 hll 类型,支持 hll_add 累加、hll_union 合并、hll_cardinality 求基数。它解决海量数据精确 distinct count 内存占用大、计算慢的问题,适合 UV 统计、留存分析、实时去重等允许近似误差的场景。多个 HLL 可 union 合并,支持跨天/跨分区聚合。

关键词:HLL,HyperLogLog,近似基数,UV,去重 | 来源:202003/20200324_09.md

Q:PostgreSQL 的 Hypothetical-Set Aggregate Functions(假设聚合)是什么?

假设聚合(如 rank、dense_rank、percent_rank、cume_dist 的 WITHIN GROUP 形式)用于计算“如果某值加入数据集,它会排第几”的假设性问题,例如 SELECT rank(90) WITHIN GROUP (ORDER BY score) FROM t 返回 90 分在现有成绩中的排名。它们不聚合实际数据,而是回答假设排序问题,常用于分位数、排名分析。

关键词:假设聚合,WITHIN GROUP,rank,percent_rank | 来源:202401/20240131_02.md

Q:PostgreSQL 的 JOIN … USING 别名(F404 Range variable)是什么?

PG14 支持 SQL:2016 特性 F404,允许给 JOIN … USING 附加别名(AS),用于引用 USING 公共列名。此前 JOIN USING 产生的公共列无法通过别名限定引用。该特性让 USING 连接的公共列在复杂查询中能被明确引用,消除歧义,是 SQL 标准兼容性增强。

关键词:JOIN USING,别名,F404,PG14 | 来源:202104/20210401_02.md

Q:PostgreSQL 的 LIKE ‘%xxx%’ 模糊查询如何加速?

模糊查询 like ‘%xxx%’(前后都有通配符)无法用普通 B-tree 索引,可用 pg_trgm(三字图)或 pg_bigm(双字图)插件建 GIN 索引加速。pg_trgm 对 3 个字符以上的模式效果好,pg_bigm 支持 2-gram,对中文和短词更优。此外全文检索(tsvector + GIN)适合分词场景,倒排索引插件(如 pgroonga)支持更复杂的模糊和 JSON 模糊查询。选择取决于数据是“子串匹配”还是“分词匹配”。

关键词:like模糊查询,pg_trgm,pg_bigm,GIN,pgroonga | 来源:202003/20200330_01.md

Q:PostgreSQL 的 MobilityDB(移动对象)数据库是什么?

MobilityDB 是移动对象数据库扩展,在 PostGIS 基础上增加移动对象(轨迹)类型,支持时空查询(某时刻某对象的位置、轨迹相交、速度计算等)。它把时间维度融入空间类型,适合 GPS 轨迹、车辆船舶、物流追踪等移动数据场景。可配合 citus 大规模处理百亿级轨迹。

关键词:MobilityDB,移动对象,轨迹,时空查询 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 anon(Anonymizer)脱敏插件是什么?

anon 是数据脱敏(Anonymizer)扩展,基于 security label provider,对敏感字段(姓名、身份证、手机号)做匿名化/假名化处理,用于测试环境数据脱敏、满足隐私合规(GDPR、个保法)。它支持多种脱敏策略(随机、掩码、泛化),在数据导出或查询时动态脱敏。相比手工脱敏脚本,anon 更系统、可复用。

关键词:anon,数据脱敏,Anonymizer,security label | 来源:202103/20210324_41.md

Q:PostgreSQL 的 any_value 聚合函数是什么?

any_value 是 PG16 引入的聚合函数,从每个分组返回任意一行的值(不保证是哪个),适合“分组后取任意一个代表值”的场景。它比 min/max 更快(无需比较),也不会像 first_value 那样需要 ORDER BY。典型用途是“每个客户取任意一条联系方式”这类不关心具体取哪条的需求,减少排序开销。

关键词:any_value,聚合,分组,PG16 | 来源:202302/20230224_01.md

Q:PostgreSQL 的 anyelement/anycompatible 多态类型是什么?

anyelement、anyarray、anycompatible 是伪类型(pseudo-type),用于函数参数和返回值声明多态,让一个函数适配多种具体类型。anyelement 要求所有该类型参数实际传入的类型完全一致;anycompatible 系列则允许不同类型通过隐式转换解析出一个公共类型(common type),更宽松。多态类型让函数库(如 any_value、自定义聚合)无需为每种类型写重载,是 PG 扩展点的重要机制。

关键词:anyelement,anycompatible,多态类型,伪类型,common type | 来源:201909/20190901_06.md

Q:PostgreSQL 的 array 类型有哪些常用操作?

array 类型支持:下标访问(arr[1])、切片(arr[1:3])、拼接(||)、包含(@>、<@)、重叠(&&)、unnest 展开、array_agg 聚合、array_remove/array_position 等函数。数组适合存有序小集合,但查询需配合 GIN 索引(对 @>、&&)或 unnest 展开。注意数组不宜存大集合或高频更新的数据,关系模型更合适。

关键词:array,数组,unnest,array_agg,GIN | 来源:201909/20190901_06.md

Q:PostgreSQL 的 clickhousedb_fdw 和 odbc_fdw 是做什么的?

clickhousedb_fdw 让 PG 通过外部表访问 ClickHouse 数据,odbc_fdw/ogr_fdw 访问 SQL Server 等支持 ODBC 的数据源。这些是异构数据源 FDW,让 PG 作为联邦查询入口,跨库 join 和分析不同数据库的数据。选型上,有专门 FDW(如 clickhousedb_fdw、mysql_fdw)优先用专门的,否则用 ODBC 通用接口。

关键词:clickhousedb_fdw,odbc_fdw,异构数据源,联邦查询 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 dblink 和 postgres_fdw 区别,怎么选?

dblink 是早期的跨库查询函数接口(dblink() 函数执行远端 SQL),语法灵活但无法做查询优化、无 pushdown、结果需手动处理;postgres_fdw 是标准 FDW(外部表),支持 pushdown、异步、批量插入,优化器能参与规划,性能更好。新场景优先 postgres_fdw,dblink 仅用于临时、动态远端 SQL 的场景。

关键词:dblink,postgres_fdw,跨库查询,FDW | 来源:202103/20210324_41.md

Q:PostgreSQL 的 ddlx 插件(show create)是什么?

ddlx 插件提供类似 MySQL 的 SHOW CREATE 功能,生成对象的 DDL 语句(表、视图、函数等),方便查看对象定义。它补齐了 PG 缺“show create table”的短板(虽可查 pg_get_*_ddl 或 pg_dump)。ddlx 用 SQL 函数直接返回 DDL 文本,便于脚本化获取对象定义,是对象管理和审计的实用工具。

关键词:ddlx,show create,DDL,对象定义 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 diskquota 磁盘配额插件是什么?

diskquota 是磁盘配额插件,限制 schema、role、表空间等的磁盘使用上限,防止单个用户/业务写满磁盘影响他人。它在多租户共享实例里很重要,配合 cgroup 资源隔离实现完整的租户隔离(CPU/内存/磁盘)。超配额时拒绝写入并告警。

关键词:diskquota,磁盘配额,多租户,隔离 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 domain 类型如何兼容 MySQL 的 year、tinyint、unsigned?

用 domain 定义带约束的别名类型来兼容 MySQL 特殊类型:year 可定义为 int2 加范围约束;tinyint 定义为 int2;unsigned int 定义为 int4/int8 加 CHECK (值 >= 0);zerofill 可用 lpad 格式化输出模拟。domain 不改底层存储类型,只附加约束和显示格式,因此能低成本兼容 MySQL 的列定义语义,迁移时无需改底层数据。

关键词:domain,MySQL兼容,year,tinyint,unsigned,zerofill | 来源:202001/20200106_01.md

Q:PostgreSQL 的 email 类型如何实现?

PG 没有内置 email 类型,可用 domain 定义(CREATE DOMAIN email AS text CHECK (value ~ ‘邮箱正则’))附加格式校验;或用第三方扩展 pgemailaddr 提供专用 email 类型。domain 方案简单灵活、基于 text 存储,校验靠 CHECK 约束;扩展方案类型更专业、附带更多函数。多数场景用 domain + 正则校验即可满足。

关键词:email类型,domain,pgemailaddr,CHECK | 来源:202001/20200106_02.md

Q:PostgreSQL 的 file_fdw 查询日志怎么做?

file_fdw 把文件(CSV、日志)作为外部表查询。查数据库日志:log_destination 配 csvlog,日志落 csv 文件,用 file_fdw(或 log_fdw)建外部表指向日志文件,SQL 查询。PROGRAM 选项可执行外部命令(find、awk)生成数据流。这让“用 SQL 查日志”成为可能,配合过滤、聚合分析日志。

关键词:file_fdw,log_fdw,日志查询,csvlog,PROGRAM | 来源:202103/20210324_41.md

Q:PostgreSQL 的 gdb / VS Code 调试 PG 怎么做?

调试 PG 用 gdb 附加到 backend 进程(需编译带 -g 调试符号、设置断点、跟踪执行),或用 VS Code 配置 launch.json 远程/本地调试。要点:找到对应 backend 进程 PID(pg_stat_activity 的 pid),gdb attach 后设断点(如 ExecInsert、某函数),观察变量和调用栈。配合 backtrace_functions、debug 参数定位内核问题。

关键词:gdb,VS Code,调试,backend,断点 | 来源:202010/20201024_01.md

Q:PostgreSQL 的 geography 和 geometry 类型有什么区别?

geometry 在平面笛卡尔坐标系下计算,适合小范围、投影坐标;geography 在地球球面上计算(大地测量),考虑地球曲率,适合全球范围的经纬度距离和面积计算。geography 计算更准确但更慢,支持的函数少于 geometry。PostGIS 里选型取决于范围:全球/大范围用 geography,局部高精度用 geometry。

关键词:geography,geometry,PostGIS,球面,平面 | 来源:202605/20260526_37.md

Q:PostgreSQL 的 hll 在留存和 UV 统计中的通用用法是什么?

HLL 用于留存/UV 统计:每天对活跃用户生成一个 HLL,跨天留存用 hll_union 合并多天 HLL 后 hll_cardinality 求并集基数,即“这些天总的去重用户数”;留存用户数 = 第 1 天 HLL 与第 N 天 HLL 的交集基数(用公式 A+B-union 近似)。相比精确 count(distinct) 需存全量用户 ID,HLL 只存极小结构,适合亿级 UV 实时分析。

关键词:HLL,留存,UV,union,基数估计 | 来源:202211/20221122_01.md

Q:PostgreSQL 的 imgsmlr 图像相似搜索是什么?

imgsmlr 是图像相似搜索插件,存储图像的特征值(如颜色直方图、GIST 特征),用向量距离计算图像相似度。它配合 PG 的向量能力实现“以图搜图”。相比深度特征(pgvector + embedding),imgsmlr 用传统图像特征,轻量但精度有限,适合简单图像去重和相似检索。

关键词:imgsmlr,图像相似,特征值,以图搜图 | 来源:202212/20221222_04.md

Q:PostgreSQL 的 jsonb 索引有哪两种 GIN 操作符类,怎么选?

jsonb 的 GIN 索引有两种操作符类:jsonb_ops(默认)和 jsonb_path_ops。jsonb_ops 支持 ?、?|、?&、@> 等操作符,索引条目记录每个 key 和 value,索引较大;jsonb_path_ops 只支持 @> 包含操作符,但索引更小、查询更快,因为它只记录 value 的路径哈希。如果查询主要是 @>(包含判断),优先 jsonb_path_ops;需要 ?、?| 等操作符则必须 jsonb_ops。此外还能建表达式索引对特定路径(如 jsonb_col-»‘x’)建 B-tree。

关键词:jsonb,GIN,jsonb_ops,jsonb_path_ops,表达式索引,包含 | 来源:202012/20201226_01.md

Q:PostgreSQL 的 log_fdw 是什么?

log_fdw 是文件 FDW 的应用,把数据库日志(csvlog)作为外部表用 SQL 查询,方便在库内直接检索和分析日志内容。配合 file_fdw 读取 csv 格式日志、program 选项执行外部命令(find 等),实现“用 SQL 查询数据库日志”。这在排查问题时无需登录服务器 grep 日志,可直接 SQL 过滤、聚合。

关键词:log_fdw,file_fdw,日志查询,csvlog | 来源:202103/20210324_41.md

Q:PostgreSQL 的 ltree 存储结构是什么?

ltree 用点分隔的标签路径存储(如 a.b.c),内部用紧凑的路径表示存储,配合 GiST 索引加速祖先/后代、路径匹配查询。ltree 的标签长度和字符集有限制(PG16 扩展到 1000 字符、支持大小写/数字/下划线/连字符)。它适合层次分类、树形路径等场景,是轻量的层次数据方案。

关键词:ltree,存储结构,层次路径,GiST | 来源:202301/20230110_02.md

Q:PostgreSQL 的 ltree 类型是什么,PG16 增强了什么?

ltree 是层次路径类型,用点分隔的标签表示树形路径(如 Top.Countries.Europe.France),支持祖先/后代查询、路径匹配(lquery/ltxtquery),配合 GiST 索引加速。PG16 增强 ltree:支持大小写字母、数字、下划线、连字符,值长度增加到 1000 字符。ltree 适合分类体系、物料编码、组织架构等层次数据。

关键词:ltree,层次路径,GiST,PG16 | 来源:202301/20230110_02.md

Q:PostgreSQL 的 md5hash 插件是什么?

md5hash 插件用 128 位整数存储 MD5 哈希值,替代 text/bytea 存储 32 位十六进制字符串,压缩空间、提升比较和索引效率。MD5 值本质是 128 位,用整数存储比文本小一半以上,且整数比较更快。适合需要大量存储哈希值(如去重指纹、缓存 key)的场景。

关键词:md5hash,128位,哈希存储,压缩 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 parser 和 resolution 有什么区别?

parser(解析器)把 SQL 文本解析为语法树(parse tree),只做语法层面的解析,不检查语义;resolution(解析/绑定)把语法树中的名字(表名、列名、函数名)绑定到实际的数据库对象(OID),做语义分析,生成 query tree。两者是 SQL 处理流水线的两个阶段:先语法后语义,对应 PG 的 raw parser 和 analyze/rewrite 阶段。

关键词:parser,resolution,解析器,语义分析 | 来源:202011/20201107_04.md

Q:PostgreSQL 的 pase 向量相似推荐插件是什么?

pase 是 PG 的向量相似检索插件(阿里云生态),用向量表示特征(用户画像、商品、图像),做相似度检索和推荐。它配合 smlar、pg_trgm 实现“标签+权重相似排序、标签命中率排序”的推荐系统。向量检索是推荐系统的核心技术,PG 内实现可减少数据搬运。

关键词:pase,向量相似,推荐系统,标签权重 | 来源:202004/20200424_01.md

Q:PostgreSQL 的 pg_backtrace 插件是什么?

pg_backtrace 是打印详细错误调用栈的插件,当数据库发生错误时输出 C 层 backtrace,帮助定位错误发生的代码路径。它类似 PG17 内置的 backtrace_on_internal_error,但作为插件可用于更早版本。对内核开发、问题定位、bug 反馈都有用。

关键词:pg_backtrace,调用栈,错误定位 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pg_cgroups 资源隔离是什么?

pg_cgroups 是用户、会话、业务级的资源隔离方案,基于 Linux cgroup 把不同用户/会话/业务的进程放入不同 cgroup,限制其 CPU、内存、IO 等资源配额。这让多租户共享一个 PG 实例时,能隔离“捣蛋鬼”业务对资源的抢占,避免单一业务拖垮整个库。相比独立实例,cgroup 隔离粒度更细、资源利用率更高。

关键词:pg_cgroups,cgroup,资源隔离,多租户 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pg_cheat_funcs 和 pg_dba 常用函数库是什么?

这类插件打包了 DBA 日常常用的工具函数(类型转换、格式化、调试、权限查询等),省去手工创建 UDF。它们提供“开箱即用”的函数集合,提升 DBA 工作效率。属于轻量实用插件,适合快速部署常用功能。

关键词:pg_cheat_funcs,函数库,DBA,工具函数 | 来源:202003/20200324_41.md

Q:PostgreSQL 的 pg_cheat_funcs 扩展是什么?

pg_cheat_funcs 是 DBA 常用的扩展函数库,集合了一批日常运维和开发的小工具函数(如转义、格式转换、调试辅助等)。它把散落的“作弊”函数打包,省去 DBA 手工创建 UDF 的麻烦。属于轻量级实用函数集,适合快速获得常用工具函数。

关键词:pg_cheat_funcs,扩展,工具函数 | 来源:202003/20200324_41.md

Q:PostgreSQL 的 pg_crash 模拟 crash 插件是什么?

pg_crash 是模拟数据库 crash 的插件,用于测试崩溃恢复、主备切换、故障演练等场景。它能人为触发 backend 崩溃或 postmaster 崩溃,验证 HA 机制和恢复流程是否可靠。这是混沌工程(chaos engineering)在数据库测试里的应用。

关键词:pg_crash,故障注入,崩溃测试,混沌工程 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pg_hashids 短 ID 生成器是什么?

pg_hashids 是短唯一 ID 生成器(Hashids 算法),把整数编码成短字符串(如 YouTube 风格的短 ID),并可从短 ID 还原整数。相比 UUID(长且无序),hashids 短、可读、可逆,适合短链接、邀请码、订单号展示等场景。它生成的是可逆编码而非随机,需注意隐私(可还原)。

关键词:pg_hashids,短ID,Hashids,唯一ID | 来源:202003/20200324_22.md

Q:PostgreSQL 的 pg_hint_plan 和 pg_stash_advice 关系是什么?

pg_hint_plan 是成熟的第三方执行计划提示插件,用注释(/*+ SeqScan(t) */)强制指定扫描方式、连接顺序等;pg_stash_advice 是 PG19 预览的官方化计划建议机制。两者目标相同(干预执行计划),但 pg_hint_plan 是插件、功能更成熟,pg_stash_advice 是内核方向。选型上生产环境多用 pg_hint_plan 应急固定计划。

关键词:pg_hint_plan,pg_stash_advice,执行计划,hint | 来源:202604/20260406_11.md

Q:PostgreSQL 的 pg_ivm / pg_imv / pg-trickle 增量物化视图有何区别?

三者都是 PG 的增量物化视图(IVM)方案:pg_ivm 是较成熟的增量物化视图维护扩展,跟踪基表变更增量更新;pg_imv 是实时增量物化视图;pg-trickle 是较新的增量物化视图插件。它们都解决“物化视图只能全量 REFRESH”的痛点,按变更日志(WAL/触发器)只更新受影响的行。选择看功能完整度、性能和维护活跃度。PG 原生 IVM 长期在 wait 列表,尚未落地。

关键词:pg_ivm,pg_imv,pg-trickle,增量物化视图,IVM | 来源:202204/20220420_01.md

Q:PostgreSQL 的 pg_linegazer 代码覆盖测试插件是什么?

pg_linegazer 是 plpgsql 代码覆盖率测试插件,统计存储过程/函数里哪些代码行被执行过,辅助测试覆盖分析。类似代码覆盖工具(如 gcov),但针对 plpgsql 函数,帮助发现未测试的代码分支,提升存储过程测试质量。

关键词:pg_linegazer,代码覆盖,plpgsql,测试 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pg_migrate online DDL with table rewrite 是什么?

pg_migrate 实现 PG 的 online DDL(含表重写),在不锁表的情况下完成需要重写表的变更。它类似 pg_osc,用影子表+增量同步+切换的方式,减少大表 DDL 的停机影响。这类工具解决了 PG 原生 ALTER TABLE 某些变更(改类型、重建表)需 ACCESS EXCLUSIVE 锁重写的痛点。

关键词:pg_migrate,online DDL,表重写 | 来源:202401/20240104_04.md

Q:PostgreSQL 的 pg_prioritize 进程优先级调度插件是什么?

pg_prioritize 是用户进程优先级调度插件,调整不同会话/用户的 CPU 调度优先级(nice 值),让关键业务进程优先获得 CPU。它用 task scheduling 机制隔离优先级,配合资源隔离策略,实现业务分级保障。

关键词:pg_prioritize,进程优先级,调度,资源隔离 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pg_stat_io 视图作用是什么?

pg_stat_io 是 I/O 统计视图,按 backend 类型和 I/O 操作(读、写、扩展、fsync、命中)统计次数和时间。PG16 增强增加 hits 和 IO timing。它是诊断存储性能、buffer 效率的核心视图:能看出哪些操作是瓶颈、命中率如何、fsync 开销多大。配合 pg_stat_get_backend_io 可细化到单进程。

关键词:pg_stat_io,I/O统计,buffer,命中率 | 来源:202303/20230331_08.md

Q:PostgreSQL 的 pg_stat_wal 和 pg_stat_checkpointer 监控什么?

pg_stat_wal 统计 WAL 生成量、写入、同步、满页写等,评估 WAL 活动和写放大;pg_stat_checkpointer 统计 checkpoint 的触发次数、耗时、写 buffer 数,评估 checkpoint 频率和开销。两者配合可分析 checkpoint 导致的性能抖动(checkpoint 时写放大和 IO 尖峰),是调优 checkpoint 参数的依据。

关键词:pg_stat_wal,pg_stat_checkpointer,checkpoint,WAL | 来源:202010/20201003_02.md

Q:PostgreSQL 的 pg_transport / pgtransfer 表传输功能是什么?

pg_transport/pgtransfer 是表传输工具/插件,在不同数据库实例间传输表数据(结构和数据),类似表级导入导出,但更高效。它适合按表粒度做数据迁移、同步,比全库 dump 更灵活。

关键词:pg_transport,表传输,迁移 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pg_trgm_pro 文本相似搜索是什么?

pg_trgm_pro 是 pg_trgm 的增强,提供“包含则返回 1,不包含则计算 token 相似百分比”的语义,用于文本相似度搜索和排序。它比 pg_trgm 的 similarity 更贴近业务语义(包含优先,否则按相似度)。适合“先精确包含、再相似兜底”的搜索场景。

关键词:pg_trgm_pro,文本相似,相似度,包含 | 来源:202101/20210103_01.md

Q:PostgreSQL 的 pg_upgrade –link 和 –copy-file-range 区别?

pg_upgrade 的 –link 用硬链接(不复制数据文件,只建链接),升级最快但要求新旧数据目录在同一文件系统,且升级后旧目录不能删(共享 inode);–copy-file-range 用 copy_file_range 系统调用(COW/reflink),也快且支持写时复制。默认是普通复制(最慢但最安全)。选型:同文件系统且磁盘够用 –link,否则 –copy-file-range,最稳妥用默认复制。

关键词:pg_upgrade,–link,–copy-file-range,硬链接 | 来源:202403/20240306_01.md

Q:PostgreSQL 的 pg_waldump 和 pg_walinspect 区别?

pg_waldump 是命令行工具,解析 WAL 文件内容(record 类型、relation、LSN),需在 OS 执行;pg_walinspect 是 PG15 的 SQL 接口,用函数在库内解析 WAL。两者功能类似(查看 WAL 内容),pg_walinspect 更便捷(SQL 调用、可 join 分析)。用途:排查复制延迟、WAL 膨胀、逻辑解码问题。

关键词:pg_waldump,pg_walinspect,WAL解析 | 来源:202204/20220411_01.md

Q:PostgreSQL 的 pgbench 压测工具用法要点是什么?

pgbench 是 PG 内置压测工具,支持内置测试(TPC-B 类似)和自定义脚本(-f)。要点:-c 客户端数、-j 线程数、-T 时长、-M prepared 使用绑定变量、-n 跳过 vacuum、-r 报告每条语句延迟、-P 周期输出进度。自定义脚本用 \set 定义变量、\gset 存查询结果、random/permute 生成随机数据。压测要预热、控制变量、观察 TPS/延迟分布。

关键词:pgbench,压测,TPS,延迟,-M prepared | 来源:201903/20190331_07.md

Q:PostgreSQL 的 pgreplay / sqlreplay 负载回放是什么?

pgreplay 是 SQL 回放工具,把数据库的日志(csvlog)或审计日志解析成 SQL 语句,按原始时间节奏重新执行,用于模拟真实负载、性能测试、升级前验证。它保留了原始 SQL 的执行顺序和时延分布,比随机压测更能还原生产负载。适合在测试环境回放生产日志,评估升级、调参、扩容的效果。

关键词:pgreplay,负载回放,SQL回放,csvlog | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pgroonga 外部加速器全文检索是什么?

pgroonga 基于 Groonga 全文检索引擎,作为 PG 的外部加速器,提供高性能全文检索,支持中文、日文等多语言分词,以及 JSON 模糊查询。相比内置 tsvector,pgroonga 分词更智能(无需手工配置词典)、支持更多语言,适合对全文检索质量要求高的场景。它是 PG 全文检索的重要增强方案。

关键词:pgroonga,Groonga,全文检索,中文分词 | 来源:202003/20200324_19.md

Q:PostgreSQL 的 plotpg 和 pgcharts 图表化插件是什么?

plotpg 是绘图插件,在数据库内生成图表(如曲线图、散点图);pgcharts 是 SQL 结果图表化插件,把查询结果可视化。它们让 DBA/分析师在库内直接出图,无需导出数据到外部 BI 工具,适合快速可视化分析。

关键词:plotpg,pgcharts,图表,可视化 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 plpgsql %TYPE 和 %ROWTYPE 数组变量是什么?

%TYPE 引用某列的类型,%ROWTYPE 引用某表/游标的整行结构,PG17 预览支持定义 %TYPE 和 %ROWTYPE 的数组变量类型,例如 v_arr col%TYPE[]。这让 plpgsql 里能声明与表结构绑定的数组,随表结构变化自动调整,减少硬编码类型带来的维护成本,提升了函数对表结构的自适应性。

关键词:%TYPE,%ROWTYPE,数组变量,plpgsql,PG17 | 来源:202008/20200814_02.md

Q:PostgreSQL 的 pq_trace(libpq 协议跟踪)是什么?

PQTrace 是 libpq 的协议层跟踪功能,打印 frontend(客户端)和 backend(服务端)之间的协议交互(SQL 发送、结果返回、错误消息)。用于调试客户端驱动、分析协议行为、定位应用与数据库交互问题。是数据库通信层排障的底层工具。

关键词:PQTrace,libpq,协议跟踪,frontend,backend | 来源:202104/20210408_06.md

Q:PostgreSQL 的 range 类型支持哪些操作,PG18 增强了什么?

range 类型(int4range、tsrange、daterange 等)表示区间,支持包含(@>)、相交(&&)、并(+)、差(-)等操作,配合 GiST 索引加速区间查询。PG18 为 range 增加 GiST 和 B-tree 的 sortsupport,加速比较排序。range 常用于会议室时间不交叉、版本有效期、价格区间等场景,配合排他约束实现区间互斥。

关键词:range,区间,tsrange,GiST,sortsupport | 来源:202504/20250403_07.md

Q:PostgreSQL 的 regexp 正则操作符有哪些?

PG 用 POSIX 正则:~ 匹配、* 不区分大小写匹配、! 不匹配、!~* 不区分大小写不匹配,配合 regexp_replace、regexp_matches、regexp_split_to_table 等函数。PG15 起 regexp_xxx 系列对齐 Oracle(REGEXP_SUBSTR、REGEXP_INSTR、REGEXP_COUNT)。正则用于文本清洗、模式提取、校验,注意正则无索引、大文本正则可能较慢。

关键词:正则,,*,regexp_replace,regexp_matches | 来源:202010/20201031_08.md

Q:PostgreSQL 的 rewrite(规则重写器)做什么?

rewrite 阶段在 query tree 生成后,应用规则系统(rule)重写查询,例如视图展开(把视图替换为基表查询)、INSTEAD 规则改写 DML。它把逻辑查询转换为物理可执行的形式,是 PG 查询处理的中间阶段(parser -> analyze -> rewrite -> planner -> executor)。rule 机制和视图都依赖 rewrite。

关键词:rewrite,规则重写,视图展开 | 来源:202503/20250307_01.md

Q:PostgreSQL 的 rule(规则)和 trigger 有什么区别,怎么选?

rule 是查询重写规则,在语句解析后改写查询计划(如视图的 DO INSTEAD 规则),属于语句级、发生在计划生成前;trigger 是事件驱动的存储过程,发生在数据行操作时,是行级/语句级。rule 常用于视图的可更新实现、条件重写;trigger 用于数据校验、审计、复杂逻辑。一般能用 trigger 就别用 rule(rule 语义复杂、易踩坑),rule 主要留给视图内部机制。

关键词:rule,trigger,查询重写,视图 | 来源:202605/20260531_34.md

Q:PostgreSQL 的 sequence 迁移同步怎么做?

序列迁移同步需保证目标库的 sequence 当前值不低于源库,避免新插入值冲突。方法:用 pg_dump 导出时含 sequence setval,或迁移后手工 SELECT setval(‘seq’, (SELECT max(id) FROM t)) 校准。逻辑复制场景 PG15 起支持序列变更复制,主备/双活下自动同步序列值。核心是迁移后校准序列当前值到数据最大值之上。

关键词:sequence迁移,setval,同步 | 来源:202005/20200514_01.md

Q:PostgreSQL 的 set_user 权限控制插件是什么?

set_user 是 ACL 增强插件,提供受控的权限切换功能,允许会话临时切换到指定用户(set_user),用于权限分离、最小权限原则的实施。它比 SET ROLE 更严格,支持密码保护、白名单控制,适合应用连接时从高权限切换到低权限执行业务,降低风险。

关键词:set_user,权限控制,ACL,最小权限 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 smlar 相似文本搜索插件是什么?

smlar 是文本相似搜索插件,支持多种相似度算法(余弦、重叠系数、TF-IDF 等),用于“自助选药、相似人群圈选、相似文本”等业务。它把文本/标签转为向量后计算相似度,配合 GIN 索引加速。相比 pg_trgm 的 n-gram 相似,smlar 更偏向量化相似,适合标签集合的相似匹配。

关键词:smlar,相似文本,TF-IDF,余弦相似 | 来源:202009/20200930_01.md

Q:PostgreSQL 的 table sample 随机采样有哪些方式?

table sample 用于在表上做快速近似随机采样,语法 SELECT … FROM t TABLESAMPLE SYSTEM(10),SYSTEM 按数据页采样、速度快但行数近似;BERNOULLI 按行采样、结果更均匀但更慢。还可加载 tsm_system_rows、tsm_system_time 扩展,前者按目标行数采样(TABLESAMPLE SYSTEM_ROWS(1000)),后者按时间限制采样(SYSTEM_TIME)。相比 ORDER BY random() LIMIT N 全表排序的方式,table sample 不需要排序全表,适合大表快速抽样分析。

关键词:TABLESAMPLE,SYSTEM,BERNOULLI,tsm_system_rows,tsm_system_time,随机采样 | 来源:202005/20200509_01.md

Q:PostgreSQL 的 tbls schema document 工具是什么?

tbls 是数据库 schema 文档生成工具,自动生成对象关系 ER 图、注释、函数等文档。它把数据库结构导出为 markdown/HTML 文档,便于团队理解和维护数据模型。类似“数据库的 README 生成器”,是文档化和知识沉淀的工具。

关键词:tbls,schema文档,ER图,文档生成 | 来源:202203/20220317_01.md

Q:PostgreSQL 的 tsvector 类型和全文检索怎么用?

tsvector 是全文检索的文档向量类型,把文本分词后存储词条+位置,配合 tsquery(查询向量)和 @@ 匹配操作符做全文搜索,用 GIN 索引加速。流程:to_tsvector 生成文档向量、plainto_tsquery/websearch_to_tsquery 生成查询,@ 用 @@ 匹配并可用 ts_rank 排序。支持中文需配置分词(如 zhparser、pg_jieba)。全文检索适合文档、日志、内容搜索,比 like 更智能(分词、词干、权重)。

关键词:tsvector,tsquery,全文检索,GIN,ts_rank,zhparser | 来源:202605/20260531_21.md

Q:PostgreSQL 的 unnest multirange 是什么?

PG14 引入 multirange 类型(多个不相交 range 的集合),PG15 预览 unnest 支持展开 multirange,把它拆成一个个独立的 range 行,例如 unnest(’{[1,3),[5,7)}’::int4multirange) 得到两个 range。这方便对 multirange 做行级处理、与 range 函数联动,是 range 类型家族向多区间场景的扩展。

关键词:multirange,unnest,range,PG15 | 来源:202012/20201224_01.md

Q:PostgreSQL 的压缩函数(zstd/gzip)接口是什么?

PG 提供压缩函数接口:gzip 插件提供压缩/解压 text 和 bytea 的函数;zstd 插件提供 zstd 压缩函数,压缩比和速度通常优于 gzip。这些函数让数据在存入前压缩、取出后解压,节省存储空间。PG14 起内置支持 lz4、zstd(用于 TOAST、WAL、备份),压缩能力从插件走向内核。

关键词:压缩,zstd,gzip,lz4,bytea | 来源:202003/20200324_38.md

Q:PostgreSQL 的字符集与 collate 由什么决定?libc 和 ICU 有什么区别?

字符集(encoding)决定字节如何编码,collate/ctype 决定排序和大小写规则,PG 的 collation 底层可基于 libc 或 ICU。libc 依赖操作系统本地化数据,不同 OS 排序结果可能不一致且无法在运行时更改;ICU 是独立于 OS 的国际化库,支持更多特性(如大小写不敏感、口音不敏感、按拼音/笔画排序),且版本可随数据库迁移。推荐新库优先使用 ICU collation,避免跨平台排序漂移。

关键词:字符集,collate,ctype,libc,ICU,encoding | 来源:201905/20190528_01.md

Q:PostgreSQL 的存储过程(procedure)和函数(function)有什么区别?

函数(function)必须有返回值,可在 SQL 里调用,不能包含事务控制(COMMIT/ROLLBACK);存储过程(procedure,PG11 起)可用 CALL 调用,支持事务控制(内部可 COMMIT/ROLLBACK 管理事务边界),适合需要分步提交的批处理。函数适合计算、可嵌入查询;过程适合复杂的多步事务逻辑。两者在 PG 里都用 plpgsql 等过程语言编写。

关键词:存储过程,procedure,function,CALL,事务控制 | 来源:202009/20200916_01.md

Q:PostgreSQL 的数组元素模糊搜索的倒排索引原理是什么?

数组/JSON 元素的模糊搜索建倒排索引:把每个元素(或元素的 n-gram)作为索引键,指向包含它的行。查询时从索引快速定位候选行,再精确过滤。插件如 parray_gin 直接对数组元素建 GIN,pg_trgm/pg_bigm 对元素文本建 n-gram 倒排。核心是把“包含某个元素/子串”的扫描转为索引查找,避免逐行 unnest 全表扫。

关键词:倒排索引,数组,GIN,n-gram,模糊搜索 | 来源:202003/20200330_01.md

Q:PostgreSQL 的数组模糊搜索如何实现?有哪些插件?

数组元素的模糊搜索(like、正则、前缀)可借助插件:parray_gin 支持数组/JSON 内元素的 GIN 模糊匹配索引;pg_trgm 和 pg_bigm 提供三字/双字图索引加速 like ‘%xxx%’。其中 pg_bigm 支持 2-gram,对短词和中文(2字)比 pg_trgm(3-gram)更友好,能索引更短的查询串。此外数组可 unnest 展开后配合普通索引或 tsvector 全文检索。核心思路是给数组内容建倒排索引,避免逐行展开全扫。

关键词:数组模糊搜索,parray_gin,pg_trgm,pg_bigm,倒排索引 | 来源:202003/20200330_01.md

Q:PostgreSQL 的模糊搜索应用(pg_trgm vs pg_bigm vs pgroonga)怎么选?

pg_trgm 用 3-gram(三元组),适合 3 字符以上的子串模糊匹配和相似度;pg_bigm 用 2-gram,支持更短查询串(2 字符),对中文和短词更友好,但索引更大;pgroonga 基于 Groonga 引擎,支持更复杂的全文检索、JSON 模糊查询和多字节字符。选型:英文长词模糊用 pg_trgm,中文/短词用 pg_bigm,复杂全文+JSON 用 pgroonga。都用 GIN 索引加速。

关键词:pg_trgm,pg_bigm,pgroonga,模糊查询,GIN | 来源:202003/20200330_01.md

Q:PostgreSQL 的物化视图(materialized view)和增量物化视图(IVM)是什么?

普通视图是查询的别名,不存储数据;物化视图把查询结果物化存储,可 REFRESH 刷新,但刷新是整体的(需重建)。PG 原生不支持基于日志的增量刷新,因此有第三方 IVM(增量物化视图维护)方案:pg_ivm、pg_imv、pg-trickle 等,跟踪基表变更,只增量更新受影响的物化行,避免全量刷新。IVM 适合大表上需要近实时、又不想全量刷新的聚合视图场景。

关键词:物化视图,IVM,增量刷新,pg_ivm,pg_imv | 来源:202204/20220420_01.md

Q:PostgreSQL 的窗口函数 frame(帧)如何控制计算范围?

窗口函数在 OVER 子句里用 PARTITION BY 分组、ORDER BY 排序,并用 frame(帧)界定每行参与计算的行范围。帧可用 ROWS(按物理行数,如 ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING)或 RANGE(按值的范围),GROUPS 则按 peer 组。默认帧在无 ORDER BY 时是整个分区,有 ORDER BY 时是 RANGE UNBOUNDED PRECEDING 到 CURRENT ROW。帧是窗口内滑动计算的核心,直接影响累计求和、移动平均等结果。

关键词:窗口函数,frame,帧,ROWS,RANGE,GROUPS,OVER | 来源:201905/20190523_02.md

Q:PostgreSQL 的约束延判 deferrable 是什么,什么场景用?

deferrable 约束允许把唯一、主键、外键、exclude 等约束的检查推迟到事务提交时(SET CONSTRAINTS … DEFERRED),默认是 IMMEDIATE 立即检查。典型场景是成对更新存在相互引用关系的行,比如 A 引用 B、B 引用 A 时,先插任意一边都会违反外键,用 deferrable 约束在事务内先插两边、提交时再统一校验即可。它增加了灵活性,但会推迟错误发现、增大事务提交时的校验开销。

关键词:deferrable,约束延判,SET CONSTRAINTS,外键,IMMEDIATE | 来源:201911/20191128_01.md

Q:PostgreSQL 的自定义类型(CREATE TYPE)怎么用?

CREATE TYPE 定义新数据类型:可定义复合类型(CREATE TYPE … AS (字段列表))、枚举类型(AS ENUM)、或基于内置类型加约束的 domain。复合类型相当于结构体,枚举适合有限取值集合。自定义类型让数据模型更贴合业务语义,配合类型转换函数和操作符可完全定制行为。

关键词:CREATE TYPE,复合类型,枚举,domain | 来源:202001/20200106_02.md

Q:PostgreSQL 的自定义聚合函数的 finalfunc 如何保证只执行一次?

自定义聚合函数由 state transition function(逐行累加)和 final function(最终转换)组成。finalfunc 通常应在整个分组聚合结束后只执行一次,但若写成对每个输入都调用就会错误。正确做法是用 CREATE AGGREGATE 的 SFUNC + FINALFUNC 结构:sfunc 处理每条输入更新中间状态,finalfunc 只把最终状态转为输出值,由聚合执行器保证 finalfunc 仅调用一次。作者曾因理解偏差“以为 finalfunc 会执行多次”,实际聚合框架保证其单次执行。

关键词:自定义聚合,CREATE AGGREGATE,sfunc,finalfunc | 来源:202512/20251201_05.md

Q:PostgreSQL 的随机唯一有范围序列生成器怎么实现?

生成随机、唯一、有取值范围的序列,可用 random() 变换到目标范围 + 唯一约束去重,或用加密洗牌(如 Feistel 置换)实现区间内无重复伪随机。简单做法:generate_series 生成全部候选值,order by random() 打散后取前 N,保证唯一。高性能场景用可逆置换函数(一对一映射)在范围内产生不重复随机值,避免冲突重试。

关键词:随机序列,唯一,Feistel,洗牌 | 来源:202003/20200324_09.md

Q:PostgreSQL 的随机数据生成有哪些方法?

常用方法:random() 生成 01 随机数,可变换为任意范围(100+ceil(random()*400) 生成 100500 整数);gen_random_uuid()(需 pgcrypto)生成 UUID;md5(random()::text) 生成随机字符串;generate_series 批量生成行。PG17 起 random(min,max) 直接生成区间内随机数,PG19 又扩展到 date/timestamp 类型。批量测试数据通常用 generate_series + 这些随机函数一次性生成,避免逐行循环。

关键词:random,gen_random_uuid,generate_series,随机数据,md5 | 来源:202006/20200609_01.md

Q:PostgreSQL 的高效精确数值类型 pg_rational 是什么?

pg_rational 是扩展提供的精确有理数类型,用分子/分母存储分数,避免浮点数的精度损失(如 1/3 在 float 里是近似值)。它适合需要精确分数运算的场景(财务、科学计算)。相比 NUMERIC 用十进制定点,pg_rational 用有理数表示,除法结果精确。代价是运算和存储开销高于普通浮点。

关键词:pg_rational,有理数,精确数值,扩展 | 来源:202003/20200324_21.md

Q:PostgreSQL 递归 CTE 的 recursive_worktable_factor 参数是做什么的?

它设置优化器对递归查询 work table 平均记录数的估算倍数,即评估为非递归初始项的多少倍,默认 10.0。此前该倍数被写死为 10 倍,但不同场景差异很大:图全展开每层可能是上层的 N 倍,而最短路径查询每层只返回 1 条(倍数应接近 1)。调小(如 1.0)适合低扇出的最短路径查询,图分析类可调大,帮助优化器选择更合适的 work table 连接方式。

关键词:recursive_worktable_factor,递归CTE,work table,优化器,PG15 | 来源:202003/20200329_01.md

Q:WITH RECURSIVE 递归 CTE 的 SEARCH 和 CYCLE 语法分别解决什么问题?

SEARCH 子句(PG14)支持广度优先(BREADTH FIRST)或深度优先(DEPTH FIRST)搜索,并按指定列生成搜索序序列号列,方便图式搜索控制遍历顺序;CYCLE 子句用于检测递归中的环,生成标记列指示是否形成环并记录循环路径。它们由 rewriter 改写成现有语法实现。注意 CYCLE 默认已按深度优先计算路径列,若只用深度优先可省略 SEARCH;需要广度优先时再同时写 SEARCH 和 CYCLE。

关键词:WITH RECURSIVE,SEARCH,CYCLE,广度优先,深度优先,环检测,PG14 | 来源:202003/20200329_01.md

Q:为什么 JSON 可能“污染”PostgreSQL 数据库?

JSON/JSONB 若被滥用会带来问题:把大量结构化数据塞进 JSONB 导致查询无法走常规索引、类型约束失效、数据冗余(JSONB 存储比原生类型大)、无 schema 约束易产生脏数据、GIN 索引维护开销大等。JSONB 适合半结构化、灵活 schema 的场景,不应替代关系模型存储强结构数据。合理做法是结构化字段用原生列,仅灵活部分用 JSONB,并配合 jsonpath 和表达式索引。

关键词:JSON,JSONB,滥用,数据模型,索引 | 来源:201903/20190331_06.md

*Q:为什么 where x=round(random()N) 这类查询结果会反常?背后的函数稳定性是什么?

因为 random() 是 volatile 函数,每次调用都返回不同值,导致 WHERE 条件里对每一行重新求值,行为不可预测。PG 把函数稳定性分为三档:immutable(相同入参永远相同结果,可安全用于索引/常量折叠)、stable(同一语句内结果稳定,可优化)、volatile(每次调用都可能不同,禁止大部分优化)。random() 属于 volatile,所以不能放进表达式索引、不能在 planner 里预计算,WHERE 中每次求值都会变。

关键词:函数稳定性,immutable,stable,volatile,random,表达式索引 | 来源:202011/20201120_01.md

Q:为什么窗口函数里不能直接用 DISTINCT(如 count(distinct x) over()),怎么解决?

PG 的窗口函数聚合内部长期不支持 DISTINCT,直接写 array_agg(DISTINCT week) OVER(…) 会报 DISTINCT is not implemented for window functions。解决方法是先用子查询把窗口内需要的行聚合出来,再在外层对聚合结果做 distinct 处理,例如先 array_agg(week) OVER(帧),再在外层用 (SELECT array_agg(DISTINCT unnest) FROM unnest(x)) 去重。本质是窗口聚合是逐行滑动的,distinct 语义与帧边界冲突。

关键词:窗口函数,DISTINCT,count distinct over,帧 | 来源:201908/20190819_01.md

Q:用 PostgreSQL 的 exclude 排他约束如何实现“一对一结伴”(A组和B组结伴后不能再与他人结伴)?

利用 exclude 约束绑定一对一关系:建表时 exclude using gist (id1 with =, id2 with <>),需要先 create extension btree_gist。该约束含义是:在 id1 相同的前提下,id2 不允许出现不同的值,即同一个 id1 只能绑定一个 id2,实现严格的一对一结伴。排他约束本质是“任意两行不满足指定操作符谓词”的通用约束,用 = 和 <> 组合可表达“同组内字段必须相等”这类关系约束,比普通唯一约束更灵活。

关键词:exclude,排他约束,btree_gist,一对一,id1 with =,id2 with <> | 来源:201911/20191128_01.md

Q:用 exclude 约束如何实现“行政区不跨界”和“会议室时间不交叉”?

空间跨界用 exclude using gist (l1 with <>, geo1 with &&) 表示:不同 l1(省ID)的多边形 geo1 不允许相交,即不同省边界不能重叠;会议室时间不交叉用 exclude using gist (room_id with =, tsrange with &&),表示同一会议室的时间范围不允许重叠。这些都需要 btree_gist 和 postgis/gist 范围索引支持。注意同一 ID 内部的多条记录无法用该约束强制不同(例如同一个 l1 内的多条记录仍可相交),这是排他约束按“任意两行”校验的局限。

关键词:exclude,排他约束,行政区不跨界,tsrange,会议室,&& | 来源:201911/20191128_01.md

1.2 查询优化 / 性能(84 条)

Q:48表JOIN的优化中, inner join 与 outer join 在连接顺序上有什么区别?

inner join 可以任意调整连接顺序, 而 outer join 不能随意调整顺序。因此优化时把 INNER JOIN 全部提前到最前面可获得更好性能。开启穷举法后 inner 被提前, 性能飙升; 关闭穷举(调小 join_collapse_limit)后 inner join 不再被优化器优化, 性能变差。DuckDB 对比中 PG 需要人工改写 join 顺序, 而 DuckDB 优化器能自动推理条件。

关键词:多表join;inner join;outer join;join_collapse_limit;穷举;连接顺序 | 来源:202210/20221026_05.md

Q:AQO(Adaptive Query Optimization)的核心思想是什么?

传统 CBO 基于统计信息估计行数, 但多表相关性、复杂谓词、数据倾斜、统计过期都会让估计误差跨 join tree 放大。AQO 的直觉是: 既然执行过类似 SQL, 把上次真实 actual rows 反馈给下次规划, 形成"优化器学习闭环"。AQO 核心目标限定在 cardinality estimation(行数估计), 不是直接生成计划, 最终是否换计划仍取决于 PG 原有 path 搜索和 cost model。它是 PG 扩展+源码补丁组合, 需重新编译并 shared_preload_libraries 加载。

关键词:AQO;自适应查询优化;基数估算;学习闭环;actual rows | 来源:202605/20260531_15.md

Q:Bao 学习型查询优化器如何工作?

Bao 是学习型查询优化器, 通过发出粗粒度查询提示(如 SET enable_nestloop TO off)引导 PostgreSQL 优化器, 用强化学习从错误中学习。由 Bao 服务器(独立 Python 应用)和 PostgreSQL 扩展两部分组成。

关键词:Bao;学习型优化器;强化学习;查询提示 | 来源:202307/20230704_02.md

Q:Bitmap Scan 解决什么问题? 与 Index Scan 的区别?

普通 Index Scan 的弱点是随机回表: 索引项相邻但指向的 heap tuple 分散, 返回几万行时随机读 heap page、重复访问同一 page、频繁 pin/unpin buffer 比顺序扫描还差。Bitmap Scan 用支持 amgetbitmap 的访问方法(btree/gin/gist/brin/hash/sp-gist), 执行期把命中 TID 放进内存 TIDBitmap, 再按物理顺序回表, 减少随机 IO。注意: PG 计划里的 Bitmap Heap Scan 不是原生磁盘 bitmap index。

关键词:bitmap scan;TIDBitmap;随机回表;amgetbitmap;索引扫描 | 来源:202605/20260530_12.md

Q:CBO(基于代价优化)的核心流水线是什么?

CBO 以代价模型为核心: 1) 生成候选路径; 2) 估算每条路径输出多少行(基数); 3) 把 IO/CPU/排序/哈希/并行通信等成本折算成统一 cost; 4) 选择预计代价最低的路径。它牺牲规划时间、模型复杂度与可解释性, 用更多规划期开销换更低执行期开销。选择率 0.01% 时索引扫描很香, 80% 时索引回表可能比顺序扫描还差。

关键词:CBO;代价优化;基数估算;cost model;路径选择 | 来源:202605/20260531_13.md

Q:DuckDB 如何自动消除相关子查询? PostgreSQL 怎么办?

相关子查询可看作参数化子查询, PG 和 SQLite 不自动取消相关性, 优化器对每一行执行一次子查询, 记录越多越慢(如执行9000次)。DuckDB 优化器会自动消除相关子查询(rewrite)。PG 中改写相关子查询提升性能的方法: 1) 用窗口函数改写; 2) 用 JOIN 消除相关子查询。

关键词:相关子查询;DuckDB;窗口函数;query rewrite;子查询消除 | 来源:202305/20230529_01.md

Q:GEQO(遗传查询优化器)解决什么问题? 何时使用?

当 join relation 数达到 geqo_threshold 阈值后, 穷举(动态规划)搜索空间指数级膨胀、规划时间过长, GEQO 用遗传算法(选择/交叉/变异)在有限规划时间内近似找到一个"足够好"的连接顺序, 牺牲优化精度换更快优化速度。仅当查询含大量表连接(通常超过4-5个)、优化时间过长、对计划精度要求不高时使用。很多"偶发慢SQL"是大 join 进入 GEQO 后探索到的 join order 质量变化导致。

关键词:GEQO;遗传算法;join order;geqo_threshold;连接顺序 | 来源:202605/20260531_14.md

Q:HASH JOIN 算法的核心原理是什么? 内存存不下时怎么办?

hash join 假设一边(通常小表)作为 hash table, 由两片内存区域组成: 一片存地址、一片存真实 value(因为 value 可能变长)。内存存得下时直接构建+探测; 内存存不下时走分批(batch)的 hybrid hash join, 把 build/probe 侧拆成多批, 当前批留内存, 其余写临时文件。并行 hash join 同样面临 inner table 能否放进内存的问题。

关键词:hash join;哈希连接;batch;hybrid hash join;work_mem | 来源:202208/20220812_03.md

Q:Nested Loop Join 的工程价值是什么? 什么时候最强/最差?

NestLoop 不是"最笨的双重循环", 其工程价值是把外表当前行的值传给内表路径, 让内表用索引、参数化子查询、Memoize 或其他可重扫节点快速找匹配行。如果外表小、内表有合适索引, 往往是最强路径; 如果外表行数被低估、内表每次全扫, 会把错误放大成灾难。

关键词:nestloop;嵌套循环;参数化路径;memoize;驱动表 | 来源:202605/20260530_22.md

Q:On-Disk Hash Join 是什么? 为什么会出现 Batches: N?

当 hash join 的 build/inner 侧放不进 work_mem*hash_mem_multiplier 预算时, 走多 batch 的 hybrid hash join。EXPLAIN 里的 Batches: 32 说明不是纯内存 hash join, 而是把两侧拆成多批, 当前批留内存、后续批写临时文件。此时瓶颈从 CPU hash 计算变成临时文件 IO、批次数爆炸、数据倾斜、内存参数与并发放大。

关键词:on-disk hash join;batch;临时文件;hash_mem_multiplier;数据倾斜 | 来源:202605/20260530_25.md

Q:PG 写表(insert into select / copy into)为什么还不支持并行?

PG 9.6 开始支持并行, 但 create table as/select into/materialized view 的并行只体现在后面的查询部分, 写入(insert)部分是单进程的 Gather。本质上要解决导入速度, 是系统工程: 即使解决了写入并行, WAL insert 可能又成为瓶颈, 网络存储(尤其云盘)串行写 IO 延迟瓶颈明显。

关键词:写表并行;insert into select;copy;WAL insert;网络存储 | 来源:202405/20240510_01.md

Q:PG15 enable_group_by_reordering 如何提高多列分组聚合性能?

通过调整多列 group by 的列排序顺序, 提高 sort group 性能: 每一次排序尽可能让下一次排序涉及的行顺序调整更少。例如 group by a,b, 若 a 重复值太多应先排 b 再排 a(先排 a 等于白排)。实际场景还需多列统计信息支持, 让优化器选出更优组合, 如 a,b,c distinct 数相同时应排 c,a,b。

关键词:enable_group_by_reordering;group by;排序;多列分组;PG15 | 来源:202204/20220401_01.md

Q:PG16 IO 统计信息大升级的意义?

重点升级 IO 统计颗粒度, 新的统计信息有助于判断如何优化 shared buffer、checkpoint 调度、bgwriter 调度、backend 刷盘等参数, 减少 backend 刷盘带来的 IO 延迟与 IO 操作。原来的统计颗粒度太大, 对参数优化参考价值不大。

关键词:IO统计;checkpoint;bgwriter;shared buffer;PG16 | 来源:202302/20230209_02.md

Q:PG16 enable_presorted_aggregate 解决什么?

PG16 新增 GUC enable_presorted_aggregate, 优化器支持预排序选择, 减少 distinct|order by agg 的显式排序消耗。开启后优化器会优先使用相应字段索引或在前段执行过程优先产出有序结果传输给聚合函数, 通常在字符串有序聚合、选择中位数等聚合时使用排序。

关键词:enable_presorted_aggregate;预排序;distinct;order by agg;PG16 | 来源:202212/20221222_02.md

Q:PG16 explain (GENERIC_PLAN) 的作用?

PG16 支持 EXPLAIN (GENERIC_PLAN) 直接打印带变量 SQL 的通用执行计划。generic plan 可理解为默认(根据数据柱状分布、偏大众的通用)执行计划: 用变量作条件时优化器假设输入是概率较大的值来生成计划。例如某值占 99% 时 where 字段等于某值会用 seqscan 而非索引。

关键词:EXPLAIN GENERIC_PLAN;generic plan;通用执行计划;PG16 | 来源:202303/20230327_02.md

Q:PG16 extend relation 优化提升什么场景?

扩展数据文件瓶颈有三: 1) 扩展时在 shared buffer 申请 page, 无空闲时需驱逐 dirty buffer 触发 wal flush; 2) 扩展期间先写 zero page 再写实际内容(double write); 3) bulk 扩展只平摊了锁成本。优化用 smgrzeroextend() 扩展 page 不使对应 kernel page cache 变脏, 提升批量、高并发写入场景(IoT、时序、数据导入)性能。

关键词:extend relation;数据文件扩展;double write;smgrzeroextend;PG16 | 来源:202304/20230406_01.md

Q:PG16 为什么新增 Parallel Hash Full Join? 此前不支持的原因?

此前不支持 parallel full outer join 的原因是有死锁风险, PG16 增加 PHJ phase PHJ_BATCH_SCAN 处理死锁问题, 从而支持并行 hash full join。

关键词:parallel hash full join;full outer join;死锁;PHJ_BATCH_SCAN;PG16 | 来源:202303/20230331_01.md

Q:PG16 优化 ORDER BY / DISTINCT aggregates 减少排序次数的思路?

未优化前每个聚合函数都要单独排序且不使用索引, 性能差。PG16 优化方法较暴力: 选出一种排序方法覆盖最多的 agg(可采用索引), 覆盖聚合排序数量一样多则选第一种, 并结合 incremental sort 减少排序次数。

关键词:order by agg;distinct agg;incremental sort;PG16;排序 | 来源:202208/20220808_03.md

Q:PG16 优化器支持 Incremental Sort for DISTINCT 是什么?

PG16 让优化器在 DISTINCT 场景也支持 Incremental Sort(增量排序), 如果数据扫描过程已保证部分有序, 则只需对剩余部分排序, 减少大批量数据排序带来的 CPU 开销。

关键词:incremental sort;distinct;PG16;增量排序 | 来源:202301/20230111_02.md

Q:PG17 如何优化 wal insert lock 提升高并发写入吞吐?

通过原子操作减少 wal insert lock 锁冲突, 提升高并发写入吞吐性能。

关键词:wal insert lock;原子操作;高并发写入;PG17 | 来源:202307/20230726_01.md

Q:PG17 用 Merge Append 提升 UNION 性能的原理?

UNION 有去重需求。原优化器把所有子查询结果放一起再处理, PG17 让子查询按 union 字段有序返回, 通过 Merge Append 在 merge 过程中去重(配合 Unique 节点), 有效提升性能。

关键词:merge append;UNION;去重;PG17 | 来源:202403/20240326_02.md

Q:PG17 的 JIT deform_counter 统计什么?

explain analyze 和 pg_stat_statements 增加 JIT deform_counter, 用于区分统计 tuple Deform(元组拆解) 和 ing expression(表达式计算)的耗时, 更细粒度定位 JIT 相关性能开销。

关键词:JIT;deform_counter;tuple deform;pg_stat_statements;PG17 | 来源:202309/20230910_04.md

Q:PG18 fast-path lock 优化了什么?

fast-path locks 是轻量级锁机制, 避免访问共享锁表(Lock Manager)提高性能, 存于 PGPROC。之前 FastPathTransferRelationLocks() 和 GetLockConflicts() 每次迭代都重新计算 fast-path group 并扫描空 group, 造成不必要开销。优化: 减少重复计算、跳过空的 fast-path group, 提升高并发下锁搜索效率。

关键词:fast-path lock;PGPROC;锁;高并发;PG18 | 来源:202503/20250317_02.md

Q:PG18 numeric 乘法算法性能优化?

PG18 优化 numeric 类型乘法算法, 提升 decimal/numeric 运算性能。底层 native numeric 为支持科学计算采用可变长度存储支持超长精确数值, 导致性能下降, PolarDB 开源版有 fixeddecimal/pgdecimal(decimal128/decimal64)插件改进。

关键词:numeric;乘法;decimal;fixeddecimal;PG18 | 来源:202407/20240713_04.md

Q:PG18 如何优化大量分区的规划(plan)阶段性能?

分区表查询时, 对每个未剪枝掉的子分区, 规划器为它克隆父表等价成员(Equivalence Member)并标记 em_is_child, 旧的实现把这些成员都加入父等价类, 子分区数量增加时查找变慢(二次方级别)。补丁改变存储和查找子分区等价成员的方式, 解决规划时间急剧变慢的问题。

关键词:分区表;等价成员;规划性能;Partition Pruning;PG18 | 来源:202504/20250408_08.md

Q:PG18 如何利用 tuple_fraction 优化分区表 Append 节点?

Append 节点合并各分区数据, 之前决定如何扫描每个分区时未充分利用 tuple_fraction(查询只需返回多少比例的元组)。补丁让 Append 累积子路径时考虑 tuple_fraction: 返回结果较少时更积极使用 index scan 和参数化 nestloop, 选择"分数分支"子路径; 需要全部元组时仍选"非分数分支"。

关键词:Append;tuple_fraction;分区表;index scan;nestloop;PG18 | 来源:202503/20250311_02.md

Q:PG18 如何打印正在执行的慢SQL的执行计划?

PG18 内置 pg_log_query_plan(pid) 函数, 可请求将指定 backend 进程当前正在运行的查询计划以 LOG 级别写入服务器日志(不发给客户端)。注意: 语句在函数内执行时只记录最深层嵌套查询的计划; 子事务 abort 后无法记录。此前需要 pg_show_plans、pg_query_state 等插件实现。

关键词:pg_log_query_plan;慢SQL;执行计划;PG18;pg_show_plans | 来源:202407/20240701_05.md

Q:PG18 如何用扩展统计信息提高 hash join bucket 估算准确度?

哈希连接中准确估计哈希桶大小至关重要, 桶数估少会导致哈希冲突增加、降低效率甚至误选 merge join。多列连接时列间存在函数依赖(如城市对应邮编), 若忽略依赖会低估/高估 distinct 值。Commit 6bb6a62f 增加额外阶段: 对包含两个以上 join 子句的情况查找扩展统计信息(CREATE STATISTICS … ndistinct ON x,y,z), 将 join 子句按关系分组做多列估计, 得到更准确的 distinct 值数量, 从而精确估计桶大小。

关键词:hash join;bucket;扩展统计信息;ndistinct;多列连接;函数依赖 | 来源:202503/20250311_03.md

Q:PG18 子查询单列 GROUP BY 统计信息提升的原理?

当子查询只有一个 GROUP BY 列时, 输出变量可视为唯一(unique), 优化器利用这一特性在上层查询做更精确的统计估计, 改善对子查询输出行数和数据分布的估计, 避免低估/高估导致次优计划。

关键词:子查询;group by;统计信息;唯一性;PG18 | 来源:202502/20250220_01.md

Q:PG18 并行 nestloop join 的优化是什么?

PG18 在并行 nestloop join 中优先考虑物化最廉价的 inner path(物化内表), 减少每个 worker 重复扫描内表的代价。

关键词:并行nestloop;物化inner;PG18 | 来源:202407/20240713_01.md

Q:PG18 异步IO(io_uring)带来什么性能提升?

PG18 引入 Linux 特有的 io_uring 机制, 异步 IO 最大的差别是 IO 等待模式: 某些不必等待 IO 返回即可继续的场景, 同步 IO 会阻塞等待。用 nvme 盘(30微秒内)感知小, 但云存储一次 IO 延迟在毫秒级(相差2个数量级), 异步 IO 让云环境重 IO 负载(如 OLAP 查询)性能飙升。PG18 中 AIO 限于读操作, 写保持同步。

关键词:异步IO;io_uring;AIO;云存储;PG18 | 来源:202503/20250327_03.md

Q:PG18 支持重置/设置指定对象统计信息的作用是什么?

pg_upgrade 大版本升级只导元数据不导统计信息, 升级后需 analyze 重新生成, 若生成前业务大量访问可能计划不准; 数据重大变化时统计更新不及时也会计划不准。PG18 增加 pg_clear_relation_stats/pg_set_relation_stats(对象级)及 pg_clear_attribute_stats/pg_set_attribute_stats(列级)函数, 用于重置和设置指定对象统计信息, 为导出/导入/固化统计信息铺路。

关键词:pg_clear_relation_stats;pg_set_relation_stats;统计信息;pg_upgrade;PG18 | 来源:202410/20241012_02.md

Q:PG18 的 Self-Join Elimination 是什么?

Self-Join Elimination 是针对"烂SQL"的一个优化补丁, 当 SQL 中表与自身做 join(自连接)且该 join 不影响结果时, 优化器可以消除多余的自连接, 避免不必要的扫描。

关键词:self-join elimination;自连接消除;PG18;优化器 | 来源:202502/20250218_02.md

Q:PG18 索引启发式扫描如何优化 in/=any(array) 多值匹配?

处理 WHERE column = ANY(array)/column in(…) 时, 原始逻辑对数组每个元素生成扫描键, 若下一个匹配元组在后续页面会立即结束当前扫描并重新从 btree root 下探。当数组元素集中在相邻叶子页时(如 in (1,2,3,4))频繁重启扫描浪费 CPU 和 IO。PG18 启发式扫描: 若原始扫描已从初始叶子页移动到相邻页(说明匹配密集), 不立即结束, 直接在叶子节点步进。

关键词:启发式扫描;in;=any(array);btree;PG18;索引 | 来源:202503/20250324_03.md

Q:PG19 EXPLAIN (IO) 能观测到什么?

这组 commit 在 SQL 层(EXPLAIN ANALYZE IO)和 auto_explain(log_io)暴露 ReadStream 内部 IO 统计: 扫描节点预取了多少数据、实际 IO 请求次数、等待次数、平均预读深度等, 使 DBA 能量化预读效率、识别预读不足或过度预读, 有据可查地调整 effective_io_concurrency/effective_cache_size 等参数, 不再依赖经验猜测。

关键词:EXPLAIN IO;ReadStream;预读;异步IO;auto_explain;PG19 | 来源:202604/20260408_04.md

Q:PG19 ExecProcNodeInstr 内联化优化了什么?

EXPLAIN (ANALYZE, BUFFERS) 会为每个计划节点挂 ExecProcNodeInstr 包装器, 在每个元组经过节点前后记录时间/缓冲区统计, 开启性能分析本身引入显著开销(海量数据可达 10% 以上)。Commit 54400028 将其及核心函数移至同一编译单元并标记 inline, 编译器生成更优代码, 降低 4%~12% 的 EXPLAIN ANALYZE 性能开销, 减少观测副作用。

关键词:ExecProcNodeInstr;内联;EXPLAIN ANALYZE;观测开销;PG19 | 来源:202604/20260408_09.md

Q:PG19 TSC 计时优化如何降低 EXPLAIN ANALYZE 开销?

EXPLAIN ANALYZE/TIMING ON 传统依赖 gettimeofday 等系统调用, 每次调用涉及用户态到内核态切换, 处理大量行时计时开销可达 2 倍。PG19 在 x86-64 上用 CPU 时间戳计数器(RDTSC/RDTSCP)替代系统调用, 开销从 2 倍降到 1.2 倍, TPC-H 的 InstrShowTime 减少约 20%, 并通过 timing_clock_source GUC 允许选择计时源, pg_test_timing 验证选择。

关键词:TSC;RDTSC;计时;EXPLAIN ANALYZE;timing_clock_source;PG19 | 来源:202604/20260408_03.md

Q:PG19 pg_stat_lock 的设计为什么"克制"?

PG19 新增 pg_stat_lock, 首次把锁行为沉淀为可累计、可重置、可对比的统计事实, 解决过去只能"看现场"(pg_locks 等)不能"看趋势"的问题。它只做 cluster 级、按 LockTagType 聚合的统计(5列), 不做按表/按SQL/按会话的高基数明细, 因为锁管理是数据库最敏感的核心路径, 高基数强实时明细会把代价打在并发控制路径上, “为了监控锁先把锁搞慢”。

关键词:pg_stat_lock;锁等待;统计;LockTagType;PG19 | 来源:202603/20260324_03.md

Q:PG19 pg_stat_statements 如何归一化 FETCH 语句?

此前每个不同 FETCH 调用(即使只差提取行数, 如 FETCH 1 c1 与 FETCH 2 c1)都生成唯一 queryId, 大量游标场景产生大量几乎重复条目。Commit bee23ea 将 FETCH 的大小显示为常量归一化, 使不同 FETCH 合并为同一 queryId, 优化游标 SQL 统计的实用性和准确性。

关键词:pg_stat_statements;FETCH归一化;queryId;游标;PG19 | 来源:202507/20250714_06.md

Q:PG19 pg_stat_statements 新增 generic_plan/custom_plan 计数器解决什么?

带参数 SQL 可能走通用计划(Generic Plan, 复用同一计划)或定制计划(Custom Plan, 按每次参数单独生成)。此前 pg_stat_statements 只统计执行次数/耗时, 无法区分走了多少次通用计划、多少次定制计划。新增两个计数器后可分析计划类型分布, 帮助判断参数是否导致计划抖动、是否需要 plan_cache_mode 调整。

关键词:pg_stat_statements;generic plan;custom plan;计数器;PG19 | 来源:202507/20250731_03.md

Q:PG19 为什么 ANTI join 且内表唯一时可启用 Memoize?

Anti join(反连接)用于查找"在一个表存在但在另一个表不存在"的记录, 通常通过 NOT EXISTS / NOT IN / LEFT JOIN…WHERE IS NULL 实现。Commit 0da29e4 允许 ANTI join 且内表唯一时启用 Memoize 算子: 内表唯一意味着同一参数只产生一个结果, 可以用 Memoize 缓存探测结果, 避免重复探测内表, 提升性能。

关键词:anti join;memoize;内表唯一;NOT EXISTS;PG19 | 来源:202507/20250714_07.md

Q:PG19 为什么"异步IO退化成同步IO"反而性能飙升?

io_method=worker 模式下所有后端进程共享一个提交队列, 由全局锁 AioWorkerSubmissionQueueLock 保护。高并发时锁竞争成为新瓶颈, 等待锁的时间甚至超过 IO 本身。Tomas Vondra 的补丁用条件性锁定+智能退化: 如果不能立即获得锁, 就放弃异步直接执行同步 IO, 避免所有进程排队抢同一把锁。

关键词:异步IO;锁竞争;智能退化;io_method;PG19 | 来源:202603/20260314_10.md

Q:PG19 外键检查快速通道如何绕过 SPI 提升性能?

外键检查传统用 SPI 执行 SELECT … FOR KEY SHARE 验证引用完整性, 每行都有完整 CCI(命令计数器递增)和安全上下文切换。快速路径绕过 SPI 直接探测索引: CCI 和安全上下文切换对整个批次只执行一次(批大小 RI_FASTPATH_BATCH_SIZE=64), 因为单行 CCI 不必要、每行探查完全以 PK 表所有者身份运行。

关键词:外键检查;快速通道;SPI;CCI;安全上下文;PG19 | 来源:202604/20260406_01.md

Q:PG19 如何根治 NOT IN 的性能问题(16年顽疾)?

NOT IN 因 NULL 语义(子查询返回 NULL 时整个表达式为假)导致优化器长期无法优化为反连接(anti join), 只能生成 SubPlan: 对外层每一行都执行一次子查询, 无法做全局连接顺序优化, 无法利用 hash/merge join, 索引几乎失效。Richard Guo 提交的补丁解决了 NULL 障碍, 使 NOT IN 可优化为高效反连接, 10万行主表场景下 SubPlan 450ms 以上降到哈希反连接 50ms 以下(约9倍), 百万级时差异可达分钟级 vs 秒级。

关键词:NOT IN;anti join;反连接;SubPlan;NULL语义;PG19 | 来源:202603/20260314_01.md

Q:PG19 的 Eager Aggregation(急切聚合)是什么优化?

Eager Aggregation 是在 JOIN 之前尽可能早地对某个表或子查询做部分聚合(partial aggregation), 再参与后续连接, 最后顶层完成完整聚合, 以减少中间数据量。例如先对 b 按 b.a_id 做 SUM(b.y) GROUP BY b.a_id 再与 a join, 而非先全量 join 再聚合。由 Richard Guo(郭峰) 重构实现, 2017 年 Antonin Houska 提出原型。

关键词:eager aggregation;急切聚合;partial aggregation;join前聚合;PG19 | 来源:202510/20251009_06.md

Q:PG19 的 TID Range Scan 并行解决了什么问题?

此前规划器在"并行顺序扫描"与"非并行 TID 范围扫描"间权衡: 并行 seqscan 有 CPU 并行优势但可能多读磁盘块, 非并行 TID 范围扫描只读所需块但缺 CPU 并行。PG19 引入并行 TID 范围扫描后, 直接获得并行 CPU 优势同时只扫描需要的块, 减少不必要 IO。其思想与 PolarDB epq 一样: 动态分配数据扫描范围, 多劳多得, 不会因某个并行任务慢而拖慢整体。

关键词:TID range scan;并行扫描;PolarDB epq;动态并行;PG19 | 来源:202511/20251127_12.md

Q:PG19 的 planner hook 扩展为未来做什么准备?

三个 patch: 1) 给 pg_plan_query()/planner() 增加 ExplainState 参数; 2) 新增 planner_setup_hook/planner_shutdown_hook; 3) 给 PlannedStmt 增加 extension_state 成员。为增强扩展能力、细粒度计划器调试、接入更多外部优化器/自定义优化器铺路。

关键词:planner hook;扩展点;外部优化器;PG19 | 来源:202510/20251009_12.md

Q:PG19 组提交(group commit)可观测性补丁做了什么?

高并发小事务下, 每个事务 commit 都要刷 WAL 会打爆 IO, PG 用组提交把多个同时提交的事务聚集到一起减少物理 IO。但"多少个事务等待、等多久"难定。PG19 补丁在 WAL flush 前的组提交延迟等待期间报告一个等待事件(wait event), 使组提交是否生效、等待多久可观测, 帮助判断 commit_delay/commit_siblings 等参数设置是否合理。

关键词:组提交;group commit;WAL flush;等待事件;commit_delay;PG19 | 来源:202512/20251210_06.md

Q:PG19 组提交等待事件与 pg_stat_lock 分别补上哪些可观测短板?

pg_stat_lock 补上锁等待的"增量统计"短板(按 lock type 聚合, 可累计可对比); 组提交补丁补上 WAL flush 前组提交延迟等待的观测短板, 两者都让 DBA 从"有现象无累计事实"转向"有趋势画像"。

关键词:可观测性;锁等待;组提交;等待事件;PG19 | 来源:202512/20251210_06.md

Q:Parallel Hash Join 的难点是什么?

难点在共享: 每个 worker 各建一份 hash table 简单但重复 build 侧 CPU 和内存; 共用一张 hash table 则需要用 barrier(屏障) 同步协调多个 backend 协作构建共享哈希表、分配 batch、避免互相踩踏。真正的性能重点不是开更多线程, 而是 hash table 共享方式、分区粒度、cache/TLB、本地内存、同步、内存带宽与数据倾斜之间的平衡。

关键词:parallel hash join;barrier;共享哈希表;并行连接;数据倾斜 | 来源:202605/20260530_26.md

Q:PostgreSQL 并行聚合(Parallel Agg)的三个阶段是什么?

并行聚合把聚合拆成 Partial Agg(worker 侧局部聚合, 把 N 行输入压缩成 G 个局部状态)、Combine Agg(合并各 worker 的部分状态)、Finalize Agg(把合并后状态转成最终结果)。核心思想是 worker 先做局部聚合, 再交给 leader 合并, 避免 leader 单进程 GROUP BY 成为新瓶颈。要求聚合函数必须有正确的 combinefn(如 avg 需合并 sum/count 而非平均值)。

关键词:并行聚合;partial agg;combine agg;finalize agg;combinefn | 来源:202605/20260531_08.md

Q:PostgreSQL 的 Merge Join 需要同时回答哪些问题?

Merge Join 不是简单"两边排序后拉拉链合并", 至少同时回答: 1) 哪些 join 条件能作为 merge 条件; 2) 两侧输入如何获得同一套排序语义; 3) 遇到重复 key 时 inner 已扫过的匹配段如何重新使用(mark/restore); 4) outer join/semi join/anti join/NULL key 如何保持语义; 5) 排序、mark/restore、Materialize、重复 key 重扫的代价由谁估算。看 EXPLAIN 时要注意上游是否有 Sort、inner 是否有 Materialize。

关键词:merge join;归并连接;mark/restore;materialize;重复key | 来源:202605/20260530_23.md

Q:PostgreSQL 的 pg_dropcache 和 pg_buffercache_evict 有什么用?

pg_dropcache 是清理操作系统页缓存的插件(drop cache),pg_buffercache_evict 是驱逐 shared buffer 的函数。两者都用于测试查询在“无缓存”状态下的真实性能(冷启动性能),或模拟缓存失效。它们让 DBA 能精确控制缓存状态,评估缓存命中率对性能的影响,是性能测试的辅助工具。

关键词:pg_dropcache,pg_buffercache_evict,缓存清理,性能测试 | 来源:202103/20210324_41.md

Q:PostgreSQL 脏页通过哪三种机制刷新?

更新/插入先在 shared buffers 内存修改并标记脏页, WAL 先落盘, 表文件延后更新。脏页通过三种机制刷新: 1) 检查点(checkpoint); 2) 后台写入器(background writer, 后台写脏页保持干净缓冲区可用); 3) 用户后端进程刷脏(当后端需要干净 page 但 buffer 不够时自己刷)。

关键词:脏页;checkpoint;background writer;shared buffers;WAL | 来源:202511/20251107_16.md

Q:PostgreSQL 自适应并行扫描(Parallel Seq Scan)如何分工?

多个参与进程通过共享扫描描述符动态领取连续 block chunk: 快的进程领取更多 chunk, 慢的进程不阻塞其他进程; 扫描末尾减小 chunk size 降低长尾。它是运行时领取任务, 而非计划阶段静态平均切段, 避免"每个 worker 从头扫一遍"和"慢者卡住整体"。

关键词:并行seqscan;自适应扫描;chunk;长尾;动态分配 | 来源:202605/20260530_16.md

Q:RBO 与 CBO 的关系? PostgreSQL 主优化器是哪种?

RBO(基于规则优化)用固定规则缩小搜索空间, 如谓词下推、常量折叠、能用索引就用索引。但真实负载中同一规则在不同数据分布下可能完全相反。PostgreSQL 主优化器不是纯 RBO, 而是以规则生成和裁剪候选路径、再用统计信息与代价模型选择路径的 CBO 系统。

关键词:RBO;CBO;谓词下推;常量折叠;规则优化 | 来源:202605/20260531_12.md

Q:SQL 时快时慢(例如 select count 主键 1500万行 要5分钟)怎么排查?

可能原因: 计划、资源、锁、脏数据相关问题, 特别是 IO 或并行计算时的 CPU 资源, 极少是锁冲突。方法: 打开 auto_explain 跟踪执行计划与 io timing; auto_explain 只能跟踪单一 SQL, 要看执行过程中的环境问题可结合 perf insight 思路间歇性采集会话状态(如 pgsentinel 插件), 类似 AWS performance insight 的理念。

关键词:时快时慢;auto_explain;pgsentinel;perf insight;count慢 | 来源:202008/20200826_01.md

Q:TID 扫描路径(tidpath.c)的核心组件是什么?

TID 是行号, 由 blockNum 和 ItemPoint 组成, 如 (103,21) 表示第103号数据块第21行。核心组件: TidPath(直接通过 TID 访问元组)、TidRangePath(通过 TID 范围条件扫描)、RestrictInfo(存储查询条件)。入口 create_tidscan_paths 生成普通/范围/参数化三种 TID 扫描路径; TidQualFromRestrictInfo 分析单个条件是否可用于 TID 扫描。

关键词:TID扫描;tidpath;TidPath;TidRangePath;行号 | 来源:202503/20250328_05.md

Q:explain 执行计划结果如何可视化?

可用 dalibo 开源的 pev2 工具(https://github.com/dalibo/pev2), 支持在线使用 explain.dalibo.com、下载单个 index.html 本地离线使用、或整合到 web 应用, 把 JSON 格式的 explain 计划渲染成可视化树形图。

关键词:pev2;explain可视化;dalibo;执行计划 | 来源:202406/20240626_04.md

Q:fetch with ties 如何解决分页优化 gap 问题?

limit offset 翻页到很后面时, offset 需扫描并丢弃大量记录, 性能差, 常用"位置偏移条件"优化但排序列有重复值会出现 gap。fetch first with ties 新标准: 返回时可超过 limit 数, 把最后一条相同排序值的行都返回, 避免 gap(老标准 limit 需引入 pk/uk 解决)。担心数据倾斜一次返回过多可: 1) 用游标; 2) 把排序字段改成表达式(如加 row 的 hash 值), 减少重复值个数。

关键词:fetch with ties;分页;gap;limit offset;数据倾斜 | 来源:202311/20231111_02.md

Q:io_max_combine_limit 与 io_combine_limit 的区别?

io_combine_limit 控制单个 IO 操作可合并的最大块数(软限制, 最大值增至 1MB); io_max_combine_limit 是新增的硬限制, 用于限制异步 IO 分配共享内存时每个块的数据大小, 减少 AioHandleIov/AioHandleData 内存占用, 为后续扩大 PG_IOV_MAX 做准备。

关键词:io_max_combine_limit;io_combine_limit;IO合并;异步IO;PG18 | 来源:202503/20250319_07.md

Q:optimizer trace 的作用是什么?

帮助理解优化器的优化原理, 生成执行计划的决策过程(parser/rewriter/optimize), 辅助诊断因优化器自身、参数设置、代价校准因子、索引缺失、统计信息不准带来的 SQL 性能问题, 适合 DBA 和开发者。参考 opttrace、hyper-db 等工具。

关键词:optimizer trace;优化器;诊断;代价校准 | 来源:202209/20220923_02.md

Q:or_to_any_transform_limit 参数控制什么?

控制 OR 到 ANY 转换: 当 OR 表达式中参数长度超过该阈值(默认5)时, 优化器尝试查找并分组多个相似的 OR 表达式为 ANY 表达式, 基于变量侧的等价性(一侧为常量、另一侧为变量)。好处是更快的规划和执行, 某些情况产生单次索引扫描而非多次 bitmap scan; 但 distinct OR 较多时可能导致规划退化, -1 完全禁用。

关键词:or_to_any_transform_limit;OR转ANY;PG17;索引扫描 | 来源:202404/20240409_02.md

Q:partitionwise join 和 partitionwise aggregate 的触发条件是什么?

partitionwise join:两个 JOIN 的分区表在 JOIN 字段上分区、分区类型一致(枚举/LIST/范围/HASH)、分区个数一致,且 JOIN 字段类型一致,优化器就选择并行分区智能 JOIN,子分区各自 JOIN 子分区(10 亿 join 10 亿 from 1006 秒降到 76 秒)。partitionwise aggregate:分区表聚合的分组字段为分区字段时,选择并行分区智能聚合(10 亿 from 191 秒降到 8 秒)。两者都通过 enable_partitionwise_aggregate / enable_partitionwise_join 控制,配合 parallel append 让分段结果集尽量小以提升性能。

关键词:partitionwise join partitionwise aggregate 分区裁剪 MPP co-located | 来源:201903/20190317_13.md

Q:pg_dump 导出统计信息功能做了哪些优化?

PG18 支持统计信息导出/导入, 解决大版本升级后需 vacuum analyze 重新生成统计信息的问题。后续 patch 优化了 pg_dump 导出统计信息大量占用内存的问题, 并通过批量查询大幅降低获取统计信息的总时间。

关键词:pg_dump;统计信息导出;大版本升级;内存优化;PG18 | 来源:202504/20250406_04.md

Q:pg_hint_plan / pg_plan_inspector / pg_plan_advsr / pg_store_plans 分别是什么?

四者用于复杂SQL执行计划优化修正: pg_hint_plan 手动强制某些执行计划决策; pg_plan_inspector 外部框架, 通过 explain analyze 获得真实统计信息存外部, 下次执行 feedback 给优化器修正计划(机器学习方法); pg_plan_advsr 内部实现, 不存统计信息而存修正后的 SQL HINT, 相当于内部自动通过 HINT 修正计划; pg_store_plans 像 pg_stat_statements 一样存储执行计划。

关键词:pg_hint_plan;pg_plan_inspector;pg_plan_advsr;pg_store_plans;执行计划修正 | 来源:202207/20220714_02.md

Q:pg_hint_plan 新增的 DisableIndex hint 是什么?

pg_hint_plan 支持 PG18 后新增 DisableIndex hint: 在查询规划时排除指定索引(全部、少部分或正则匹配的索引名), 优先级高于其他 hint, 被禁用的索引即使被 IndexScan 显式请求也不会使用。

关键词:pg_hint_plan;DisableIndex;禁用索引;PG18 | 来源:202508/20250829_08.md

Q:pg_overexplain 插件为 EXPLAIN 增加了什么?

pg_overexplain 为 EXPLAIN 增加两个调试选项: EXPLAIN (DEBUG) 提供更详细调试信息、EXPLAIN (RANGE_TABLE) 显示范围表信息, 解决 debug_print_plan 输出过于冗长的问题, 帮助开发者深入分析查询计划。

关键词:pg_overexplain;EXPLAIN;DEBUG;RANGE_TABLE;调试 | 来源:202503/20250327_02.md

Q:pg_plan_advice 三件套解决什么问题?

解决"优化器抽风时无法精确干预"的悖论: enable_seqscan=off 太粗暴影响其他查询, pg_hint_plan 复杂 JOIN 语法难精确控制。pg_plan_advice 及配套 pg_collect_advice/pg_stash_advice 提供捕获、审视、修改并强制执行查询计划关键决策的能力, 遵循"机制与策略分离", 基于更完美的信息(实际执行经验)做人工干预。

关键词:pg_plan_advice;pg_collect_advice;pg_stash_advice;执行计划;优化器干预 | 来源:202603/20260314_06.md

Q:pg_profile 是什么? 解决什么问题?

pg_profile 是 PostgreSQL 性能基准对比/诊断工具(https://github.com/zubkov-andrei/pg_profile), 弥补 PG 性能诊断工具较弱的短板, 通过采集统计快照做基准对比, 大大提升排查问题的效率。

关键词:pg_profile;性能诊断;基准对比;监控工具 | 来源:202212/20221208_01.md

Q:pg_qualstats 的用途和局限?

pg_qualstats 采集 WHERE 条件统计用于推荐索引。测试发现其推荐 btree 索引较理想, 但 gin/gist/brin/bloom/sp-gist 等接口不理想; 它另一个核心价值是采样并存储过滤性较差的 SQL, 充当"发现过滤性差的 SQL"的角色, 即使没自动推荐索引, DBA 也可用自己的知识优化。配合 HypoPG 使用。

关键词:pg_qualstats;HypoPG;索引推荐;过滤性差 | 来源:202307/20230705_03.md

Q:pg_stash_advice 持久化机制如何工作?

此前 pg_stash_advice 数据存于 DSA 动态共享内存, 重启丢失。Commit c10edb10 引入磁盘持久化: 新增 pg_stash_advice.persist 和 persist_interval 两个 GUC, 通过后台工作进程定期把 queryId→advice_string 映射写入数据目录下 pg_stash_advice.tsv, 重启后自动加载, 实现"一次配置永久生效"。

关键词:pg_stash_advice;持久化;background worker;建议存储;PG19 | 来源:202604/20260408_06.md

Q:read_stream 预读逻辑优化了什么?

read_stream.c 负责在合适时候向内核发 read-ahead advice 优化 IO。之前实现过早放弃发建议, 导致后续读取可能遇到本可避免的 IO stall。优化后改进密集流(dense streams)的预读建议机制; 又简化距离启发式(distance heuristics), 为异步 IO 做准备。

关键词:read_stream;预读;read-ahead;IO;PG18 | 来源:202503/20250317_04.md

Q:什么是 semi-join / anti-join? 数据库未实现时如何模拟?

等值 JOIN 的表达式存在重复值且只需要 JOIN 字段/表达式时, 只查每个值第一条即可跳到下一个值, 常用来优化 in/exists/not exists/=any()/except 等。若数据库未实现半连接, 可用 递归/group by/distinct on/distinct 模拟。实测用递归模拟 SEMI-JOIN, 在 b 表 100万行只有 11 个唯一值的场景下, 改写后从 226.630ms 提升到 0.246ms。

关键词:semi-join;anti-join;递归模拟;exists;not exists;distinct | 来源:202401/20240103_02.md

Q:分页优化的三种模型及其代价边界?

  1. LIMIT/OFFSET: 数过前 N 行再返回后 M 行, 深分页时被跳过的行仍经历扫描/排序/可见性判断, 只是没返回; 2) 服务端游标: 在会话/事务里保存执行状态分批取, 但把应用状态绑在连接和事务上; 3) keyset/seek method(每次递进输入 WHERE 边界): 把上一页最后一行排序键作下一页谓词, 索引从边界继续读, 但失去任意跳页能力。核心是把问题从"我要第几页"改写成"下一批从哪里开始, 能否用索引定位"。

关键词:分页;keyset;offset;游标;深分页 | 来源:202606/20260601_04.md

Q:向量搜索 limit + 距离阈值 where 为什么性能骤降?

向量搜索通常取 TOP N(limit 10)走索引很快。但加 where 距离阈值条件后, 优化器不知道距离操作符的"排序"和"小于"步调一致: 满足条件的记录够 limit 条时没问题, 不足 limit 条时优化器会扫完整个索引直到找不到 N 条, 性能骤降。GiST 索引同样问题。vectorchord 提供 similarity filter 算子, 把距离条件下推至向量索引, 超出距离立即停止搜索。

关键词:向量搜索;limit;距离阈值;similarity filter;vectorchord;性能骤降 | 来源:202508/20250829_10.md

Q:向量搜索优化的三板斧(空间/性能/召回)如何平衡?

向量搜索是近似求解, 在"空间、性能、召回"三方面取平衡, 类似 CAP 无法既要又要。先天优化: 降低维数(128→64)、降低精度(float32→float16/int/bit), 控制空间占用并逼近能容忍的最小召回率; 后天优化: 调整参数(如 ef_search), 在满足召回条数下逼近最小召回率。

关键词:向量搜索;召回;量化;降维;ef_search;pgvector | 来源:202405/20240506_03.md

Q:如何查看 prepared statement 的 generic plan?

prepared statement 参数用位置变量替代, 直接 explain 会报错。PG12 起通过 plan_cache_mode 控制计划选择: generic plan 是适合大多数输入值的通用计划(数据倾斜大时可能不适合某些值), custom plan 按实际输入选最佳。要得到 generic plan 可用 generic-plan 等工具或 EXPLAIN (GENERIC_PLAN)(PG16 内置)。custom plan 需实际输入条件才有意义, 通常用 auto_explain 追踪。

关键词:generic plan;prepared statement;plan_cache_mode;绑定变量;EXPLAIN GENERIC_PLAN | 来源:202211/20221121_01.md

Q:数据分布与扫描方法如何影响 join+order by limit 的性能?

数据的组织+扫描方法决定数据过滤多少与性能极限, 即用索引精准定位且要求完全无 filter。例: gid 1~10 各10万行连续分布, crt_time 顺序写入, 查 gid=9,10 按 crt_time 排序。若按 crt_time 索引顺序扫需过滤80万行无用记录; 优化器选择大表作内表(过滤性更好)、配合 merge sort 才能高效。PG 允许大表作内表, MySQL 则需 STRAIGHT_JOIN 固定。

关键词:扫描方法;数据分布;merge sort;join;order by limit;内表 | 来源:202208/20220826_01.md

Q:数据库整体变慢/慢SQL/性能抖动这三类问题, 分别该怎么分析和优化?

分三类处理: 1) 单一慢SQL: 从执行计划入手, 看计划是否正确、索引是否缺失/不合理、SQL是否需要改写、表是否有膨胀、是否存在锁冲突、SQL是否过于复杂需要固定计划或更高级优化器; 常用工具为 explain analyze、auto_explain、pg_stat_statements。2) 数据库整体变慢: 从资源瓶颈入手(IO/CPU/内存/锁/连接数)。3) 性能抖动: 结合间歇性采集会话状态(如 pgsentinel)、perf 等方法定位瞬时环境问题。同时强调"治未病", 在变慢前就做好监控与建模。

关键词:慢SQL;性能抖动;整体变慢;执行计划;auto_explain;pg_stat_statements;pgsentinel | 来源:202208/20220823_02.md

Q:查询所有传感器最新值的典型慢SQL, 如何通过递归CTE优化?

场景: 查询所有传感器上报数据的最新值, 原方案用外部排序(external merge Disk)且扫描大量数据块, 耗时数千毫秒。优化1: 建 gid,crt_time desc 索引, 避免外部排序但仍大量扫描。优化2: 引入递归查询(CTE recursive, 索引链表跳跳糖), 扫描从几十万个 block 降到 47 个 block, 同时避免排序, 整体耗时从 5508 毫秒降到 0.6 毫秒。

关键词:递归CTE;最新值;索引;慢SQL优化;external merge | 来源:202208/20220823_02.md

Q:编译器 PGO 如何让 PostgreSQL 性能飙升?

PGO(Profile-Guided Optimization)利用程序实际运行时的性能数据指导编译器优化, 相比静态 -O2/-O3 更有针对性。流程: 插桩编译→收集 profile→基于 profile 重新编译。优化点: 分支预测、代码布局、内联、循环优化、去除冷代码、虚函数去虚化、间接调用优化。云 RDS sysbench 结果优于自建可能与此相关。

关键词:PGO;编译器优化;分支预测;内联;代码布局 | 来源:202504/20250423_03.md

Q:自定义统计信息包含哪几层? 解决什么问题?

解决"优化器把列之间、表达式结果、热门组合当成独立且均匀"的问题。四层: 1) 调整单列统计目标(ALTER TABLE … SET STATISTICS); 2) CREATE STATISTICS 创建扩展统计(dependencies/ndistinct/mcv/表达式统计); 3) 用 pg_stats/pg_stats_ext/pg_mcv_list_items() 检查; 4) 用 pg_restore_relation_stats 等临时恢复(会被 autovacuum/analyze 覆盖)。例: tenant_id 与 currency 相关, 当成独立相乘会严重低估/高估行数。

关键词:自定义统计信息;扩展统计;CREATE STATISTICS;mcv;ndistinct;列相关性 | 来源:202606/20260601_16.md

Q:软删除场景 NOT EXISTS 比 EXISTS 快 32 倍的根因?

当"少数派状态"(如 deleted=true 占很小比例)存在时, 用 NOT EXISTS 检查"是否不存在少数派"比 EXISTS 确认"多数派存在"更快, 因为查的是少数派索引, 且大部分查找结果在索引里找不到。对 PG 而言, “索引里找不到通常可直接结束; 找到了反而往往还得回表”, 这正是性能差距根因。

关键词:NOT EXISTS;EXISTS;软删除;partial index;索引回表 | 来源:202603/20260327_01.md

1.3 Vacuum / 存储引擎(83 条)

Q:64 位 XID 改造能解决和不能解决什么问题?

能解决:freeze 风暴根源(不再有半圆快耗尽的焦虑)、autovacuum 必须成功的强约束(XID 不循环,vacuum 慢一点也不致命)、长事务导致停库的极端情况、从库延迟与 freeze 的耦合。不能解决:表膨胀(仍需 vacuum/autovacuum 清理死元组)、长事务本身的回滚代价、长事务持有的锁。即 64 位 XID 消除了 wraparound 风险,但没有改变 MVCC 死元组与膨胀的基本面。

关键词:64位XID freeze 膨胀 长事务 收益 局限 | 来源:202609/20260904_01.md

Q:Arrow 是什么?为什么说它是面向内存和进程 0 拷贝共享数据的列存设计?

Arrow 是一种列式内存数据格式(In-Memory Columnar Format),设计目标是让不同进程/系统之间共享数据时无需序列化/反序列化:数据以连续内存的列缓冲组织,配合零拷贝 IPC,跨进程、跨语言(C++/Python/Java 等)可直接读写同一块内存。它解决了传统行式数据在进程间传递需要序列化、以及列式计算中内存布局不紧凑的问题,是数据分析和向量化执行的底座。

关键词:Arrow 列存 内存 零拷贝 IPC 序列化 | 来源:202501/20250127_01.md

Q:BYPASS_THRESHOLD_PAGES 优化(PG14)如何减少不必要的 index vacuum?

PG14 引入 BYPASS_THRESHOLD_PAGES 优化:当 heap 页中被 LP_DEAD 覆盖的 page 较少(未达到阈值)时,跳过 index vacuum 阶段,避免每次 vacuum 都要扫描一遍所有索引。因为如果 dead tuple 只集中在少量页,索引里的 dead entries 也少,直接跳过索引清理更划算,可显著降低 vacuum 成本。

关键词:BYPASS_THRESHOLD_PAGES PG14 index vacuum 跳过 | 来源:202104/20210408_01.md

Q:FSM(Free Space Map)和 VM(Visibility Map)在垃圾回收中分别解决什么问题?

FSM 记录每个 page 近似有多少 free space,目的是快速找到足够容纳新 tuple 的 page;它不记精确字节,而是每 heap page 一个字节的近似值,组织成树,根节点快速判断有没有足够大的空闲页。VACUUM 扫描时调用 RecordPageWithFreeSpace(),并周期性用 FreeSpaceMapVacuumRange() 向上层传播空闲信息。VM 记录每个 heap page 两个 bit:all-visible 和 all-frozen,用于让 index-only scan 跳过 heap fetch、让 vacuum 跳过已全可见的页面;它是保守结构,bit 设上时必为真,没设不代表一定为假。简言之 FSM 解决’新版本写到哪里’,VM 解决’哪些页面可以少看’。

关键词:FSM VM FreeSpaceMap VisibilityMap all-visible all-frozen | 来源:202606/20260601_07.md

Q:HOT vacuum 收缩链路对 DML where CTID=ctid 安全吗?为什么?

不安全。HOT 更新会把旧版本通过 t_ctid 链指向新版本,vacuum 收缩(清理 HOT 链)后,旧版本的 t_ctid 可能已被回收或指向不可预期的位置。如果用 WHERE ctid = 某个物理行号来做 DELETE/UPDATE,由于 ctid 是物理位置且会被 vacuum/HOT 收缩改变,定位到的行可能已不是预期的那行(甚至已复用给别的行)。因此业务 SQL 不应依赖 ctid 做定位,ctid 只能用于诊断或临时定位,且用完即弃。

关键词:HOT 收缩 ctid 安全 物理行号 DML | 来源:202204/20220401_03.md

Q:Heikki page epoch 方案为什么用 PageLSN 推断 epoch 而不显式存储?有什么 corner case?

LSN 是单调递增的物理时间戳。XID 走过 2^31 边界(进入新 half-epoch)时,在 pg_control 里记录该边界的 LSN;MVCC 解读 tuple 时读 page 的 PageLSN,查 half-epoch 边界表确定 PageLSN 落在哪个 epoch,再用 tuple.xmin + epoch 拼出 64 位 XID。这样 epoch 不用显式存,page 格式 0 字节开销。corner case:完全不更新、不删除的 tuple,其 PageLSN 永远不变,指向的 epoch 可能已走远,此时仍需显式冻结(autovacuum_freeze_max_age = 2*10^9 兜底),但只扫有未冻结 tuple 的 page。由于一个 tuple 在被更新前最多老 2^31,一个 page 上的 tuple XID 最多跨 2 个 half-epoch,pg_control 只需存最近 2 个边界。

关键词:PageLSN epoch pg_control half-epoch freeze corner case | 来源:202609/20260904_05.md

Q:LSM-Tree 的 size-tiered 和 leveled 两种 compaction 策略各自的取舍是什么?

size-tiered:每层 SST 数量有固定阈值(如 4 个),某层达到阈值就把该层所有 SST 合并成一个更大的放上层。优点是简单、SST 数量少、定位快;缺点是空间放大严重(大 SST 合并瞬间磁盘占用可能翻倍,重复 key 多时放大因子可到数倍)。leveled:L0 之外每层 SST 的 key 区间互不相交(一个 run),层间按 10 倍增长,compaction 时只选该层若干文件与下层有交集的合并。优点是空间放大小;缺点是写放大更严重(一对多合并,同等条件下写放大可达 size-tiered 的两倍以上,极端数十倍)。

关键词:size-tiered leveled compaction 空间放大 写放大 LSM | 来源:202411/20241122_01.md

Q:LSM-Tree 的三放大(读放大、写放大、空间放大)分别指什么?

读放大:读取数据时实际读取的数据量大于真正需要的数据量,LSM 里需要从 MemTable 开始逐层向下查多个 SSTable 才能找到 key。写放大:写入时实际写入量大于真实数据量,compaction 会让同一个 key 在向高层沉淀过程中被反复重写,有多少层就写多少次。空间放大:数据占用的磁盘空间比真实大小多,因为 LSM 的增删改都是 append,旧版本要等 compaction 执行到该 key 才会被清理,一个 key 可能同时存在多个 value(删除标记也是特殊 value)。

关键词:LSM 读放大 写放大 空间放大 compaction 三放大 | 来源:202411/20241122_01.md

Q:Lance 列存格式的定位是什么?相比 Parquet 有什么优势?

Lance 是面向 AI/多模态工作负载的现代列式数据格式,定位为’超越 Parquet’。它在列存基础上针对机器学习训练、向量检索等场景做了优化,支持高效的随机访问、向量化读取和版本化(支持追加、更新),并兼容 Arrow 生态。相比 Parquet 的批量读定位,Lance 更适合 AI 训练数据管道、向量数据等需要频繁小批量随机读和可变长数据的场景。

关键词:Lance 列存 AI 向量 Arrow Parquet 随机访问 | 来源:202604/20260415_01.md

Q:ORC 列存格式与 Parquet 的主要定位差异是什么?

ORC(Optimized Row Columnar)也是一种列式存储格式,最初为 Hive 设计,按 stripe(行组)、column 组织,支持列级压缩、编码、轻量级索引(min/max、布隆过滤器)和内嵌统计。与 Parquet 相比定位相近,都是列存分析格式,但 ORC 在 stripe 内携带更丰富的索引/统计(如布隆过滤器),查询时数据跳过更细;Parquet 生态更通用、跨引擎支持更广。两者都用于数据仓库/数据湖的列存。

关键词:ORC 列存 stripe 布隆过滤器 Parquet 数据湖 | 来源:202604/20260416_01.md

Q:OrioleDB 是什么?它的 undo 和 copy-on-write checkpoint 机制有什么特点?

OrioleDB 是 PostgreSQL 的一个 table access method(存储引擎),基于 B+ 树组织数据,采用 undo(回滚段)而非 heap+MVCC 死元组方式处理并发,更新时旧版本进 undo segment,避免死元组累积和 vacuum 压力。它支持 copy-on-write checkpoint,checkpoint 时不阻塞写,通过写时复制快照实现一致恢复,降低 checkpoint 对业务的冲击。

关键词:OrioleDB undo B+树 copy-on-write checkpoint 存储引擎 | 来源:202202/20220228_01.md

Q:PG 32 位 XID 困境的实质是什么?Heikki 2013 page epoch 方案的核心思想是什么?

32 位 XID 困境的实质不是'4 字节存事务号’那么简单,而是 4 字节事务号 + 环形比较 + 半数冻结:XID 是 uint32,最多 43 亿,用完循环,PG 把空间切成两半区分过去/未来,一旦走过半圆边界老 XID 就变’未来’,必须靠 freeze 全表扫来防止。Heikki 2013 page epoch 方案的核心是:在 page header 存一个 epoch(或用 PageLSN 推断 epoch),tuple header 的 t_xmin 仍是 32 位,但 MVCC 解读时真实 XID = (page.epoch « 32) | tuple.xmin。这样不破坏 page 格式、不增加 tuple 头大小、freeze 从’全表扫’降级为’自然变更’。

关键词:32位XID page epoch Heikki freeze 环形 wraparound | 来源:202609/20260904_05.md

Q:PG Data Block 中 LSN 的作用是什么?

每个数据页的 page header 里存有 PageLSN,记录最后一次修改该页的 WAL 记录的 LSN。它的作用:1) 崩溃恢复时,用页的 LSN 与要重放的 WAL 记录 LSN 比较,判断该页是否已包含该条 WAL 的修改,从而决定是否重放(保证幂等、避免重复应用);2) 判断脏页刷盘与 WAL 刷盘的前后关系,实施 WAL-before-data。它是崩溃恢复正确性和幂等性的关键。

关键词:PageLSN 数据块 LSN 崩溃恢复 幂等 WAL-before-data | 来源:202510/20251011_03.md

Q:PG unlogged table 转 logged 为什么会写大量 REDO/WAL?

unlogged table 正常写入时不写 WAL(数据不保证崩溃恢复),转换回 logged 时需要把表中已有数据全部补充写 WAL(否则崩溃后无法恢复这些数据)。这个转换过程会为整张表的数据生成大量 REDO/WAL,表越大写的 WAL 越多,可能造成 WAL 尖峰。这是 unlogged 表的固有代价,转换时应评估 WAL 量。

关键词:unlogged table logged WAL REDO 转换 代价 | 来源:202405/20240510_03.md

Q:PG17 用 TidStore 替代旧的 dead tuple 存储结构提升了 vacuum 什么?为什么说 PG 单表不建议超过 8.9 亿条记录?

PG17 引入 TidStore 数据结构存储 dead tupleid,替代旧的数组结构,提升 vacuum 在记录和查找 dead TID 时的效率。之所以说 PG 单表不建议超过 8.9 亿条记录,是因为按默认 autovacuum 参数(1GB 内存记录 dead tupleid,tupleid 6 字节约 1.7 亿条)配合 20% 触发阈值,1GB 内存最多覆盖约 8.9 亿行表的垃圾;超过这个量级,单次 vacuum 无法一次性装下所有 dead TID,需要多次扫描索引,维护成本上升。

关键词:TidStore PG17 dead tupleid 8.9亿 单表规模 | 来源:202404/20240402_02.md

Q:PG19 对哈希索引的改动为什么是’改写 VACUUM 的 I/O 逻辑’?

哈希索引的 bulk delete(vacuum 清理索引中的死项)此前用随机访问方式读取索引页,IO 效率低。PG19 把 streaming read(流式/预取式顺序读)用于 hash index 的 bulk delete,把散乱的随机读改成可预取的顺序读,显著提升哈希索引在 vacuum 阶段的清理效率。

关键词:哈希索引 vacuum bulk delete streaming read PG19 | 来源:202603/20260318_02.md

Q:PG19 的 Autovacuum 并行化如何突破大表维护瓶颈?

传统 autovacuum 单 worker 处理单表,大表 vacuum 是串行的,成为维护瓶颈。PG19 引入 autovacuum 并行化,让单张表的多索引清理(index vacuum 阶段)可以并行执行,配合 parallel vacuum 机制,由多个 worker 分工清理同一张表的不同索引,大幅缩短大表 vacuum 耗时。并行度受 max_parallel_maintenance_workers、autovacuum_max_parallel_workers 等参数约束。

关键词:autovacuum 并行化 PG19 parallel vacuum 大表 | 来源:202604/20260407_07.md

Q:PG19 的 Autovacuum 智能优先级是怎么让关键表先被处理的?

它重构了 autovacuum 的调度评分:不再简单按单一阈值,而是综合 XID/MXID 年龄、死元组数量、插入量、统计信息陈旧度等维度打分,并让接近 wraparound 危险区的表(XID 年龄高)获得更高优先级,确保防 wraparound 这类数据安全维护优先于普通空间回收。配套的 pg_stat_autovacuum_scores 视图让这个评分对外可观测。

关键词:autovacuum 智能优先级 PG19 wraparound 调度 | 来源:202604/20260406_02.md

Q:PG19 的 CHECKPOINT 精细化控制支持哪些 MODE?FLUSH_UNLOGGED 是什么?

PG19 支持 CHECKPOINT 语句的精细化控制,可指定 MODE 为 FAST(快速,尽可能快完成)、SPREAD(散布,控制刷脏速率降低对业务 IO 冲击)等;FLUSH_UNLOGGED 控制是否把 unlogged table 的数据也 flush 出去。这让 DBA 能根据场景选择立即 checkpoint 还是平滑 checkpoint,避免一次 checkpoint 引发的 IO 尖峰。

关键词:CHECKPOINT MODE FAST SPREAD FLUSH_UNLOGGED PG19 | 来源:202507/20250714_12.md

Q:PG19 的 REPACK 意味着什么?为什么说 vacuum full 将成为历史?

REPACK 是 PG19 引入的在线表重写/收缩方案,目标是替代需要强锁和额外磁盘空间的 VACUUM FULL。传统 VACUUM FULL 用 ACCESS EXCLUSIVE 锁整表重写,对在线业务影响大;REPACK 以接近在线的方式完成表压缩、回收空洞,让’收缩表’不再是一个需要维护窗口的重操作。

关键词:REPACK PG19 vacuum full 在线重写 表收缩 | 来源:202603/20260314_03.md

Q:PG19 的 vacuum 优化补丁为什么最多能少产生 50% WAL?

它优化了 vacuum 在扫描/清理过程中对 page 的写操作,减少不必要的 full-page image 和增量 WAL 记录的产生(例如避免对未被实际修改的页写 WAL、合并小改动、减少 page 头的更新)。vacuum 扫大表时即使只改一点点也要写 WAL,这个补丁让 vacuum 只对真正有变化的部分写 WAL,从而最多可少产生约 50% 的 WAL。

关键词:vacuum WAL 优化 PG19 50% full-page image | 来源:202510/20251017_07.md

Q:PG19 的并行 VACUUM 把什么写进了日志?

PG19 让并行 VACUUM 把’计划启动几个 worker、实际真正拉起几个’写进日志。此前并行 vacuum 只报告整体进度,无法知道并行度是否按预期生效(可能因为 max_parallel_maintenance_workers、autovacuum 资源或索引数不足导致实际并行度低于计划)。现在日志能显示 plan 与实际启动的 worker 数,便于诊断并行 vacuum 是否真正并行。

关键词:并行 VACUUM 日志 worker PG19 计划 实际 | 来源:202603/20260322_02.md

Q:PG19 硬件加速的校验和计算是什么?

PG19 为 data page 校验和(checksum)计算引入硬件加速:在 x86 上用 AVX2 指令、在 ARM 上用 CRC32C 指令实现校验和计算,替代原来的软件标量实现,大幅降低启用 data checksums 时的 CPU 开销。这让开启校验和的性能代价变小,鼓励更多场景开启数据校验和以检测静默损坏。

关键词:校验和 AVX2 CRC32C 硬件加速 data checksums PG19 | 来源:202604/20260406_06.md

Q:Parquet 列存格式的核心特点是什么?

Parquet 是面向分析的列存文件格式,按列组织数据并支持列级压缩、编码(如字典编码、RLE、bit-packing)和嵌套结构。它以 row group 和 column chunk 为单位组织,元数据里保存每列的统计信息(min/max、null count),查询时可据此跳过无关数据(谓词下推),适合 OLAP 大表扫描。Parquet 是数据湖生态的事实标准,pg_duckdb、pg_mooncake 等插件让 PostgreSQL 能直接查询 Parquet 文件。

关键词:Parquet 列存 row group 压缩 编码 谓词下推 数据湖 | 来源:202410/20241015_01.md

Q:PostgreSQL 12 的 blackhole(黑洞)存储引擎是什么?有什么用途?

blackhole 是 PG12 基于 table access method API 实现的一个’黑洞’存储引擎:写入的数据被直接丢弃(类似 MySQL 的 BLACKHOLE),读取恒为空。用途包括:测试复制链路和 SQL 解析开销(数据不落盘、写入极快)、作为某些中间层/审计场景的 sink,以及演示 AM 框架的可扩展性。

关键词:blackhole 黑洞引擎 table access method AM sink | 来源:201906/20190607_01.md

Q:PostgreSQL 三种心跳(keepalive)指标是什么?分别用于什么场景?

三种心跳指标:1) 时间戳(时间心跳),用于判断实例/进程是否还活着、延迟;2) redo/WAL 位点(LSN 心跳),用于主从复制延迟监控、判断备库追上主库的位置;3) 事务号(XID 心跳),用于监控事务消耗速率、预测 freeze/wraparound 风险。三者分别对应’时间维度’‘数据持久化进度’‘事务生命周期’,是 DBA 监控数据库健康的三类基础探针。

关键词:心跳 keepalive 时间戳 LSN XID 监控 | 来源:201905/20190503_04.md

Q:PostgreSQL 列存相比行存有哪些优势?为什么列存没有 1666 列限制?

列存按列组织存储,同一列的数据连续存放。优势:1) 列存没有行存 1666 列的限制(行存受 tuple 最大宽度约束);2) 大量记录扫描时只读取需要的列,节约 IO 和资源,OLAP 聚合/过滤场景收益大;3) 便于按列做向量化计算和压缩。行存则适合按行整取、频繁更新的 OLTP 场景。二者结合即行列混合存储(HTAP)。

关键词:列存 1666列 行存 混合存储 OLAP 向量化 | 来源:201902/20190216_01.md

Q:PostgreSQL 列存索引/混合索引的思路是什么?适合什么负载?

混合存储(行存+列存)与混合索引的思路是:OLTP 热数据用行存、OLAP 分析数据用列存,并在列存上建列存索引或物化/向量化结构加速扫描。适合 HTAP 混合负载——既需要高频单行事务读写,又需要对大量历史数据做聚合分析的场景,用一套数据库同时承载两种负载,避免 ETL 搬运。

关键词:列存索引 混合索引 HTAP 混合负载 行存 | 来源:201902/20190216_01.md

Q:PostgreSQL 有哪些膨胀点?哪些垃圾(dead tuple)和 WAL 文件不能被回收复用?

膨胀点分为:全局 catalog、库级 catalog、普通表、WAL 文件。dead tuple 若被老快照、长事务、prepared transaction、复制槽 xmin/catalog_xmin 或逻辑复制保留,就无法被 vacuum 回收;WAL 文件若被复制槽、归档、逻辑解码等下游未消费,就无法被复用/回收。因此膨胀的本质是’有人还留着更老的边界’,排查膨胀要同时看表和 WAL 两个层面的阻塞者。

关键词:膨胀点 catalog dead tuple WAL 复制槽 阻塞 | 来源:201907/20190701_01.md

Q:VACUUM 的 BUFFER_USAGE_LIMIT 选项(PG16)和 vacuum_buffer_usage_limit 参数有什么用?

它限制 vacuum 使用的共享缓冲(shared buffer)量,通过控制 vacuum 环状缓冲(buffer ring)的大小来减少 vacuum 造成的 WAL flush 和其他页面被挤出缓存的影响。设小一点可以降低 vacuum 对 shared buffer 和 wal flush 的压力,提升整体速度、避免 vacuum 与业务争缓存。PG17 调大了 vacuum_buffer_usage_limit 的默认值(从 256KB 提到 2MB),进一步减少 vacuum 造成的 wal flush、提升 vacuum 速度。

关键词:BUFFER_USAGE_LIMIT vacuum_buffer_usage_limit PG16 PG17 buffer ring | 来源:202304/20230407_03.md

Q:VACUUM 的 PROCESS_TOAST 开关(PG14)和 MAIN/TOAST 选项(PG16)分别控制什么?

PG14 引入 vacuum PROCESS_TOAST 开关,控制 vacuum 是否同时处理关联的 TOAST 表(大字段外部存储)。PG16 进一步支持在 VACUUM 语句中指定仅处理 MAIN 或仅处理 TOAST,例如 VACUUM (PROCESS_MAIN FALSE) 或只处理 TOAST,让 DBA 能按需定向清理主表或 TOAST 表,减少不必要的维护开销。

关键词:PROCESS_TOAST MAIN TOAST vacuum PG14 PG16 | 来源:202102/20210209_02.md

Q:VACUUM/ANALYZE 的 SKIP_LOCKED(PG12)解决什么问题?

PG12 引入 VACUUM (SKIP_LOCKED) 和 ANALYZE (SKIP_LOCKED),让 vacuum/analyze 在遇到被其他会话锁定的表时跳过该表而不是等待或报错。这解决了批量维护时个别表被锁导致整个维护任务卡住的问题,尤其适合在业务高峰期或大量表上跑 vacuumdb 时避免长时间锁等待。

关键词:SKIP_LOCKED vacuum analyze PG12 vacuumdb 锁 | 来源:201903/20190331_10.md

Q:Vortex 列存格式是什么定位?

Vortex 是一种面向分析/数据湖的列存新范式,同样基于 Arrow 生态,强调高效的向量化读取和压缩,针对现代 CPU(SIMD 向量化)做了数据布局优化,目标是在保持压缩率的同时提升解压与扫描吞吐。它与 Lance、Parquet 同属数据湖列存阵营,各有侧重。

关键词:Vortex 列存 Arrow 向量化 数据湖 | 来源:202604/20260414_04.md

Q:WAL Sender 关闭超时(PG19)解决复制环境下的什么问题?

PG19 为 WAL Sender 引入关闭超时机制:当主库要关闭或切换时,WAL sender 进程若长时间无法正常结束(例如备库网络中断导致 send 阻塞),会按超时强制终止,避免主库关闭/切换被卡住的 WAL sender 拖住。这让复制环境下的优雅关闭/切换更可靠。

关键词:WAL Sender 关闭超时 PG19 复制 切换 | 来源:202604/20260406_04.md

Q:WAL 的 insert/write/flush 三个 LSN 水位分别代表什么?

三个 LSN 对应 WAL 的不同持久化进度:insert LSN 是已写入 WAL buffer 的位点;write LSN 是已由 walwriter 调用 write() 写入 OS 的位点(数据在 OS page cache 但未必落盘);flush LSN 是已调用 fsync 真正持久化到磁盘的位点。WAL-before-data 原则要求数据页刷盘前,对应的 WAL 必须先达到 flush。同步提交时事务要等 flush LSN 到达提交记录的位点;异步提交则只需 write 到位即可返回,由 walwriter 稍后异步 flush。

关键词:WAL LSN insert write flush 持久化 walwriter | 来源:202606/20260608_53.md

Q:autovacuum 基于什么公式触发对更新/删除产生死元组的表的普通 vacuum?

核心触发条件是 dead tuple 数量超过阈值:threshold = autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor * reltuples。默认 autovacuum_vacuum_threshold=50、autovacuum_vacuum_scale_factor=0.2,即垃圾记录约等于表行数 20% 时触发。对几乎只插入的表另有 insert vacuum 触发(autovacuum_vacuum_insert_threshold 与 autovacuum_vacuum_insert_scale_factor)。此外,若表的 relfrozenxid 或 relminmxid 太老,即使 autovacuum 被关闭,系统也会为防 wraparound 强制启动 autovacuum。

关键词:autovacuum 触发公式 threshold scale_factor reltuples wraparound | 来源:201906/20190617_01.md

Q:autovacuum_vacuum_max_threshold(PG18 新增)解决什么问题?

它给 autovacuum 触发增加了一个绝对上限:无论表多大、scale_factor 如何,dead tuple 数量一旦达到这个上限就触发 vacuum。目的是解决大表的自动垃圾回收频率过低问题——旧逻辑 threshold + scale_factor*reltuples 对大表(如十亿行)会算出极高的触发点,导致垃圾长时间累积。有了 max_threshold,DBA 可以给一个硬上限,避免大表膨胀失控。

关键词:autovacuum_vacuum_max_threshold PG18 大表 触发上限 | 来源:202502/20250206_01.md

Q:bgwriter 和 checkpointer 的职责边界分别是什么?bgwriter 的 clock-sweep 是什么?

bgwriter 负责在后台定期扫描 shared buffer,把 LRU 里的脏页写出(BgBufferSync),减轻 client backend 需要自己找干净页时的同步刷脏压力;它用 clock-sweep 算法循环扫描 buffer 描述符,按一定速率推进写脏。checkpointer 则负责在 checkpoint 时把 dirty page 刷盘并写 checkpoint 记录,保证崩溃恢复能从一个一致点开始。bgwriter 是平滑、预防性的刷脏,checkpointer 是周期性、强一致性的刷脏。

关键词:bgwriter checkpointer clock-sweep BgBufferSync 刷脏 职责 | 来源:202606/20260608_69.md

Q:bgwriter 相关参数 bgwriter_delay、bgwriter_lru_maxpages、bgwriter_lru_multiplier 各控制什么?

bgwriter_delay 是 bgwriter 两轮扫描之间的休眠间隔(默认 200ms)。bgwriter_lru_maxpages 是每轮最多写出的脏页数上限。bgwriter_lru_multiplier 是乘数,与最近一段时间的缓冲请求数相乘估算本轮应写的页数目标,再受 lru_maxpages 封顶。调大这些参数让 bgwriter 更激进地刷脏,可减少 backend 的同步刷脏等待,但过度会与业务争 IO。

关键词:bgwriter_delay bgwriter_lru_maxpages bgwriter_lru_multiplier 刷脏 | 来源:202011/20201107_05.md

Q:block wand 剪枝如何缓解 Top K 简单查询的性能噩梦?

Top K 查询(ORDER BY … LIMIT K)如果列无索引,PG 传统上要做全表排序或堆排序,扫描成本高。block wand(块魔杖)剪枝利用’块级上界’思想:先按 block 统计每个数据块内目标列的最大/最小值(或上界信息),排序时优先处理可能包含 Top K 值的块、跳过不可能进入 Top K 的块,从而大幅减少需要扫描和排序的数据量,缓解 Top K 查询的全表扫描噩梦。

关键词:block wand Top K 剪枝 排序 LIMIT 扫描 | 来源:202603/20260314_15.md

Q:drop column 之后 VACUUM FULL 能释放 pg_attribute 里的 dropped column 元数据吗?为什么 1600 列上限无法通过 drop column 突破?

不能。drop column 只是逻辑删除,pg_attribute 中的行仍然保留(attnum 不回收、attisdropped 标记),VACUUM FULL 只回收旧值占用的物理空间,不会删除 dropped column 的元数据。因此 1600 列的硬限制(源于 tuple 最大宽度和 pg_attribute 行数)无法通过反复 drop column 来绕过——即使 drop 后再 vacuum full,pg_attribute 里仍有这些 dropped column 记录,attnum 计数不会回落,新增列仍会受 1600 上限约束。

关键词:drop column pg_attribute 1600列 attnum attisdropped VACUUM FULL | 来源:202107/20210729_01.md

Q:freeze 事务号年龄降不下来时,应该优先排查什么?

应优先排查实例中最老的事务:两阶段事务(2PC / prepared transaction)、长查询(long query)、长事务(long xact)。因为 relfrozenxid/datfrozenxid 年龄能否推进取决于是否存在很老的事务快照:只要存在未提交的 prepared transaction 或长时间运行的事务,其 xmin 就会卡住 freeze 边界,导致年龄降不下来。处理方法是找到并结束这些最老事务(COMMIT/ROLLBACK PREPARED、杀掉长事务),再执行 VACUUM FREEZE 推进边界。

关键词:freeze 年龄 2PC prepared transaction 长事务 xmin | 来源:201908/20190807_01.md

Q:freeze 的本质是什么?XID 为什么必须循环使用、为什么需要 freeze 防止 wraparound?

XID 是 32 位 uint32,最多 43 亿个事务号,用完必须循环复用。PG 把 XID 空间看作圆,‘frozen xid’ 是圆上一个点,顺时针是过去(已分配)事务号、逆时针是未来(可分配)事务号。一旦 XID 走过半圆边界(消耗约 20 亿事务),老 XID 会被误判为’未来事务’,其 tuple 会从 MVCC 视野里’消失’。freeze 的防御机制就是 autovacuum 周期性扫表,把超过冻结边界的 tuple 标记为 HEAP_XMIN_FROZEN(把 t_xmin 替换成 FrozenTransactionId=2),标记后该 tuple 永远可见、不再参与 MVCC 判断,同时推进 relfrozenxid/datfrozenxid 边界。freeze 的本质不是清理老数据,而是防止老 XID 跨过半圆变成未来。

关键词:freeze XID wraparound HEAP_XMIN_FROZEN 半圆 relfrozenxid | 来源:202606/20260608_67.md

Q:full_page_write 和 FPI(Full Page Image)是什么?为什么要默认开启?

full_page_write=on 时,checkpoint 后每个 page 第一次被修改时,WAL 记录里会写入该 page 的完整镜像(full-page image, FPI),而不仅是增量变化。原因是崩溃恢复时若页面只写了部分(torn page),没有完整镜像就无法还原。FPI 是 WAL 体积膨胀的主要来源,但换来可靠性;代价是性能、存储空间和稳定性开销。wal_compression 可对 FPI 压缩(PG15 起支持 pglz/zlib/lz4/zstd)。

关键词:full_page_write FPI torn page WAL 崩溃恢复 wal_compression | 来源:201906/20190608_01.md

Q:greenplum 的 append only column store(AOCO)是什么?

Greenplum 的 AOCO(Append-Optimized Column-Oriented)是列式追加写存储:数据按列组织、以 append-only 方式写入,每列单独存一个文件并独立压缩,配合元数据里的 min/max 等统计做 segment 裁剪。它面向批量加载和 OLAP 扫描,支持列级压缩,适合数仓场景。追加写避免了 in-place 更新的随机 IO,但删除/更新需要额外的可见性处理(如 bitmap 或 AO 表的隐式版本)。

关键词:greenplum AOCO append-only 列存 压缩 数仓 | 来源:202604/20260416_03.md

Q:maintenance_work_mem 和 autovacuum_work_mem 在垃圾回收中起什么作用?设太小会有什么后果?

这两个参数控制 vacuum 记录垃圾 tupleid 的内存上限。vacuum 扫描表时把 dead tuple 的 TID 存进这块内存(tupleid 为 6 字节,1GB 约可存 1.7 亿条),内存占满后暂停表扫描、转去扫描索引按记录的 TID 清理死索引项,清完再回到断点继续扫表。若设得太小,索引会被反复扫描多次,浪费 IO 和时间。9.4 之前用 maintenance_work_mem,9.4 及之后可用 autovacuum_work_mem,未设置则回退到 maintenance_work_mem。判断依据是 autovacuum 日志里的 index scans 次数:超过 1 说明内存不够,可把 autovacuum_work_mem 乘以 index scans 来调大,或把 autovacuum_vacuum_scale_factor 除以 index scans 让 vacuum 更早触发。

关键词:maintenance_work_mem autovacuum_work_mem index scans dead tupleid vacuum | 来源:201902/20190226_01.md

Q:parallel vacuum(PG13)如何并行清理一张有很多索引的表?

PG13 引入 parallel vacuum:当一张表有很多索引时,vacuum 的 index vacuum 阶段可以把不同索引分配给多个并行 worker 同时清理,主进程负责扫描 heap 收集 dead tuple TID。并行度受 max_parallel_maintenance_workers 和 autovacuum_max_parallel_workers 约束。索引多、单索引清理耗时的场景收益明显。

关键词:parallel vacuum PG13 max_parallel_maintenance_workers 多索引 | 来源:202002/20200206_03.md

Q:pg_control 控制文件的原子写和 CRC 校验机制是怎样的?

pg_control 保存实例的关键元数据(checkpoint 位置、WAL 位点、系统标识符、数据库状态、参数值等),是崩溃恢复的入口。为保证安全,它采用原子写(先写临时文件再 rename 或双写)和 CRC 校验:每次写 pg_control 时计算 CRC 并存储,读取时校验 CRC 是否一致,若损坏则拒绝启动(需用 pg_resetwal 重建)。CRC 用于检测半写/损坏的 pg_control。

关键词:pg_control 原子写 CRC 崩溃恢复 校验 pg_resetwal | 来源:201907/20190721_01.md

Q:pg_duckdb 和 pg_mooncake 在接入数据湖上的异同?

两者都是把 DuckDB 的列存/OLAP 能力接入 PostgreSQL:pg_duckdb 通过 DuckDB 引擎在 PG 里执行分析查询、读写 Parquet 等外部列存文件;pg_mooncake 更进一步面向数据湖,支持 Iceberg 等表格式和原生列存表。共同点是都依赖 DuckDB 的向量化列存执行来获得 OLAP 性能数量级提升;区别在于 mooncake 更强调数据湖生态(Iceberg/Parquet 管理),duckdb_fdw 更偏通用列存查询。

关键词:pg_duckdb pg_mooncake DuckDB 数据湖 列存 | 来源:202412/20241231_02.md

Q:pg_mooncake 是什么?它如何让 PostgreSQL 具备数据湖/列存能力?

pg_mooncake 是 PostgreSQL 的数据湖/列存扩展,把 DuckDB 作为执行引擎内嵌,让 PostgreSQL 能直接在列存表(支持 Parquet、Iceberg 等格式)上做高性能 OLAP。它把 Postgres 的 SQL 接口与 DuckDB 的列存执行、向量化计算结合,用户可以在 PG 里创建列存表、查询外部 Parquet/Iceberg 数据湖文件,OLAP 性能相比行存有数量级提升。

关键词:pg_mooncake 数据湖 列存 DuckDB Parquet Iceberg OLAP | 来源:202410/20241031_01.md

Q:pg_receivewal + 同步复制的 WAL 零丢失方案(mirror)是怎么实现的?

pg_receivewal 是一个流式接收 WAL 并落盘的工具,可把主库 WAL 实时镜像到远程目录。配合同步复制(synchronous_commit 和 synchronous_standby_names),主库提交需等 WAL 被备库/镜像端确认收到并持久化,实现 WAL 0 丢失。多层 mirror 时可用多个 pg_receivewal 或级联备库,把 WAL 同时镜像到多处,提升容灾可靠性。

关键词:pg_receivewal 同步复制 WAL 0丢失 mirror 容灾 | 来源:201910/20191027_03.md

Q:pg_stat_autovacuum_scores 视图(PG19)解决了什么问题?它反映哪些维度的优先级?

它把 autovacuum 的优先级评分从黑箱变成可见。autovacuum 选择先处理哪张表是基于一个优先级评分,该评分由多个维度合成:XID score(事务号年龄)、MXID score(multixact 年龄)、vacuum score(死元组累积)、insert score(插入类 vacuum 需求)、analyze score(统计信息陈旧)。通过该视图可以看出一张表为什么被优先(或不被优先)处理,便于诊断 autovacuum 是否及时。

关键词:pg_stat_autovacuum_scores PG19 autovacuum 优先级 评分 | 来源:202604/20260407_01.md

Q:pg_stat_checkpointer(PG17)和其 num_done 字段(PG18)统计什么?

PG17 引入 pg_stat_checkpointer,把 checkpointer 的统计从 bgwriter 中分离出来,单独统计 checkpointer 的 checkpoint 次数、耗时、刷脏页数、写 WAL 量等。PG18 增加 num_done 字段统计实际完成的检查点次数,与 requested(请求的检查点数)区分,便于 DBA 了解 checkpoint 的触发与完成情况,排查 checkpoint 相关性能问题。

关键词:pg_stat_checkpointer num_done checkpoint PG17 PG18 | 来源:202310/20231030_01.md

Q:pg_stat_wal(PG14)和 track_wal_io_timing 参数提供什么统计?

pg_stat_wal 是 PG14 引入的实例级 WAL 统计视图,提供 wal_records(WAL 记录数)、wal_fpi(full-page image 数)、wal_bytes(WAL 字节数)等。track_wal_io_timing 参数开启后,可统计 WAL buffer 的 write 和 fsync 的 IO 等待时长,输出到 pg_stat_wal,帮助定位 WAL 落盘延迟瓶颈。PG15 起 pg_walinspect 插件可进一步分析 WAL 记录内容。

关键词:pg_stat_wal track_wal_io_timing wal_records wal_bytes PG14 | 来源:202012/20201202_02.md

Q:pg_surgery(PG14)用于修复什么?

pg_surgery 是 PG14 引入的 contrib 扩展,用于修复损坏的 tuple。它提供 force_freeze 和 remove 两种能力:force_freeze 可强制把 tuple 标记为 frozen(绕过正常的可见性检查),remove 可物理删除指定的 dead/corrupted tuple(通过 TID 指定)。它用于应急修复因损坏或 freeze 异常导致无法 vacuum 或无法访问的表,属于危险操作,只能由熟悉原理的 DBA 在明确目标下使用。

关键词:pg_surgery 修复 corrupted tuple force_freeze remove PG14 | 来源:202009/20200911_01.md

Q:relfrozenxid 和 datfrozenxid 的年龄(age)代表什么?为什么 DBA 要重点监控它?

age(relfrozenxid) = 当前事务号 - relfrozenxid,表示自该表上次推进冻结边界以来已消耗的 XID 数量;datfrozenxid 是库级冻结边界。年龄越接近 20 亿(2^31),越接近 XID wraparound 危险区。防 wraparound 的数据安全优先级高于空间回收:一旦年龄失控,会触发数据库拒绝分配新 XID、强制进入单用户模式跑 freeze。所以 DBA 监控 age(relfrozenxid)/age(relminmxid) 比监控死元组更重要,应优先保证 freeze 及时推进。

关键词:relfrozenxid datfrozenxid age wraparound 监控 | 来源:202205/20220531_01.md

Q:tuple deformation 优化是什么?为什么能提升 OLAP 场景性能 5-20%?

tuple deformation 指把 heap 元组(行格式)‘拆解’成列式内存布局、抽取所需列值的过程,是 OLAP 扫描中 CPU 开销的大头。PG18/19 对 tuple deformation 做了优化(减少冗余的字段定位、批量解列、利用 SIMD 等),让行存表在做列式聚合/过滤时,把行拆列这一步更快,从而在 OLAP 场景获得 5-20% 的性能提升。

关键词:tuple deformation OLAP 解列 SIMD PG18 PG19 | 来源:202412/20241230_01.md

Q:update 时新 tuple 如何选择空闲 block 插入?

heap_update 先尝试在原 page 内找空间(若 HOT 或同页有 free space 则同页插入,形成 HOT 链或普通更新链);同页放不下时,通过 FSM 查找有足够 free space 的 page 插入新版本,并把旧版本的 t_ctid 指向新版本、设置 xmax。若 FSM 里没有合适页,则向表尾扩展新 block。选择空闲 block 的核心依赖 FSM 的空闲空间近似值。

关键词:heap_update FSM 空闲block t_ctid HOT 新版本 | 来源:202509/20250917_06.md

Q:vacuum 的 failsafe 模式是什么?什么情况下会触发?

failsafe 是 PG14 引入的防 wraparound 兜底机制,由 vacuum_failsafe_age 和 vacuum_multixact_failsafe_age 两个参数控制。当表的 relfrozenxid 或 relminmxid 年龄逼近危险区(接近 20 亿回卷边界)时,vacuum 进入 failsafe 模式:跳过部分索引维护、不受 cost-based vacuum delay 限制,把目标优先级切到尽快推进冻结边界、防止 XID wraparound 数据丢失。这是以牺牲部分空间回收质量为代价换取数据安全。

关键词:failsafe vacuum_failsafe_age vacuum_multixact_failsafe_age wraparound PG14 | 来源:202104/20210408_03.md

Q:vacuum_truncate 参数/选项控制什么?

它控制 vacuum 结束时是否收缩文件大小(截断表尾的空页)。标准 vacuum 把页内空间标记为可复用,通常只在表尾有整页全空且能拿到锁时才截断。vacuum_truncate 设为 off 可禁止截断,避免截断引起的锁等待或 IO 抖动;PG18 把它作为独立 GUC 暴露,PG19 也可在 VACUUM 语句级别控制。对于不想让 vacuum 频繁锁表截断的场景,关闭它更合适。

关键词:vacuum_truncate 截断 表尾空页 PG18 | 来源:202503/20250321_01.md

Q:wal_compression 支持哪些压缩算法?各版本演进是怎样的?

wal_compression 用于压缩 WAL 中的 full-page image(FPI),减少 WAL 体积。PG15 起支持 pglz、zlib、lz4 三种,PG15 又加入 zstd;PG15 的 wal full page write 支持 lz4 压缩,PG15 同时支持 zstd 压缩 FPI。压缩 FPI 能显著降低 WAL 写入量,代价是少量 CPU 开销,适合 FPI 占比高、网络/磁盘带宽紧张的场景。

关键词:wal_compression pglz zlib lz4 zstd FPI 压缩 | 来源:202106/20210615_05.md

Q:wal_recycle 和 wal_init_zero(PG12)适配 COW 文件系统解决什么问题?

PG12 引入 wal_recycle 和 wal_init_zero 两个 GUC。默认 PG 会复用旧的 WAL 文件并对其预置零(zero-fill),在 ZFS 等 COW(copy-on-write)文件系统上,预置零会导致大量无谓的写放大和空间占用。wal_recycle 控制是否复用 WAL 文件,wal_init_zero 控制是否在新建 WAL 文件时预置零。在 COW 文件系统上关闭这两个选项可避免写放大。

关键词:wal_recycle wal_init_zero COW ZFS PG12 写放大 | 来源:201904/20190405_05.md

Q:walwriter 的调度逻辑是什么?wal_writer_delay 和 wal_writer_flush_after 各控制什么?

walwriter 是后台进程,负责周期性地把 WAL buffer 刷到磁盘。它在一个主循环里休眠 wal_writer_delay(默认 200ms)后被唤醒,调用 XLogBackgroundFlush() 把累积的 WAL 写到 OS 并尝试 flush。wal_writer_flush_after 控制累计写出多少字节后强制 flush。异步提交最坏情况下会丢失约三倍 wal_writer_delay 时间内的已提交事务,因为 walwriter 的唤醒周期就是这个 delay。

关键词:walwriter wal_writer_delay wal_writer_flush_after XLogBackgroundFlush 调度 | 来源:202606/20260608_70.md

Q:zedstore 是什么?它的行/列混合存储思路是怎样的?

zedstore 是 PostgreSQL 基于 access method API 的列存/行列混合存储引擎实验项目。它把表按列族组织,支持行式与列式混合存储:把频繁一起更新的列放行式、把用于分析的大字段列放列式,兼顾 OLTP 更新与 OLAP 扫描。它通过 PostgreSQL 的 table access method 接口实现,可替换默认 heap AM。

关键词:zedstore 列存 混合存储 table access method | 来源:201905/20190531_03.md

Q:为什么 VACUUM FULL / CLUSTER 需要 ACCESS EXCLUSIVE 锁?PG18 的 CONCURRENTLY 版解决了什么?

VACUUM FULL 和 CLUSTER 都是整表重写操作,会锁表、阻塞并发读写,且需要额外磁盘空间保存新副本。PG18 引入 VACUUM FULL / CLUSTER CONCURRENTLY,把重写过程改成类似在线重写的并发方式,降低对业务的阻塞影响,使得表收缩可以在接近在线的状态下完成。

关键词:VACUUM FULL CONCURRENTLY CLUSTER PG18 在线重写 锁 | 来源:202409/20240902_01.md

Q:为什么 VACUUM 不仅清理 dead tuple,还要清理 CLOG?

CLOG(Commit Log)记录每个事务的提交状态(每事务 2 bit),事务号推进后旧事务的提交状态最终可以被 ‘冻结覆盖’。VACUUM 在推进 freeze 边界(relfrozenxid 前进)时,意味着比该边界更老的 XID 的提交状态不再需要保留,对应的 CLOG 页可以被截断/回收。因此 vacuum 推进 freeze 的同时也把 CLOG 的过期页清理掉,防止 CLOG 无限增长;如果 freeze 长期不推进,CLOG 也会随之膨胀。

关键词:CLOG freeze 截断 事务提交状态 vacuum | 来源:202509/20250921_01.md

Q:为什么 autovacuum 对大热表经常触发太晚?如何按表设置更合理的参数?

默认 autovacuum_vacuum_scale_factor=0.2 意味着一张估算 10 亿行的表要累积到约 2 亿 dead tuples 才触发普通 vacuum,除非被 autovacuum_vacuum_max_threshold 截住或按表设置更小阈值。热表应按业务写入速率和可接受膨胀窗口设置表级 storage parameters,例如调小 autovacuum_vacuum_scale_factor(如 0.01)、调低 threshold,必要时提高 worker 数、cost limit 或在低峰期手工补充 VACUUM,而不是盲目提高全局 autovacuum 频率。

关键词:autovacuum scale_factor 热表 膨胀窗口 表级参数 | 来源:202502/20250206_01.md

Q:为什么更新表的索引列会破坏 HOT 更新机会、加剧膨胀?

HOT(Heap-Only Tuple)更新要求更新的列不在任何索引中。若只更新非索引列,旧 tuple 的新版本可留在同一 page、旧版本通过 t_ctid 链指向新版本,索引无需新增条目,从而避免索引膨胀,VACUUM 也不必清理索引。一旦更新了索引列(或表上有表达式索引等),HOT 前提被破坏,每次 update 都要在索引里插入新 entry、留下旧 entry 变 dead,索引垃圾增多,VACUUM 清理成本也随之上升。因此高频更新表应减少不必要索引、避免频繁更新索引列。

关键词:HOT update 索引列 索引膨胀 t_ctid heap-only | 来源:202606/20260601_07.md

Q:为什么说 PostgreSQL 想成为 HTAP 数据库还缺一个存储引擎?

PostgreSQL 的默认 heap 是行存,适合 OLTP,但 OLAP 大表扫描需要列存、向量化、压缩和物化/冷热分离等能力。虽然已有 pg_duckdb、pg_mooncake、zedstore、OrioleDB 等实验或扩展引擎,但社区内核长期没有一个内置、成熟、可插拔的列存/混合存储引擎来无缝支撑 HTAP。行存到列存的转换(tuple deformation)、列存更新、混合事务/分析的一致性是主要挑战,所以’还缺一个存储引擎’。

关键词:HTAP 存储引擎 列存 heap 行存 向量化 | 来源:202604/20260429_01.md

Q:为什么说 PostgreSQL 的 undo 存储引擎可能不那么重要了?

undo 存储引擎(如 zheap/zedstore、OrioleDB 的 undo)的设计动机之一是消除 heap 的死元组和 vacuum 压力。但文章认为,随着社区对 vacuum 的持续优化(并行 vacuum、failsafe、TidStore、更智能的 autovacuum 优先级、64 位 XID 减少 freeze 焦虑等),heap+MVCC 的痛点被逐步缓解,加上 64 位 XID 消除了 wraparound 风险,undo 引擎相对 heap 的收益空间变小,因此其必要性下降。

关键词:undo 存储引擎 zheap vacuum 64位XID MVCC | 来源:202301/20230115_01.md

Q:什么是 hint bit?为什么 CLogControlLock 会在大并发下成为风暴瓶颈?

hint bit 是 tuple header 里缓存的事务提交/回滚状态位。第一次读取某个 tuple 时,PG 需要查 CLOG 确认其 xmin/xmax 对应事务是否提交,确定后把结果以 hint bit 形式写回 tuple header(HEAP_XMIN_COMMITTED 等),后续读取就不再查 CLOG。当大量 tuple 尚未被 hint bit 标记、又集中在短时间内被访问时(例如刚导入大批数据后),所有会话都要访问 CLOG,争用 CLogControlLock 轻量锁形成风暴。PG11 通过批量读取 CLOG、减少锁竞争等内核层优化缓解了这一问题。

关键词:hint bit CLogControlLock CLOG 风暴 提交状态 | 来源:201903/20190319_02.md

Q:分组提交(group commit)是什么?它对高并发写有什么价值?

分组提交指多个并发事务的 WAL 记录被合并到同一次 fsync 中一起刷盘:一个事务发起 XLogFlush 时,把缓冲区内其他事务也已就绪的 WAL 一并刷盘,大家共享一次 fsync 的开销。这样在高并发写场景下,单事务的平均 fsync 成本大幅下降,提升提交吞吐。fsync 是写路径上最贵的操作之一,分组提交能有效摊薄这一成本。

关键词:group commit 分组提交 fsync XLogFlush 高并发 | 来源:201906/20190608_01.md

Q:同步提交与异步提交在 WAL flush 行为上的区别是什么?

同步提交(synchronous_commit=on)时,事务提交要等 WAL 记录 fsync 到磁盘(flush LSN 到达提交位点)才返回,保证已提交事务不丢。异步提交(synchronous_commit=off)时,提交只需 WAL 写入 OS(write LSN 到位)即可返回,由 walwriter 稍后异步 flush,最坏情况下可能丢失约三倍 wal_writer_delay 时间内的已提交事务,但能显著降低提交延迟、提升吞吐。业务若通过查询 wal flush lsn 控制最终一致,可兼顾性能与一致性。

关键词:synchronous_commit 异步提交 WAL flush 一致性 wal_writer_delay | 来源:201906/20190608_01.md

Q:垃圾回收与膨胀的根因是什么?UPDATE/DELETE 为什么制造垃圾?

根因是 MVCC 的追加写模型:UPDATE/DELETE 不立即删除旧行版本。heap_update() 会准备新 tuple 写入页面(新页面或同页),在旧版本上设置 xmax 并把旧版本 t_ctid 指向新版本;若满足 HOT 条件,旧版本标记 HOT-updated、新版本标记 heap-only。旧版本何时可清理,取决于系统里是否还有更老的快照、事务、复制槽或逻辑复制保留需求。只要更新频率高于回收频率,或回收被阻塞,page 内部就累积不可立即复用的旧版本,形成膨胀。

关键词:MVCC 膨胀 根因 heap_update 追加写 旧版本 | 来源:202606/20260601_07.md

Q:如何得到某个事务 commit 或 abort 时的 WAL LSN 位置?

可以通过查询事务提交时写入的 WAL 位点来获取。方法之一是使用 pg_current_wal_insert_lsn() 或 pg_current_wal_flush_lsn() 在事务提交前后采样;更精确的做法是利用 pg_waldump 或 pg_walinspect 分析 WAL 记录,找到该事务的 commit/abort 记录对应的 LSN。txid_current() 与 WAL 位点的关联需要借助 WAL 记录中携带的 xid 信息。

关键词:WAL LSN commit abort 事务位点 pg_waldump | 来源:202102/20210225_02.md

Q:如何诊断一张表是否膨胀?pgstattuple 能提供什么信息?

pgstattuple 会扫描整个关系,返回 tuple 数、dead tuple 数、free space、total_len 等物理统计,适合确认膨胀程度。但它是全表扫描,不适合高频扫大表。更轻量的方式是结合 pg_stat_all_tables 的 n_dead_tup、last_autovacuum、autovacuum_count、vacuum_count,以及 pg_relation_size、pg_freespace/VM 信息综合判断。好的膨胀检查 SQL 应同时看死元组占比、表大小与 VM all-visible 比例,并排查长事务、复制槽等阻塞者。

关键词:pgstattuple 膨胀检查 n_dead_tup pg_freespace 诊断 | 来源:202502/20250221_01.md

Q:如何配置 PostgreSQL 归档,并自动删除 N 天前的归档 WAL?

通过 archive_mode=on + archive_command 把完成的 WAL 归档到目标目录(archive_command 里可用 %p 源、%f 文件名等占位符)。自动清理过期归档通常由外部脚本完成,例如用 find 按 mtime 删除 7 天前的归档文件,配合 crontab 定时执行。核心是保证归档先成功(archive_command 返回 0)再允许 WAL 被复用,清理时也要确保下游(PITR 备份、复制槽)不再需要。

关键词:归档 archive_mode archive_command 清理 mtime find | 来源:201910/20191021_01.md

Q:异步提交场景下,业务如何通过查询 wal flush lsn 控制最终一致?

异步提交下事务返回时 WAL 可能尚未 fsync。业务若需要确认某笔已提交数据已真正落盘(例如跨库对账、下游消费),可以查询当前 wal flush LSN(如 pg_current_wal_flush_lsn()),并与目标事务提交时的 WAL 位点比较:当 flush LSN 大于等于该事务的提交 LSN 时,说明该事务的 WAL 已持久化。这样在不牺牲异步提交吞吐的前提下,按需实现最终一致确认。

关键词:异步提交 wal flush lsn 最终一致 pg_current_wal_flush_lsn | 来源:202102/20210224_02.md

Q:标准 VACUUM 与 VACUUM FULL 的区别是什么?为什么 VACUUM 后表文件往往不缩小?

标准 VACUUM 的目标是稳态空间复用而非最小化文件:它删除表和索引里的 dead row versions,把空间标记为未来可复用,通常不把空间归还给操作系统,除非表尾有整页全空且能拿到锁才截断。VACUUM FULL 则重写整张表把文件压缩到更小,但需要 ACCESS EXCLUSIVE 锁,且需要额外磁盘空间保存新副本直到完成。所以大删除后表文件不缩小是预期行为,关键看后续写入是否复用了这些空间;若业务不会再写入同等规模数据,才考虑 VACUUM FULL、CLUSTER、分区 drop/detach、在线重写工具(如 pg_repack)。

关键词:VACUUM FULL 空间复用 表膨胀 截断 pg_repack ACCESS EXCLUSIVE | 来源:202606/20260601_07.md

Q:标准 VACUUM 的三个阶段分别是什么?为什么不能一发现死元组就立刻释放 heap line pointer?

vacuumlazy.c 把 heap vacuum 分为三阶段:1) 扫描 heap page,剪枝和冻结 tuple,把需要从索引删除的 dead tuple TID 存入 TID store;2) 扫描索引,删除这些 TID 对应的 dead index entries;3) 回到 heap page,把对应 LP_DEAD line pointer 标记为 LP_UNUSED 让页内空间可复用。不能立即释放的原因:索引里可能还有指向该 TID 的条目,必须先批量清理索引,再回 heap 释放 line pointer,否则会出现索引指向已复用空间的不一致。

关键词:vacuum 三阶段 vacuumlazy TID store LP_DEAD LP_UNUSED | 来源:202606/20260601_07.md

Q:遇到 ‘database is not accepting commands to avoid wraparound data loss’ 或 ‘uncommitted xmin before xid cutoff needs to be frozen’ 报错怎么处理?

前者表示数据库已进入防 wraparound 保护模式,拒绝分配新 XID,要求立即 vacuum 推进冻结边界;这是数据安全告警,绝不能当作普通后台任务杀掉。处理方法是先解除阻塞者(长事务、idle in transaction、prepared transaction、复制槽、逻辑复制保留),然后对年龄最高的库/表执行 VACUUM(必要时 VACUUM FREEZE),让 relfrozenxid/datfrozenxid 前进。后者(found xmin before relfrozenxid)通常是数据损坏或 freeze 处理异常,需按报错定位具体表,检查是否有孤儿事务或需用 pg_surgery 之类工具修复。

关键词:wraparound 报错 not accepting commands freeze 救火 阻塞者 | 来源:202205/20220531_01.md

Q:金仓 V9 的 64 位事务号改造最可能采用哪种实现?为什么默认参数值没变?

金仓 V009R002C016 公开宣称支持 64 位 XID,但实现未公开。它把 VACUUM 相关参数(如 vacuum_freeze_table_age 等)数据类型升级为 int64 但默认值不变(仍是 200000000/400000000 等),只扩大上限。据此推测它走的是’分配空间 64 位、tuple header 仍 32 位’的混合方案(类似 xid8 思路):分配号 64 位不再循环,但 tuple header 的 t_xmin 仍是 32 位、仍需 freeze,只是 freeze 频率大幅降低。默认值不变是给 DBA 留一个’老 PG 运维经验继续管用’的兼容层,降低迁移心智成本。

关键词:金仓 64位XID 混合方案 分配层 tuple header freeze 兼容 | 来源:202609/20260904_01.md

Q:长事务为什么即使不锁住目标表,也会阻止 VACUUM 清理旧版本?

VACUUM 判断一个 dead tuple 能否删除,取决于它是否对所有现存事务都不可见。系统里只要有很老的快照(backend_xmin)、prepared transaction、复制槽 xmin/catalog_xmin 或逻辑复制保留需求,VACUUM 看到的很多旧版本仍是 recently dead,不能删。因此长事务、idle in transaction 即使不持有目标表锁,也会因其老快照而阻止 VACUUM 推进清理边界,导致 dead tuple 持续累积、膨胀。排查膨胀时应先找这些阻塞者。

关键词:长事务 快照 backend_xmin 复制槽 VACUUM 阻塞 膨胀 | 来源:202606/20260601_07.md

1.4 索引(41 条)

Q:B-tree 的 deduplication(去重)和 INCLUDE 列的关系是什么?

B-tree deduplication 是 PG13 引入的,把叶子页中重复的索引 key 压缩成一个 + posting list,减少索引体积。但 B-tree 有非 key 列(INCLUDE 列)时不使用 deduplication——源码和文档都明确这一点。因为 INCLUDE 列是 payload,不同行的 payload 不同,不能简单去重合并。所以 INCLUDE 覆盖索引虽然能减少回表,但会以失去 deduplication 收益为代价,索引可能更大。

关键词:deduplication INCLUDE btree 去重 覆盖索引 索引体积 | 来源:202605/20260530_11.md

Q:BRIN 索引的原理和适用场景是什么?它为什么能瘦身几百倍?

BRIN(Block Range Index)是块级范围索引:为每段连续的 heap 物理块(block range)记录被索引列在该范围内的最小值和最大值摘要。查询时先根据范围条件跳过不匹配的 block range,只访问可能匹配的块。它极其紧凑(每个 range 只有一条摘要),可瘦身几百倍,适合数据按索引列物理有序(如 IoT 时序数据、append-only 按时间写入)的大表。局限:强依赖数据物理顺序,数据随机分布时剪枝效果差;只适合范围/等值过滤(配合 recheck),不适合精确点查排序。PG14 起 BRIN 支持 multi-range min-max 和 bloom filter 两种 opclass,增强对随机数据和大量 distinct 值等值查询的支持。

关键词:BRIN 块级索引 block range min-max 时序 瘦身 摘要 | 来源:202605/20260526_11.md

Q:Bitmap 索引(on-disk)与 Bitmap Scan 的区别是什么?

Bitmap Index(on-disk,如 Greenplum/Oracle 支持)是一种持久化的索引类型:每个 distinct key 一条压缩 bitmap vector,标记哪些行号属于该 key,用 HRL/WAH 等压缩,适合低基数、读多写少、多条件组合的聚合查询。Bitmap Scan 则是执行期的扫描技术:用索引(可以是 B-tree、GIN 等任何支持 amgetbitmap 的 AM)把候选 TID 写进内存 TIDBitmap,再 BitmapAnd/Or 合并、按页顺序回表。二者本质不同:Bitmap Index 是存储结构,Bitmap Scan 是执行方式,B-tree 也能产出执行期 bitmap。PostgreSQL 官方内核没有 on-disk bitmap index AM(曾有 2006-2008 的 patch 后放弃)。

关键词:Bitmap Index on-disk Bitmap Scan HRL WAH 压缩 低基数 | 来源:202605/20260526_05.md

Q:Bloom 索引的原理是什么?它和 BRIN、Hash 的对比如何?

Bloom 索引用 Bloom filter 结构:每个索引行的每个字段经 hash 函数算出多个 bit 置位,多字段的 bit 相交得到该行对应的签名。查询时拿输入字段值算签名,若对应 bit 不全为 1 则一定不存在(无 false negative),全为 1 则可能存在(有 false positive,需回表 recheck)。它是扁平结构,每次查询都要遍历整个索引(用 buffer ring 读,类似顺序扫描)。对比:BRIN 更紧凑、支持范围查询但依赖物理顺序;Bloom 无物理顺序限制但只能等值查询、体积更大(可含多个字段);Hash 等值精确但体积远大于 Bloom 且不能多列。Bloom 适合对多字段做任意组合等值过滤的宽表。

关键词:Bloom 布隆过滤器 签名 false positive 等值查询 多字段 | 来源:202605/20260526_12.md

Q:Bloom 索引的签名长度和置位 bit 数如何选择?

创建 Bloom 索引时指定 signature length(签名总长)和每字段置位 bit 数(col1-col32)。理论公式:给定 false positive 概率 p,最优签名 bit 数 m = -n*log2(p)/ln2(n 为字段数),每字段置位数 k = -log2(p)。签名以 2 字节整数数组存储,m 可向上取整到 16 的倍数。索引大小约等于 (m/8 + 6)*N 字节(N 为行数,6 为 TID 指针)。false positive 率 p 对应单过滤器,表扫描时大约会得到 Np 个误报(需 recheck)。实际结果通常比公式更差,公式只用于选初始值。

关键词:Bloom signature 签名长度 置位数 false positive 参数选择 | 来源:202011/20201128_04.md

Q:GIN 索引创建为什么慢?PG18 如何并行化?

GIN 索引创建慢是因为要把多值列拆成元素、聚合同一 key 的 posting,且写入路径需要维护倒排结构。PG18 让 GIN 索引创建支持并行,把元素抽取和 posting 聚合分给多个 worker 并行处理,大幅缩短 GIN 建索引时间(尤其大表多值列)。此前 GIN 建索引是串行的,成为大批量导入和全文检索表建索引的瓶颈。

关键词:GIN 并行创建 PG18 多值列 posting 聚合 | 来源:202503/20250304_03.md

Q:GIN 索引的原理和适用场景是什么?它有什么局限?

GIN(Generalized Inverted Index,倒排索引)把多值列(数组、tsvector、jsonb、hstore)拆成元素,建立’元素 -> TID 列表’的倒排结构,适合’哪些行包含这些 key’的包含/匹配查询(@>、@@、? 等)。它支持多值类型按元素检索,一对多数据模型。局限:posting 里主要存 heap TID,不存词位置,短语搜索和 ranking 需要回表 recheck;写入通过 pending list(fastupdate)缓冲批量合并,但 pending list 未合并时查询要额外扫描,会带来性能抖动;GIN 通常不支持 index-only scan(只保存原值片段)。

关键词:GIN 倒排索引 posting list pending list tsvector jsonb 数组 | 来源:202605/20260526_08.md

Q:GiST 的 KNN(最近邻)排序为什么要求 distance 是子树距离下界?

GiST 支持 ORDER BY indexed_column <-> query LIMIT n,靠 opclass 提供 distance support function。关键要求是内部节点的 distance 必须是该子树里任意真实对象到 query 的距离下界,否则优先队列按距离出队时会把更近的真实对象排到后面,结果顺序错误。以 PostGIS 2D GiST 为例,内部节点返回 box 到 query box 的最小可能距离,叶子节点设 recheck=true 让执行器用真实 geometry 距离修正排序。所以 GiST KNN 不是’知道几何距离’,而是 opclass 提供了可用于优先队列的距离下界。

关键词:GiST KNN distance 距离下界 最近邻 PostGIS recheck | 来源:202605/20260526_09.md

Q:GiST 索引的定位是什么?它和 B-tree 的根本差别是什么?

GiST(Generalized Search Tree)是可扩展搜索树模板,把’搜索树的数据库工程部分’(页格式、锁、WAL、崩溃恢复、分裂、VACUUM)与’数据类型的搜索语义’(opclass 提供的 consistent/union/penalty/picksplit/distance 等函数)分离,适合空间相交、区间重叠、最近邻等非全序谓词。与 B-tree 的根本差别:B-tree 靠全序关系定位范围、路径通常唯一;GiST 内部节点保存覆盖子树的’谓词摘要’(如 R-tree 的 bounding box),靠 consistent() 判断子树是否可能命中,路径可以有多条,内部节点可以重叠,搜索可能下探多条路径。

关键词:GiST 可扩展搜索树 opclass predicate bounding box R-tree | 来源:202605/20260526_09.md

Q:Hash 索引的特点和演进是什么?

Hash 索引只支持等值查询,不支持范围、排序。历史上 PostgreSQL 的 hash 索引长期不被推荐(崩溃恢复不完整、不写 WAL),直到 PG10 起才完整支持 WAL 和崩溃恢复,变得可靠。相比 B-tree,hash 索引在纯等值点查、key 较长时可能更紧凑高效,但不能多列、不能排序、不能 index-only scan。PG18/19 还在继续优化 hash 索引(如 streaming read 用于 bulk delete、并行行车记录仪式的 IO 预取地基)。

关键词:Hash 索引 等值查询 WAL 崩溃恢复 演进 | 来源:202605/20260524_19.md

Q:HypoPG 虚拟索引是什么?它的作用和使用限制是什么?

HypoPG 是 PostgreSQL 的假设/虚拟索引扩展,用于在不真正创建索引的情况下,测试某个索引是否会被优化器采用、以及估算索引大小。它通过 hypopg_create_index() 把索引定义存入连接私有内存(不写 catalog、不膨胀表、不影响其他连接),然后用 EXPLAIN(不含 ANALYZE)查看优化器是否会使用该虚拟索引。限制:虚拟索引不存在,只能用于 EXPLAIN 不能用于 ANALYZE 实际执行;支持 btree/brin/bloom 等 AM;默认借用保留 OID 空间,同时最多约 2500 个虚拟索引。

关键词:HypoPG 虚拟索引 hypopg_create_index EXPLAIN 索引评估 | 来源:201908/20190804_02.md

Q:INCLUDE 覆盖索引的语义是什么?与多列索引的 key 列有什么区别?

INCLUDE 列是非 key 的 payload 列,只出现在叶子索引 tuple 中,不参与搜索、排序和唯一性约束。例如 CREATE UNIQUE INDEX ON t(x) INCLUDE (y),唯一性只约束 x,不约束 (x,y)。INCLUDE 列用于让 index-only scan 能返回更多列、避免回表。代价是宽列会显著扩大索引体积、更新 payload 列也要维护索引(可能破坏 HOT 更新机会)、且 B-tree 有 INCLUDE 列时不使用 deduplication。非 key 列不能作为 index scan 的搜索条件。

关键词:INCLUDE 覆盖索引 payload 非key列 唯一性 索引体积 | 来源:202605/20260530_11.md

Q:Index Only Scan 的触发条件是什么?为什么计划是 Index Only Scan 但 Heap Fetches 仍然很高?

Index Only Scan 需要三个条件:1) 索引访问方法能返回(或重构)查询需要的原始列值(B-tree 总是支持,GiST/SP-GiST 部分 opclass 支持,GIN/BRIN/Hash 通常不支持);2) 查询需要的所有列都在索引中(含输出列、过滤条件、连接条件);3) 目标 heap page 的 visibility map all-visible 位命中率高。计划是 Index Only Scan 但 Heap Fetches 高,是因为 MVCC 可见性信息在 heap tuple 上而不在索引条目里:当 VM 无法证明对应 heap page all-visible(刚导入、刚更新、长事务拖住 VACUUM),执行器仍要回表验证可见性。所以要看 EXPLAIN ANALYZE 的 Heap Fetches,而不是只看节点名。

关键词:Index Only Scan Heap Fetches visibility map all-visible 回表 | 来源:202605/20260530_11.md

Q:Multi-Index Bitmap Scan 是什么?什么时候比单个索引扫描好?

Multi-Index Bitmap Scan 不是磁盘上的 bitmap index,而是执行期把多个支持 amgetbitmap 的索引(B-tree、GIN、GiST、BRIN 等)扫描结果写进内存 TIDBitmap,再用 BitmapAnd/BitmapOr 合并,最后 BitmapHeapScan 按物理 block 顺序回表。它解决’多个条件各自有索引、但单索引都不够好’的中间地带,优势在中等选择率区域。代价是启动成本高、丢失索引顺序、work_mem 不足时 bitmap lossify 导致更多 recheck。OR 条件要求每一臂都能匹配到索引路径,否则无法整体转成 BitmapOr。

关键词:Multi-Index Bitmap Scan BitmapAnd BitmapOr TIDBitmap 多索引 | 来源:202605/20260530_13.md

Q:PG 为什么不会自动选择索引类型?DBA 如何选?

PG 不会根据查询自动选择/建议索引类型,需要 DBA 根据查询语义和数据特征手动选择:等值点查用 btree/hash;多值包含/全文检索用 GIN/RUM;空间/区间/最近邻用 GiST/SP-GiST;时序范围用 BRIN;多字段组合等值用 bloom;低基数组合用(外部)bitmap index。选择依据是查询操作符、选择性、数据物理顺序、更新频率和索引体积的权衡。辅助工具如 HypoPG、pg_qualstats 可帮助评估和发现缺失索引。

关键词:索引类型选择 btree gin gist brin bloom hash 权衡 | 来源:202109/20210904_01.md

Q:PG 的 index include 与索引组织表(IOT)有什么区别?

index include 是在索引叶子结点填充其他字段值(非 key payload 列),减少回表,达到类似聚簇/索引组织表的效果。它比传统 IOT 的好处是不限于主键维度:可以在任何索引、任何维度上 include 任意列,达到’任意组织’的效果。代价是 include 列不参与搜索/排序/唯一性,只用于返回,且增加索引体积。IOT(索引组织表)则整表数据按主键有序存储在主键索引的叶子里,表本身即索引。

关键词:index include IOT 索引组织表 覆盖索引 聚簇 | 来源:201905/20190503_03.md

Q:PG18 把命中同一索引的多个 OR 条件转换为 = ANY(…) 有什么好处?

PG18 优化器把命中同一索引的多个 OR 条件(如 WHERE a=1 OR a=2 OR a=3)转换为 = ANY(’{1,2,3}’) 形式,这样可以用一次数组索引扫描(SAOP,Scalar Array Operation)处理,而不是低效的 BitmapOr(对每个 OR 分支单独扫一次索引再合并 bitmap)。这减少了索引下探次数和 bitmap 构建开销,提升 OR 等值列表查询的效率。

关键词:OR 转 ANY SAOP BitmapOr PG18 等值列表 | 来源:202411/20241125_01.md

Q:PG18 的 index searches 统计(explain analyze)解决什么问题?

PG18 让 EXPLAIN ANALYZE 支持 index searches 统计,显示一次索引扫描实际执行的 index search 次数。这用于观察 skip scan、IN/ANY 数组条件等会产生多次索引下探的场景:Index Searches 数反映了扫描做了多少次独立定位,帮助 DBA 判断索引路径是否因为重复下探而变得昂贵,而不只是看’是否用了索引’。

关键词:index searches explain analyze PG18 统计 skip scan | 来源:202503/20250312_01.md

Q:PG18 的 index skip scan 优化做了什么?

PG18 为 B-tree 引入了 skip scan 优化:在复合索引缺少前导列等值条件但后续列有强选择条件时,允许优化器评估用 skip array 动态枚举前导列 distinct 值来做多次小范围搜索,替代整索引扫描。优化器会用被跳过列的 ndistinct 估算搜索次数,若搜索次数超过索引页数则回退。它解决了之前 PG 不支持 index skip scan、需要用递归 SQL 模拟的痛点,在低基数前导列 + 高选择后缀列场景收益明显。

关键词:index skip scan PG18 复合索引 skip array ndistinct | 来源:202504/20250406_01.md

Q:PG19 的 Bloom 索引扫描和 GIN 索引 VACUUM 的 streaming read 优化带来什么提升?

PG19 把 Bloom 索引的 bitmap scan(blgetbitmap)和 GIN 索引的 VACUUM 清理从同步循环读改成 streaming read(流式/异步预取读)。原理是把’发出读请求→阻塞等待→再发下一个’的串行 IO 改成异步预取、IO 合并、流水线,充分发挥 NVMe SSD 高并发 IO 能力。实测:Bloom 索引扫描用 io_uring 提升 3-7 倍,Bloom VACUUM 提升 30%,GIN VACUUM 提升 5 倍。索引越大收益越明显。前提是能提前知道要读哪些块且顺序确定。

关键词:streaming read Bloom GIN vacuum PG19 io_uring 异步预取 | 来源:202603/20260314_12.md

Q:PG19 的 GIN 索引垃圾回收为什么能狂飙 5 倍?

GIN 索引 VACUUM 需要遍历 GIN 索引所有页、清理指向已死亡 heap 元组的条目。传统实现是同步循环逐页读,串行 IO 无法发挥 NVMe 高并发能力。PG19(commit 6c228755)把 GIN VACUUM 的页面遍历改成 streaming read(异步预取 + IO 合并 + 流水线),在模拟高延迟 + debug_io_direct 测试下运行时提升高达 5 倍,索引页数和元组数越多优化越明显。

关键词:GIN vacuum 垃圾回收 streaming read PG19 5倍 | 来源:202603/20260314_08.md

Q:PostGIS 的空间索引和常用数据类型有哪些?

PostGIS 提供 geometry、geography、raster 等空间类型,支持点、线、面、栅格。空间索引主要用 GiST(默认)和 SP-GiST,加速空间关系运算(相交 &&、包含 @>、距离 <->、KNN 等)。核心函数如 ST_Intersects、ST_Distance、ST_Contains、ST_Transform、ST_AsGeoJSON、ST_AsMVT 等。PostGIS 3 拆离 raster 为独立扩展,并优化了空间排序(z-order、Hilbert)和 GEOS 性能。

关键词:PostGIS,GiST,geometry,geography,raster,空间索引 | 来源:202103/20210313_17.md

Q:PostgreSQL 12 nbtree v4 做了哪些关键增强?

PG12 的 nbtree 发展到第四版,主要三点:1) 把 heap ctid 加入 index leaf page 的 key value,使重复值的 heap tuples 在 leaf 里完全按物理行顺序存储,大幅提高扫描重复值时的效率(index & heap correlate=1);2) 由于 leaf 里有 ctid,key value 唯一,插入重复值时选择最右边的 leaf page 分裂,降低空间浪费(旧版随机选页分裂);3) internal/branch page 会 truncate 冗余 key value(如多列索引中不用于行定位的属性),让索引更小。另外还引入 REINDEX CONCURRENTLY、减少 B-tree 插入锁开销、pg_stat_progress_create_index 视图等。

关键词:nbtree v4 PG12 ctid leaf 分裂 truncate REINDEX CONCURRENTLY | 来源:201912/20191208_01.md

Q:PostgreSQL 的 Index Access Method(索引访问方法)是什么?它解决什么问题?

Index Access Method(AM)是 PostgreSQL 核心系统使用索引的统一接口边界:核心通过统一目录、能力标志和 C 回调表来使用索引,B-tree、Hash、GiST、SP-GiST、GIN、BRIN 这些具体索引类型在接口后面各自实现完全不同的数据结构和维护算法。它解决的是’数据库核心如何在不写死索引算法的情况下使用多种索引结构’的问题。每种 AM 的能力标志(能否支持排序、能否 index-only scan、能否多列、能否 bitmap scan 等)不同,优化器据此判断某索引能否满足查询。

关键词:Index Access Method AM 索引接口 回调表 能力标志 | 来源:202606/20260608_64.md

Q:PostgreSQL 的 global index(全局索引)是什么?为什么分区表需要它?

PG 目前只有本地索引(针对单表数据)、部分索引(partial index,带 where)、表达式索引。分区表若要对非分区键字段实施全局唯一/主键约束,就需要全局索引:因为本地索引只能保证单个分区内的唯一,无法跨分区。全局索引的 leaf 页需要 keyvalue -> tableoid + ctid(知道记录在哪个子表),而普通索引只是 keyvalue -> ctid。实现上可用 partial index + 多棵树构建,或全局分区索引(索引本身也分区)避免单棵索引过大。PG 社区尚未内置全局索引。

关键词:global index 全局索引 分区表 唯一约束 tableoid ctid | 来源:201912/20191206_02.md

Q:REINDEX CONCURRENTLY 解决什么问题?

REINDEX CONCURRENTLY 在线重建索引,不长时间阻塞 DML,用于替换普通 REINDEX(会锁表阻塞写入)。它分多阶段:用新名字建一个临时索引、扫描表填充、再原子切换,最后删除旧索引。适合:pg_upgrade 升级后重建 nbtree v4 索引、修复损坏索引、消除索引膨胀、重建到指定表空间等场景。PG14 起 reindex/reindexdb 支持指定 tablespace。失败可能留下 invalid 索引需清理。

关键词:REINDEX CONCURRENTLY 在线重建 锁 表空间 pg_upgrade | 来源:201903/20190330_02.md

Q:RUM 索引相比 GIN 的核心提升是什么?代价是什么?

RUM 是 GIN 的增强版倒排索引,核心提升是在 posting 里除 TID 外还存储 additional information(addInfo),例如 tsvector 的词位置信息、或 attach 绑定的业务字段(时间戳/数值等)。这让短语搜索、相关度排序(ORDER BY <=> LIMIT)可以在索引内完成,不必回表取 tsvector 位置或排序字段,Top-N 延迟更低。代价是索引条目更大、build/insert 慢于 GIN(无 pending list 缓冲)、使用 generic WAL records 导致 WAL 更大。适合’全文过滤 + 相关度/短语/业务字段排序’场景,不适合只做简单包含过滤的高频写入场景。

关键词:RUM GIN addInfo 短语搜索 ranking 排序 倒排索引 | 来源:202605/20260421_05.md

Q:SP-GiST 索引的原理和适用场景是什么?

SP-GiST(Space-Partitioned GiST)用空间划分树(如四叉树 quad-tree、kd-tree、radix tree/trie)组织数据,把数据空间递归划分成互不相交的子树,适合有明显空间/前缀划分结构的数据。常见应用:iprange/网络前缀(radix)、二维点(quad-tree/kd-tree)、文本前缀。与 GiST 的区别在于划分方式:GiST 内部节点可以重叠(如 bounding box),SP-GiST 的空间划分通常是互斥的。SP-GiST 适合范围查询、最近邻和前缀匹配等,PG14 起支持 leaf 结点 include 覆盖列,PG14 还支持 sort 接口加速 build。

关键词:SP-GiST 空间划分 quad-tree kd-tree radix iprange | 来源:202605/20260526_10.md

Q:Skip Index Scan 是什么?它绕过左前缀规则吗?

Skip Index Scan(B-tree skip scan optimization)不是新索引结构,也不是绕过左前缀规则的万能钥匙,而是 B-tree 扫描中的重定位策略:当多列索引缺少前导列等值条件、但后续列有强选择性条件时,把问题改写成多次小范围 index search(动态枚举前导列的 distinct 值:x=1 AND y=7700、x=2 AND y=7700……),替代一次大范围扫描。只有当前导列 distinct 数很少、后续列条件足够精确、统计信息可信时才划算。它不体现在计划节点名里,要看 EXPLAIN ANALYZE 的 Index Searches 次数。

关键词:Skip Index Scan 左前缀 复合索引 Index Searches 重定位 | 来源:202605/20260530_15.md

Q:bottom-up index deletion(PG14)解决什么问题?

PG14 增强 nbtree 的 index tuple deletion,引入 bottom-up index deletion(自底向上索引删除)。它针对频繁更新索引列引起的索引分裂和膨胀问题:传统方式下,即便某页的索引项大部分已死,也要等 VACUUM 整页处理;bottom-up 删除可以在普通索引页分裂时,从叶子页自底向上删除已死的索引项,回收空间、减少分裂和索引膨胀,大幅缓解频繁更新索引列导致的索引分裂和膨胀问题。

关键词:bottom-up index deletion nbtree PG14 索引膨胀 分裂 | 来源:202101/20210116_01.md

Q:pg_repack 和 REPACK CONCURRENTLY(PG19)如何在线整理表?

pg_repack 是外部扩展,pg_repack(REPACK)在 PG19 引入 CONCURRENTLY 选项。传统 REPACK/CLUSTER 需要 ACCESS EXCLUSIVE 锁全程阻塞读写。REPACK CONCURRENTLY 的核心原理是利用逻辑解码捕获 repack 期间的业务变更,在最终切换文件前把这些变更应用到新表文件,从而把阻塞窗口缩短到最后的锁升级、第二阶段回放和文件切换这一小段(仍需短暂 ACCESS EXCLUSIVE 锁,不是绝对零停机)。它用于在线回收表膨胀空间、整理物理存储。

关键词:REPACK CONCURRENTLY pg_repack 逻辑解码 在线整理 锁 PG19 | 来源:202604/20260407_02.md

Q:pg_trgm GIN 索引如何支持 like ‘%xxx%’ 模糊查询?

pg_trgm 扩展用 trigram(连续三字符)把文本切分成 token 建立 GIN 倒排索引。like ‘%xxx%’ 这种中缀模糊查询会被转成 trigram 匹配:查询串切成 trigram,用 GIN 找出包含这些 trigram 的行,再回表 recheck 确认。它把’无索引的全表扫’变成’倒排候选 + 回表验证’,大幅提升中缀模糊查询效率。代价是 trigram 对短串(<3 字符)效果差,且索引体积大。

关键词:pg_trgm trigram GIN 模糊查询 like 中缀匹配 | 来源:202212/20221221_03.md

Q:为什么 GIN 倒排索引启动和 recheck 代价高?

GIN 倒排索引的启动代价高:查询需要先定位多个 key 的 entry,再取它们的 posting list,当命中 key 很多或 posting 很长时,构建候选 bitmap 的成本高。recheck 代价高:GIN 只存 TID 不存完整值/位置,匹配后要回表 recheck(如 tsvector 短语位置、数组重叠语义、jsonb 包含语义),候选多时回表和 recheck 开销大。另外 fastupdate 的 pending list 未合并时会额外扫描。这些导致 GIN 在高命中、复杂谓词场景下启动慢、recheck 重。

关键词:GIN 倒排 recheck 启动代价 posting list pending list | 来源:202109/20210915_03.md

Q:为什么 PostgreSQL 允许在相同字段上创建多个索引?

PostgreSQL 不强制索引唯一性,相同字段可以创建多个索引(如不同 AM、不同 opclass、不同 include 列、不同部分索引条件)。原因是指标选择依赖具体的查询形态和语义:不同 opclass 支持不同操作符(如 text_pattern_ops 支持 LIKE 前缀、默认 ops 不支持),不同 AM 适用不同查询(等值用 btree/hash、包含用 GIN、范围用 BRIN 等)。多个索引让优化器能针对不同查询选择最优路径。但这也是槽点:可以重复创建一模一样的索引,造成存储和写入浪费,DBA 需要自己监控冗余索引。

关键词:重复索引 相同字段 opclass 索引选择 冗余 | 来源:201912/20191217_01.md

Q:为什么与检索字段类型不一致的输入条件有时不能采用索引?

索引条目的比较依赖操作符的语义和类型。当查询条件里的值类型与索引列类型不一致时,PG 需要做隐式类型转换(cast)。如果转换发生在索引列这一侧(例如把列 cast 成条件值的类型,或运算符没有对应索引列的 operator class),优化器就无法直接使用该列的索引(因为索引里存的是原始类型的排序/结构),只能全表扫描或回表过滤。跨类型的操作符必须有匹配的 opclass,且转换不能在索引列上发生,才能走索引。

关键词:类型转换 cast opclass 索引失效 隐式转换 | 来源:202112/20211224_05.md

Q:为什么优化器不选择索引扫描?常见原因有哪些?

常见原因:1) 统计信息陈旧或缺失,优化器低估/高估了行数和选择性(基数估计错误);2) 查询选择性太低,回表随机 IO 成本高于顺序扫描,优化器认为 seq scan 更便宜(尤其 random_page_cost 配置偏高);3) 索引列被表达式/函数包裹,无法下推谓词;4) 类型不一致导致隐式转换破坏索引;5) 查询返回列过多、覆盖不足,index only scan 不可行;6) enable_indexscan/enable_bitmapscan 等开关被关闭;7) 索引列序不匹配查询的前导列,且 skip scan 不划算。诊断要看 EXPLAIN ANALYZE 的实际行数 vs 估算行数、cost 设置和索引可用性。

关键词:优化器 不选索引 统计信息 选择性 seq scan random_page_cost | 来源:202211/20221111_02.md

Q:为什么创建索引会堵塞 DML?如何在线创建索引?

普通 CREATE INDEX 需要对表加 ShareLock,会阻塞对表的 DML(写入)。在线创建索引用 CREATE INDEX CONCURRENTLY:它在不长时间阻塞 DML 的情况下分多阶段建索引,先建一个无效索引、扫描表、再在 pg_index 里标记有效,只在最后的元数据更新瞬间需要短暂锁。代价是更慢、更耗资源,且失败可能留下 invalid index 需要清理。REINDEX CONCURRENTLY 同理用于在线重建索引。

关键词:CREATE INDEX CONCURRENTLY 在线建索引 锁 DML invalid index | 来源:202112/20211224_03.md

Q:为什么创建索引慢?影响 CREATE INDEX 速度的因素有哪些?

创建索引慢的原因:1) B-tree 构建需要对输入数据排序,若排序数据放不下 maintenance_work_mem 就溢出到磁盘(外部排序),内存越小越慢;2) 表越大、索引列越宽、索引越多越慢;3) 并行创建索引(PG11 起 CREATE INDEX 支持并行)可加速,但受 max_parallel_maintenance_workers 限制;4) CONCURRENTLY 创建比普通创建慢且更耗资源。加速手段:调大 maintenance_work_mem、用并行 CREATE INDEX、批量导入时先删索引后重建、PG14 起 GiST/SP-GiST 支持 sorted build、PG17 支持 BRIN 并行创建。

关键词:CREATE INDEX 慢 maintenance_work_mem 排序 并行 max_parallel_maintenance_workers | 来源:202201/20220118_05.md

Q:为什么有的函数不能被用来创建表达式索引?

表达式索引要求索引表达式是 immutable(不可变的),即对相同输入永远返回相同结果、不依赖外部状态。只有 immutable 函数才能建表达式索引,因为索引值在插入时计算并存储,查询时必须能保证用相同表达式算出相同结果来匹配索引。stable/volatile 函数(如 now()、random()、依赖配置的函数)结果会变,无法用于表达式索引,否则查询时算出的值与索引里存储的值对不上。

关键词:表达式索引 immutable 函数 stable volatile | 来源:202112/20211224_04.md

Q:为什么有的索引不支持字符串前缀匹配(like ‘xxx%’)而有的支持?

字符串 like ‘xxx%’ 前缀匹配能否走索引取决于 operator class 和 collation。默认 text_ops 使用 C 库 locale 比较,非 C collation 下 btree 无法保证前缀有序性,因此不走索引。解决办法:用 text_pattern_ops(按字节比较)、varchar_pattern_ops 这类 opclass 建索引,或用 collate ‘C’。这类 pattern_ops 索引专门支持前缀匹配。PG15 起 starts_with() 提供 planner support,collation 为 C 时可走 btree/sp-gist。

关键词:pattern_ops collation like 前缀 字符串索引 | 来源:202105/20210514_04.md

Q:为什么有的索引不支持字符串前置 like / ~ 查询?

字符串 LIKE ‘xxx%’ 或 ~ ‘^xxx’ 前缀匹配能否走索引,取决于索引使用的 operator class(opclass)和排序规则(collation)。默认的 text opclass 基于 C 库的 locale 排序规则,很多非 C collation 下无法证明前缀比较能利用 btree 的有序性,导致不能走索引。要支持前缀匹配,通常需要:1) 使用 text_pattern_ops / varchar_pattern_ops 这类按逐字节比较的 opclass;或 2) collation 为 C。PG15 起为 starts_with() 提供了 planner support function,在 collation 为 C 时字符串前缀匹配可走 btree/sp-gist 索引。

关键词:like 前缀匹配 opclass collation pattern_ops 索引 | 来源:202112/20211220_10.md

1.5 事务 / 锁 / 并发(79 条)

Q:COMMIT AND CHAIN 语法的作用是什么?

COMMIT [WORK|TRANSACTION] [AND [NO] CHAIN] 中,AND CHAIN 表示当前事务结束后立即启动一个新事务,且新事务继承刚结束事务的事务特征(transaction characteristics,如隔离级别、READ ONLY 等)。不指定 CHAIN 则不启动新事务。这减少了开启新事务的交互次数(网络往返),尤其适合需要连续多事务且特征相同的场景。示例:事务内 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ 后,循环里 COMMIT AND CHAIN / ROLLBACK AND CHAIN,每次新事务都保持 repeatable read 隔离级别(事务特征被继承)。事务特征包括 ISOLATION LEVEL、READ WRITE/READ ONLY、[NOT] DEFERRABLE 等,通过 SET TRANSACTION 或 SET SESSION CHARACTERISTICS AS TRANSACTION 设置。这对需要减少交互次数、保持事务特征一致的批量处理场景有用。

关键词:COMMIT AND CHAIN,事务特征,隔离级别,继承,交互次数 | 来源:201903/20190330_07.md

Q:FOR UPDATE SKIP LOCKED 的工作原理是什么?它适合和不适合什么场景?

SKIP LOCKED 解决多消费者队列的队头阻塞:多个 worker 按同一顺序领取任务,没有 SKIP LOCKED 时 Worker B 会等在队头被锁的行上;用 FOR UPDATE SKIP LOCKED 后遇到拿不到行锁的候选行不等待、跳过、继续找后面的可锁行。实现:锁定子句对应 LockWaitPolicy 枚举的 LockWaitSkip(LockWaitBlock/LockWaitSkip/LockWaitError),执行器 LockRows 节点从子计划取候选行,调用 table_tuple_lock(),返回 TM_WouldBlock 就 goto lnext 取下一条;heap 层 LockWaitSkip 用 ConditionalLockTupleTuplock/ConditionalMultiXactIdWait/ConditionalXactLockTableWait 条件尝试。关键语义:1) 返回结果有意不完整,跳过的行不代表不存在;2) 只作用行级锁,表级 ROW SHARE 锁仍按普通方式获取;3) LIMIT 对成功返回的行生效,不是先截断再锁;4) 不保证公平,热点行可能饥饿,需超时回收和扫尾。适合队列/批处理/补偿任务;不适合金融撮合、库存精确扣减等强顺序场景。SKIP LOCKED 不能和 WITH TIES 同时使用。

关键词:SKIP LOCKED,FOR UPDATE,队列消费,LockWaitSkip,TM_WouldBlock,队头阻塞 | 来源:202606/20260601_02.md

Q:GetOldestXmin 是什么?为什么"曾获得过快照的空闲事务"比普通只读事务更危险?

GetOldestXmin 是系统中存在的最老事务(不管 2pc、空闲事务、执行中 SQL,也不管隔离级别,只看最老的),它决定 VACUUM 能清理哪些垃圾版本。问题在于:对 RC 隔离级别,SQL 快照实际指 SQL 发起时的状态,发起前已提交事务产生的垃圾对该 SQL 已不需要看到;但 GetOldestXmin 只看事务启动后获得的第一个快照,在这个快照之后产生的垃圾 tuple 都不会被清理。所以"曾获得过事务快照"的空闲事务(例如 begin 后 select 过又挂着)会固定 xmin,非常危险;而空闲中的只读事务(从未获得快照)不影响,因为没有 backend_xid/xmin。同理,已 prepare 但未 commit/rollback 的 2pc 也危险,GetOldestXmin 包含 2pc 开启时的快照。验证方法:vacuum verbose 输出中 “1 dead row versions cannot be removed yet, oldest xmin: XXX” 的 XXX 就是卡住的 XID。优化:内核层可在 GetOldestXmin 时用当前最小未分配事务号代替空闲/2pc 事务的 oldestxmin;参数层用 old_snapshot_threshold 和 idle_in_transaction_session_timeout。

关键词:GetOldestXmin,空闲事务,2pc,膨胀,vacuum,oldest xmin | 来源:201907/20190720_01.md

Q:LWLock 的等待事件如何解读?ProcArray / BufferMapping / WALInsert / WALWrite 分别代表什么热点?

LWLock 等待事件是共享内存热点信号,不是业务锁冲突信号。常见映射:1) ProcArray:活跃事务数组,GetSnapshotData() 拿 LW_SHARED 并行取快照,事务结束更新需 LW_EXCLUSIVE,高并发快照获取、事务集中提交、连接数过高、长事务都会造成该竞争。2) BufferMapping:共享缓冲区映射表(分 128 个分区),对 BufferTag 哈希后拿分区锁,指向共享缓冲区映射竞争,可能原因包括随机访问太分散、工作集超过缓存、热点块高频替换。3) WALInsert:保护 WAL 记录插入内存 buffer(8 个插入锁),偏 WAL 内存插入竞争。4) WALWrite:保护 WAL buffer 写盘/刷盘路径,偏提交频率、同步提交、存储延迟。排查顺序:先区分 wait_event_type(Lock/LWLock/IO/Buffer/IPC),再按 wait_event 分类,用 pg_wait_events 查事件描述,回到具体子系统看证据,最后用时间序列确认是持续热点还是瞬时尖峰。不要一看到 BufferMapping 就盲目调大 shared_buffers。

关键词:LWLock,ProcArray,BufferMapping,WALInsert,WALWrite,pg_wait_events | 来源:202606/20260608_41.md

Q:LWLock、Spinlock、重量锁、谓词锁(SIReadLock)这四类锁的区别和适用场景是什么?

PostgreSQL 多进程架构下有四类进程间锁:1) Spinlock:保护极短内部状态(几十条指令内),等待者忙等,不提供死锁检测,超过几十条指令或跨内核调用就不该用。2) LWLock:保护共享内存数据结构(ProcArray、BufferMapping、WALInsert、WALWrite 等),支持 LW_SHARED/LW_EXCLUSIVE 模式,等待时睡眠不烧 CPU,无死锁检测、无普通锁超时语义,不适合可能长等待的业务级互斥。3) Heavyweight lock(重量锁):保护 SQL 可见对象(relation、transactionid、tuple、object、advisory),支持多种锁模式、冲突矩阵、完整死锁检测、事务结束自动释放,可观测于 pg_locks。4) Predicate lock(SIReadLock):Serializable 下记录读写依赖,不是普通读写锁模式,不阻塞普通操作。关键点:业务 SQL 看到 wait_event_type=‘Lock’ 优先查 pg_locks 和对象锁冲突;看到 ‘LWLock’ 要回到共享内存子系统和 wait_event 名称判断。lock_timeout 只作用于 SQL 锁等待,对 LWLock 无效。

关键词:LWLock,Spinlock,重量锁,谓词锁,SIReadLock,wait_event_type | 来源:202606/20260608_41.md

Q:MVCC 读不阻塞写、写不阻塞读是如何实现的?为什么普通 SELECT 还要 AccessShareLock?

PG 的 MVCC 通过快照 + 行版本实现读写互不阻塞:每个 SQL 看到某个时间点的数据快照,读只查可见性(xmin/xmax 与快照比对),不阻止别人写新版本;写产生新行版本,不覆盖旧版本,所以不阻止别人读旧版本。因此普通 SELECT 和普通 UPDATE 之间不互相阻塞(这正是 MVCC 相对传统 2PL 的优势:传统两阶段锁下读写会互相阻塞)。那为什么普通 SELECT 还要拿 AccessShareLock(表级锁)?因为 MVCC 只解决"读哪个版本",不解决"结构能不能被同时改"——AccessShareLock 与 AccessExclusiveLock 冲突,保证 SELECT 执行期间表结构(schema)不会被 DROP/TRUNCATE/ALTER 改变,否则查询会访问到正在被删除/重写的表和元数据。所以 MVCC 处理行版本可见性,表锁处理对象级结构保护,两者是正交的。

关键词:MVCC,读写不阻塞,AccessShareLock,快照,两阶段锁,表结构 | 来源:202606/20260608_40.md

Q:NOWAIT 和 SKIP LOCKED 有什么区别?它们只作用于行锁吗?

NOWAIT 和 SKIP LOCKED 是 SELECT FOR UPDATE/SHARE 的等待策略(不是锁强度)。区别:NOWAIT 表示如果要锁的行发生锁冲突,立即报错(LockWaitError),不等待;SKIP LOCKED 表示跳过有锁冲突的行不等待,例如 10 行符合条件但 3 行冲突,就跳过着 3 行锁其他 7 行(LockWaitSkip)。锁强度由 FOR UPDATE/NO KEY UPDATE/SHARE/KEY SHARE 决定,等待策略由 NOWAIT/SKIP LOCKED 决定。重要限制:NOWAIT 和 SKIP LOCKED 只作用于行级锁,所需的 ROW SHARE 表级锁仍按普通方式取得;如果表级锁也不想等待,应先显式 LOCK TABLE … NOWAIT。另外 PG 不支持 update|delete … skip locked|nowait 语法,需用 CTE + FOR UPDATE SKIP LOCKED 模拟一次交互:WITH picked AS (SELECT id FROM t WHERE … FOR UPDATE SKIP LOCKED) UPDATE … FROM picked WHERE …。多个锁定子句同时存在时,NOWAIT 优先级高于 SKIP LOCKED(枚举顺序被 applyLockingClause() 用来处理优先级)。

关键词:NOWAIT,SKIP LOCKED,等待策略,行锁,CTE,LockWaitError | 来源:202110/20211002_04.md

Q:PG 14 为什么增加 startup 进程与 backend 进程之间的死锁检测?

在基于流复制的只读实例(hot standby)场景,recovery conflict on lock 涉及的死锁可能发生在 hot-standby backend 和 startup 进程之间。之前的 bug:如果 backend 拿了 AccessExclusiveLock 最终触发死锁,能被 backend 内调用的死锁检测器发现;但如果 startup 进程拿了 AccessExclusiveLock 触发死锁,则无法被检测到,死锁可能在 deadlock_timeout 后依然存在。根因是处理 recovery conflict on lock 的代码完全没考虑死锁情形,假设涉及 startup 和 backend 的死锁能被 backend 内调用的死锁检测器检测到——这个假设是错的。修复(commit 8900b5a9,backpatch 到 9.6):当处理 recovery conflict on lock 达到 deadlock_timeout 时,startup 进程也调用死锁检测器——具体是请求所有持有冲突锁的 backend 检查自身是否死锁。9.5 因缺少基础设施代码且已是最后一个小版本,决定不 backpatch。

关键词:startup进程,死锁检测,流复制,hot standby,recovery conflict,deadlock_timeout | 来源:202101/20210107_03.md

Q:PG 14 为什么引入 idle_session_timeout?它和 idle_in_transaction_session_timeout 有什么区别?

idle_session_timeout(PG14 引入)用于自动终止长时间空闲的会话(idle,未开启事务的空闲连接),解决大量 idle 连接的问题。idle 连接产生的原因:DB 性能抖动导致业务拥塞,业务端新建更多连接处理请求,但没配置自动释放或未到释放超时。危害:1) 每个会话有私有内存,缓存访问过的对象元数据(尤其分区表每个分区独立元数据),连接多了可能触发 OOM;2) 占满连接导致其他业务连接不足。区别:idle_session_timeout 管"未开启事务的空闲会话",idle_in_transaction_session_timeout 管"已开启事务但空闲(idle in transaction)的会话"——后者危害更大(持锁、固定 xmin)。PG14 之前的版本没有原生 idle_session_timeout,靠第三方插件 pg_timeout 实现。这两个参数是防连接池泄漏和会话泄漏的数据库层兜底。

关键词:idle_session_timeout,idle_in_transaction_session_timeout,空闲会话,连接泄漏,PG14 | 来源:202101/20210107_06.md

Q:PG 为什么说"锁粒度只能到行",字段级锁/多版本控制缺失对业务有什么影响?

PG 的行锁是锁管理的最小颗粒,MVCC 多版本控制也是行级别。这意味着:1) 同一行不同字段无法并行更新(更新 info 和 ts 会互相阻塞);2) 对 JSON、array、tsvector 等多值类型,无法做到元素级的锁和元素级多版本。业务影响:需要经常并行更新同一行不同字段/不同元素的场景(如高频热点行、大 JSON 文档的并发修改)会遭遇行锁争用,吞吐受限。现有解法都是绕行:拆表(把需并行更新的字段拆到多表用 PK 关联)、合并更新到同一会话/事务。这背后的反思是:为什么锁粒度必须止于行?为什么多版本不能下推到字段/元素级?这是产品演进的潜在方向(类似某些列存或文档数据库的字段级 MVCC),PG 社区目前未实现。

关键词:锁粒度,字段级锁,行级锁,MVCC,元素级,JSON,热点行 | 来源:202404/20240416_01.md

Q:PG 为什么难打印慢 SQL 的锁等待信息?有哪些变通方案?

问题:log_min_duration、auto_explain、pg_stat_statements 都不单独统计 SQL 的锁等待时长——log_min_duration 打印超时 SQL 但不记录锁等待耗时;auto_explain 打印执行计划但锁等待耗时算在整个 SQL 里不单独拆;log_lock_waits 记录等待超 deadlock_timeout 的会话但不打印 SQL,且每隔 deadlock_timeout 打一条难汇总。这导致分析锁等待引起的问题非常麻烦,且锁等待通常是业务逻辑问题,需开发者介入,门槛高。变通:1) 经常采集 pg_locks、pg_stat_activity 动态视图做等待统计(如 pgsentinel 插件、AWS performance insight 类似物);2) 有开发能力的企业用 eBPF 采样做低开销采集(如 DBdoctor、pg-lock-tracer)。期望内核未来在 log_min_duration/auto_explain 记录锁等待时长,log_lock_waits 能汇总同一请求的锁等待信息(含 SQL 和堵塞信息)。

关键词:锁等待,慢SQL,log_min_duration,auto_explain,log_lock_waits,pgsentinel,eBPF | 来源:202109/20210922_04.md

Q:PG 函数和存储过程内的事务控制能力有什么区别?为什么自治事务支持不完整?

PG 的 1 个函数是 1 个原子操作,要么全部成功要么全部回滚(注意:exception 里算一个新子事务,触发 exception 时函数体操作全部回滚,exception 体内执行正常则可提交)。限制:1) 函数内不能使用 commit、rollback、savepoint 等事务控制语句;2) 存储过程(procedure)内只能使用 commit、rollback,不能使用 savepoint、rollback to savepoint、release savepoint;3) 没有真正的自治事务(autonomous transaction)。这影响用 function/procedure 做复杂业务逻辑的场景,无法灵活处理事务控制。模拟 savepoint/rollback to savepoint 用变量 + exception 很复杂,且嵌套 exception 时会报 cannot commit while a subtransaction is active。变通方案:通过 dblink 开启新会话来模拟自治事务,但复杂度大增。这与 Oracle/DB2 的语句级回滚 + 自治事务差距明显,是 PG 相对 Oracle 的兼容性短板之一。

关键词:函数,存储过程,自治事务,事务控制,savepoint,exception,dblink | 来源:202110/20211002_01.md

Q:PG 增大字段长度会锁表吗?DDL 锁等待为什么会引发"雪崩"?

  1. 所有 DDL 操作都会锁表(堵塞读写);2) DDL 有的只需修改元数据(毫秒级),有的需要 rewrite table(取决于表大小和索引多少)。增大字段长度这类操作需要 AccessExclusiveLock,与所有模式冲突。危险点:如果 DDL 未能及时获取表的排他锁(例如有其他长事务持有表的共享锁),DDL 的排他锁就进入等待队列,此时会堵塞其他该表的一切 DML 和查询操作——这就是"雪崩":一个 DDL 排队,后面所有普通读写都排到它后面,即使它们与最早的持锁者不冲突,也被等待队列顺序软阻塞。建议:1) 评估 DDL 耗时;2) 低峰操作;3) 必要时清理堵塞 DDL 的长事务或后台任务(autovacuum);4) 执行 DDL 前设置 lock_timeout=‘1s’ 防止雪崩,拿不到锁就快速失败退出而不是排队。若 rewrite 时间太长,可考虑模拟 online DDL(如 pg_repack 或新建表+切换)。

关键词:DDL,锁表,AccessExclusiveLock,雪崩,lock_timeout,rewrite table | 来源:202109/20210927_01.md

Q:PG 的 XID 是 32 位,wraparound(事务回卷)如何影响事务和 vacuum?

XID 是 32 位,超过约 40 亿会回卷,导致旧版本看起来像未来版本。为避免,每个表需周期性 vacuum 并把足够老的行版本标记为 frozen,relfrozenxid、datfrozenxid、autovacuum_freeze_max_age 等围绕此边界工作。长事务、prepared transaction、复制槽的 xmin/catalog_xmin 会固定清理边界,冻结无法推进,最终触发 anti-wraparound autovacuum 甚至拒绝分配新 XID。

关键词:XID,wraparound,事务回卷,冻结,vacuum | 来源:202606/20260608_40.md

Q:PG12 的 COMMIT/ROLLBACK AND CHAIN 是什么?

PG12 支持 COMMIT AND CHAIN 和 ROLLBACK AND CHAIN,在结束当前事务的同时立即开启一个继承上一事务特征(隔离级别等)的新事务,减少客户端交互次数和事务边界切换开销。适合需要连续多个事务、又希望减少往返的批处理场景。

关键词:COMMIT AND CHAIN,ROLLBACK AND CHAIN,事务继承,PG12 | 来源:201903/20190330_07.md

Q:PG14 为什么考虑增加 pg_lwlock_blocking_pid 做 lwlock blocking 诊断?

当前 LWLock(轻量锁)等待没有跟踪数据,只能从 wait_event 知道"在等某个 lwlock 事件"(如 WALInsert),无法知道谁堵塞了谁。PG14 曾讨论引入 pg_lwlock_blocking_pid 函数支持 lwlock 等待跟踪,返回等待者的请求模式、最后一个持有锁的 PID、持有模式、持有者数量等信息(如 (LW_WAIT_UNTIL_FREE,10232,LW_EXCLUSIVE,1))。难点是:LWLock 结构很轻(tranche + state 32 位原子 + waiters 链表),为了跟踪阻塞关系需要改锁结构、记录等待/持有关系,锁的存储可能变得更重,社区仍在讨论中(权衡诊断能力 vs 每个轻量锁的内存/性能开销)。这是 PG 在可观测性上的探索:重量锁已有 pg_blocking_pids 完整诊断,轻量锁因高频低延迟特性,很难在不增加开销的前提下实现同等诊断,是内核可观测性设计的典型取舍。

关键词:LWLock,pg_lwlock_blocking_pid,阻塞诊断,等待跟踪,WALInsert | 来源:202011/20201110_04.md

Q:PG14 的 pg_locks.wait_start 字段和 PG18 的 log_lock_failure 参数分别解决什么问题?

PG14 增加 pg_locks.wait_start 字段跟踪锁等待开始时间:之前分析锁等待时长只能 join pg_stat_activity 用 query_start 或 state_change 近似,无法得到精确锁等待时长;wait_start 记录锁开始等待的时间点,便于排查等待耗时和先后顺序。为避免 gettimeofday 频繁调用带来的性能影响,复用了 deadlock_timeout 定时器启动时已调用的 gettimeofday 结果;fast-path 锁不会等待,wait_start 为 0。PG18 增加 log_lock_failure GUC(默认 off)记录锁获取失败详细日志:当 SELECT … NOWAIT 因锁冲突立即失败时,记录所有持有或等待该锁的进程信息(pid、mode),帮助诊断锁失败原因;为防日志过载,排除 SKIP LOCKED(跳过的锁太多会产生噪音),未来可扩展到 LOCK TABLE … NOWAIT 等命令。二者分别增强锁等待"时长观测"和锁失败"原因诊断"能力。

关键词:pg_locks,wait_start,log_lock_failure,NOWAIT,锁等待,日志 | 来源:202102/20210207_01.md

Q:PG14 逻辑复制的 logical decoding 如何支持 2PC(两阶段事务)?

PG14 扩展了内置逻辑复制的 output plugin API,新增 6 个 callback 支持解码 prepared xacts:begin_prepare、filter_prepare、prepare、commit_prepared、rollback_prepared、stream_prepare。之前的限制:两阶段事务在 subscriber 上被翻译成普通事务,GID 不转发给 subscriber,两个阶段命令都不通知 subscriber。这个 patch 提供基础设施,让逻辑解码插件能被告知 PREPARE TRANSACTION、COMMIT PREPARED、ROLLBACK PREPARED 命令及对应 GID,语义区别是事务尚未提交、之后可能 abort。test_decoding 插件实现了这些新方法。这为下游按 2PC 边界复制事务(保持 prepare/commit/rollback 语义)打基础,配合后续 ReorderBuffer 在 prepare 时解码。注意这与本地 PREPARE TRANSACTION 语义是不同层次:本地 2PC 是作为 XA 参与者支持外部全局事务,逻辑复制 two_phase 决定 WAL decoding 和 subscriber 是否按 prepare/commit prepared 事件复制。

关键词:逻辑复制,logical decoding,2PC,output plugin,prepared xacts,GID | 来源:202101/20210101_01.md

Q:PG16+ 官方文档新增的"事务处理内部原理"章节覆盖了哪些内容?

PG16+ 官方文档新增 Chapter 74 Transaction Processing,提供事务管理系统内部原理概述(此前事务内部细节散落在源码 README 和文档各处)。章节包括:74.1 Transactions and Identifiers(事务与标识符——XID、VXID、xid8、FullTransactionId、子事务 XID 分配规则);74.2 Transactions and Locking(事务与锁——事务如何获取/持有锁、锁与事务生命周期的关系);74.3 Subtransactions(子事务——pg_subtrans、savepoint、子事务可见性与父事务关系);74.4 Two-Phase Transactions(两阶段事务——PREPARE TRANSACTION/COMMIT PREPARED/ROLLBACK PREPARED、prepared transaction 的锁和恢复语义)。这个章节把分散在 mvcc.sgml、xact.sgml、wal.sgml 及源码 README(access/transam/README、lmgr/README)中的事务内核知识系统化,是理解 PG 事务/锁/并发内部机制的重要官方入口。

关键词:事务内部原理,官方文档,Transaction Processing,XID,子事务,2PC | 来源:202310/20231016_02.md

Q:PG17 的 WAL 锁竞争优化做了什么?为什么需要 write barrier?

PG17 为"无锁读取 WAL buffer 内容"做准备,做了两个前置优化(commit c3a8e2a7 和 766571be):1) xlblocks 数组元素改用 64 位原子(pg_atomic_uint64),避免之前需注释解释为何无锁读不会出现 torn reads(撕裂读);2) 在 AdvanceXLInsertBuffer() 中增加 write barrier——先把 xlblock 成员标记为 InvalidXLogRecPtr,发出 write barrier,再初始化它,确保 xlblock 在内容初始化期间不会"看起来有效"(旧页可能部分清零但看似有效)。读取方不持锁读值时若得到 InvalidXLogRecPtr 是安全的,会抓 mapping lock 重试。背景是 WAL buffer 是高频写路径,WALInsert/WALWrite/WALBufMapping 等 LWLock 竞争是高并发小事务瓶颈之一,通过让读 WAL buffer 内容无需持锁,减少锁竞争、提升 WAL 路径并发。

关键词:WAL,锁竞争,write barrier,64位原子,AdvanceXLInsertBuffer,PG17 | 来源:202312/20231220_01.md

Q:PG18 增加 fast-path lock slots 提升什么性能?

PG18 增加 fast-path lock slots 数量,提升访问多对象的高并发 OLTP 业务性能。访问对象多时原本 fast-path 槽位不足会退化为重路径,增大槽位后更多锁走快捷通道,降低锁管理开销,提升高并发小事务吞吐。

关键词:fast-path lock,锁槽位,OLTP,PG18,高并发 | 来源:202603/20260324_04.md

Q:PG18 如何扩展 fast-path lock slots?为什么说原来 16 个槽位不够用?

9.2 引入的 fast-path 只允许每个 backend 最多 16 个弱 relation 锁,这个硬编码上限一直偏小,因为查询要锁所有 relation——不止表,还有索引、视图、分区等;planning 阶段甚至要锁计划中"可能用到"的所有关系。随着分区表广泛使用、分区数增多,复杂查询轻松用掉几百甚至上千个锁,多核系统上访问共享锁表成为严重争点。PG18(commit c4d5cb71)移除了硬编码上限:fast-path 数组改为启动时根据 max_locks_per_transaction 计算大小,采用 2^n 公式,上限 1024 个 lock groups(即 16k 锁),默认 64 时对应 64 个 fast-path 槽。槽位组织为 16 路组相联缓存(可想象成每 group 16 槽的哈希表),每个 relation 用 hash(relid) 映射到唯一 group,再线性搜索,保持良好局部性。用开放寻址哈希表会因接近满表时效率差、访问随机性高而不适用。

关键词:fast-path,PG18,槽位,分区表,组相联缓存,max_locks_per_transaction | 来源:202409/20240924_01.md

Q:PG18 的 GetLockStatusData 效率优化解决了什么问题?

GetLockStatusData() 是 pg_locks 视图背后的函数,负责采集锁状态数据。高并发小事务场景下,频繁查询 pg_locks(监控、排查)本身会带来开销:它要从普通锁管理器(重量锁主锁表)和谓词锁管理器采集数据,可能影响性能。PG18 优化了 GetLockStatusData 效率,降低采集锁状态的成本,使高并发小事务场景下查询 pg_locks 更轻量。这与 PG14 的 GetSnapshotData 优化、PG16 的 SSE2 加速、PG18 的 fast-path slots 扩展、log_lock_failure 日志等一起,都是围绕"高并发小事务/锁管理"这条主线的持续性能与可观测性改进。实践含义:即使优化后,也不建议秒级全量轮询 pg_locks,排障时查询没问题,监控要控制范围和频率(官方文档也提示采集锁管理器信息可能对性能有影响)。

关键词:GetLockStatusData,pg_locks,高并发,小事务,锁状态采集,PG18 | 来源:202410/20241026_02.md

Q:PG18 的 pg_stat_session 视图提供什么能力?

pg_stat_session 是 PG18 新增视图,提供会话级别各状态的耗时/计数统计(pg_stat_activity 只能查会话"当前"状态,无法看累计分布)。字段:pid、active_time(running/fastpath 状态耗时毫秒)、active_count(切换到 active 状态次数)、idle_time、idle_count、idle_in_transaction_time、idle_in_transaction_count、idle_in_transaction_aborted_time、idle_in_transaction_aborted_count。它由 pg_stat_get_session(NULL) 函数支撑,每个 client backend 一行。价值:可以量化一个会话历史上花了多少时间在 idle in transaction(空闲事务)、active、idle 等状态,帮助判断会话是否有大量空闲事务时间、是否连接池滥用、事务是否长期挂着不干活。相比 pg_stat_activity 的瞬时快照,pg_stat_session 提供累计视角,是定位"为什么这个连接长期占用资源"的有力补充。

关键词:pg_stat_session,会话状态,耗时统计,idle in transaction,PG18 | 来源:202407/20240701_03.md

Q:PG18 的 pg_stat_session 视图是什么?

PG18 新增 pg_stat_session 视图,对会话各状态的耗时和计数进行分析(如活跃、空闲、空闲事务、CPU 时间、等待时间等),类似把 pg_stat_activity 的瞬时状态聚合为累计统计。DBA 可据此分析会话在各类状态上花了多少时间,定位连接资源浪费和异常会话。

关键词:pg_stat_session,会话状态,耗时统计,PG18 | 来源:202603/20260324_04.md

Q:PG19 如何把 64 位事务号 FullTransactionId 覆盖面扩展到 2PC?

PG19 将 64 位事务号(FullTransactionId,含 epoch 的 64 位表示)的覆盖面扩展到 2PC(两阶段事务),让 prepared transaction 也能用 64 位事务号标识,解决 32 位 XID 在长时间、高事务量场景下的回卷风险,增强 prepared transaction 的事务号精度和安全性。

关键词:FullTransactionId,64位事务号,2PC,PG19 | 来源:202603/20260324_04.md

Q:PL/pgSQL 的 EXCEPTION 块为什么是"性能杀手"?如何替代?

PL/pgSQL 的 EXCEPTION 块本质是开启一个子事务(Subtransaction),每进入一次就消耗一个 XID 并生成一个保存点。它的问题:1) 浪费有限 XID 资源;2) 一旦循环里嵌套 EXCEPTION,子事务深度/数量飙升,超过 PGPROC 64 个缓存上限后溢写到 pg_subtrans,触发 SubtransControlLock 锁竞争和 SLRU 磁盘扫描;3) WAL 和 XID 消耗暴增(5000 条插入可烧掉 64 万 XID),导致 autovacuum freeze 提前甚至全库只读。替代方案:1) 处理唯一键冲突用 INSERT … ON CONFLICT DO NOTHING 等原生语法,不要用 EXCEPTION 捕获;2) 数据预校验——在应用层或临时表先过滤脏数据;3) 严禁在循环内部嵌套 EXCEPTION 块;4) 只在处理无法预知的非约束性错误时才用 EXCEPTION。防御性策略:把"WHEN OTHERS THEN NULL"这类看似万能的写法替换为明确的条件处理。

关键词:EXCEPTION,子事务,性能,ON CONFLICT,pg_subtrans,WAL,唯一键冲突 | 来源:202602/20260224_09.md

Q:PREPARE TRANSACTION 的内核路径是怎样的?为什么 prepare 时必须刷 WAL?

PrepareTransaction() 主路径:1) 触发 deferred trigger、关闭 portal;2) 拒绝不适合 prepared 的事务(访问过临时对象、导出过 snapshot 等);3) MarkAsPreparing() 保留 GID 和 GlobalTransactionData(检查 max_prepared_transactions=0 则报错、GID 超长报错、GID 查重);4) StartPrepare() 写 2PC header,收集子事务、待删除文件、统计、缓存失效消息;5) 一组 AtPrepare_*() 回调把锁、谓词锁、MultiXact 等写成 2PC record;6) EndPrepare() 写 XLOG_XACT_PREPARE WAL record 并 XLogFlush();7) MarkAsPrepared() 把 dummy PGPROC 加入 ProcArray;8) PostPrepare_Locks() 把事务锁迁移到 dummy PGPROC。为什么必须刷 WAL:参与者对协调者说"yes"后就承诺未来能提交或回滚,若 prepare record 只在内存,节点崩溃后会忘掉该事务,协调者再发 commit 时参与者丢失承诺,协议破裂。源码注释:“If we crash now, we have prepared”。锁迁移必须在 ProcArrayClearTransaction() 之前,否则其他进程可能看到锁还在但 XID 已不像 running。

关键词:2PC,PREPARE TRANSACTION,XLOG_XACT_PREPARE,WAL,prepare,锁迁移 | 来源:202606/20260608_52.md

Q:PostgreSQL 14 如何优化 GetSnapshotData 的高并发性能?

GetSnapshotData() 是 PG 扩展到大量连接的最大瓶颈,生产负载曾出现 98% CPU 时间花在这里。主要原因是 PGXACT->xmin:即使最简单的只读事务也会在生命周期内多次修改 MyPgXact->xmin(快照获取和释放各一次、EOXact 处理又改),导致 GetSnapshotData() 扫描时命中其他 CPU/socket 拥有的 cacheline,系统越大后果越严重。PG14 的优化(commit 1f51c17c 等):1) 不计算全局 horizon——GetSnapshotData() 不再读取每个 proc 的 xmin,而是用两个阈值(definitely_needed / maybe_needed)延迟精确 horizon 的计算,只在确实需要 prune 时才重算;2) 把 PGXACT->xmin 移回 PGPROC,避免与其他高频更新的 PGXACT 成员共享 cacheline;3) 紧密打包 xids/vacuumFlags/nsubxids 到独立数组。效果:pgbench 只读场景 100 连接时 tps 从约 105 万提升到约 190 万,5000 连接仍保持超 150 万 tps。

关键词:GetSnapshotData,PGXACT,xmin,cacheline,高并发,快照,PG14 | 来源:202008/20200812_01.md

Q:PostgreSQL 16 如何用 SSE2 指令集加速高并发小事务写性能?

高并发小事务写性能差的一个原因是 XidInMVCCSnapshot() 需要在线性数组(snapshot->xip/subxip)中搜索 XID,大量并发写者时扫描 xip 数组对可扩展性影响明显。PG16 引入 SSE2 SIMD 指令集优化线性数组搜索(commit b6ef16756 引入优化例程,commit 37a6e5df3 把它用于 XidInMVCCSnapshot):在 x86-64 上用 SSE2 intrinsics 加速搜索,其他平台退化为普通 for 循环。性能提升:128 并发写者吞吐提升 5%,1024 写者的病态场景提升 50%。之所以优化 unsigned 32-bit 数组是因为 XidInMVCCSnapshot() 只处理 xid/subxid。哈希表方案虽然扩展性更好,但因代码复杂度和内存分配顾虑被否决。这属于 CPU 指令集加速在事务快照可见性判断路径上的应用,配合 PG14 的 GetSnapshotData 优化,共同缓解高并发小事务的快照/可见性瓶颈。

关键词:SSE2,SIMD,XidInMVCCSnapshot,xip数组,高并发,小事务,PG16 | 来源:202208/20220811_01.md

Q:PostgreSQL 2PC 的三个命令是什么?prepared transaction 为什么危险?

2PC(两阶段提交)的用户命令是 PREPARE TRANSACTION ‘gid’、COMMIT PREPARED ‘gid’、ROLLBACK PREPARED ‘gid’,面向外部事务管理器,模型接近 X/Open XA。PREPARE TRANSACTION 执行后事务脱离原会话(对原会话像 ROLLBACK),写入暂时不可见,但 prepared transaction 会继续持有锁和 XID 边界,并通过 dummy PGPROC 挂在全局事务、锁和可见性基础设施里。危险在于:1) prepared 状态被长期遗忘时,它继续占用锁(pg_locks.pid 可能为空,需联查 pg_prepared_xacts),阻塞 DDL/DML;2) 它仍被认为 in-progress,固定 MVCC 清理边界,干扰 VACUUM 回收,极端情况造成 XID wraparound 风险;3) 短生命周期只靠 WAL 和共享内存,跨 checkpoint 才写 pg_twophase 文件,若 pg_twophase 长期有文件说明存在未结束的 prepared transaction。官方建议不用就保持 max_prepared_transactions=0。健康系统里 prepared 应在秒级关闭,超过分钟级要告警。

关键词:2PC,PREPARE TRANSACTION,COMMIT PREPARED,prepared transaction,dummy PGPROC,max_prepared_transactions | 来源:202606/20260608_52.md

Q:PostgreSQL 三个实质隔离级别(Read Committed / Repeatable Read / Serializable)的快照边界和差异是什么?

PostgreSQL 内部实现三个隔离级别(READ UNCOMMITTED 按 READ COMMITTED 处理):1) Read Committed:每条语句开始时取新快照,能读到本事务内其他会话已提交的最新结果,不读未提交数据,但同一事务两次查询可能看到不同结果。2) Repeatable Read:事务第一条非控制语句取一次快照并固定,防不可重复读,PG 中也不出现幻读;但本质是 Snapshot Isolation,仍可能出现 serialization anomaly(写偏斜),写冲突时报 could not serialize access due to concurrent update。3) Serializable:在 Snapshot Isolation 之上加 SSI(Serializable Snapshot Isolation),监控并发事务间的 rw-conflict(读写依赖),出现 Tin->Tpivot->Tout 危险结构时回滚事务,保证成功提交的并发事务等价于某个串行顺序,代价是可能返回 SQLSTATE 40001,应用必须完整重试整个事务。快照边界在 snapmgr.c 的 IsolationUsesXactSnapshot() 分支体现。

关键词:隔离级别,Read Committed,Repeatable Read,Serializable,快照,SSI,40001,写偏斜 | 来源:202606/20260608_40.md

Q:PostgreSQL 为什么事务启动时不立即分配 XID?VXID 和 XID 有什么区别?

PostgreSQL 事务系统分三层:底层事务/子事务、每条查询前后的控制代码(StartTransactionCommand/CommitTransactionCommand/AbortCurrentTransaction)、用户可见的 BEGIN/COMMIT/ROLLBACK/SAVEPOINT。StartTransaction() 启动时分配的是 VXID(VirtualTransactionId,由后端进程号 + 本地递增编号组成),不一定分配真正的 XID。AssignTransactionId() 的注释说明:事务和子事务只有在需要时才分配永久 FullTransactionId;如果子事务需要 XID,父事务会先获得 XID,从而保证子事务 XID 晚于父事务。这个"延迟分配 XID"的设计很重要:大量只读短事务不消耗 XID,降低 XID 增长速度,减少 pg_xact 维护压力。反过来,调用 pg_current_xact_id() 会强制分配 XID;如果只是观测,应优先用 pg_current_xact_id_if_assigned() 避免不必要消耗。

关键词:XID,VXID,延迟分配,FullTransactionId,pg_current_xact_id | 来源:202606/20260608_40.md

Q:PostgreSQL 事务提交的内部路径是怎样的?synchronous_commit=off 会丢数据吗?

提交关键不是"把变量设成 committed",而是让崩溃恢复能证明它已提交。CommitTransaction() 调用 RecordTransactionCommit(),流程:1) 收集待删除文件、子事务、缓存失效消息等;2) 若有 XID,进入 commit critical section,写 XactLogCommitRecord();3) 根据 synchronous_commit 和是否有强制同步条件,决定立即 XLogFlush() 还是异步提交;4) WAL 满足后,用 TransactionIdCommitTree()/AsyncCommitTree() 更新 pg_xact 中主事务和子事务的提交状态;5) 需要同步复制时调用 SyncRepWaitForLSN();6) 调用 ProcArrayEndTransaction() 让其他后端不再把它看作运行中事务,再释放锁和资源。synchronous_commit=off 允许先向客户端返回成功、稍后刷 WAL,这不会破坏数据库一致性(状态等价于这些事务干净回滚),但崩溃时可能丢失少量已返回成功的事务。因此它适合可重放、可补偿的低价值事件,不适合核心账务。

关键词:提交路径,WAL,XLogFlush,synchronous_commit,pg_xact,持久性 | 来源:202606/20260608_40.md

Q:PostgreSQL 子事务(savepoint/EXCEPTION)的性能开销有多大?64 这个数字是什么?

子事务开销:1) 每个 savepoint 消耗一个 XID;2) 每个 savepoint 消耗 8K 会话本地内存(CurTransactionContext);3) 关键分水岭是 64——PGPROC 里最多缓存 PGPROC_MAX_CACHED_SUBXIDS=64 个活跃子事务 ID。深度 <64 时子事务 ID 存在快速局部内存,开销微乎其微;超过 64 或单事务累积大量子事务后,PG 必须把 ID 溢写到慢速 SLRU 缓存(pg_subtrans),可见性判断要回头查 pg_subtrans,并与其他事务争抢 SubtransControlLock。实测:单用户下溢出 64 层开销可能只增加约 1%,但并发一上升(10+ 用户)因锁竞争执行时间会 50x-100x 爆炸。5000 行插入的基线对比:标准循环 0.02s/48 bytes WAL/1 XID;单层 EXCEPTION 0.03s/43936 bytes WAL/5001 XID;溢出 128 层 3.82s/5536832 bytes WAL/640002 XID——子事务记录保存点元数据的 WAL 量是普通插入的 10 万倍。监控不要只看 CPU,去查 pg_stat_slru 的 blks_read 是否激增。

关键词:子事务,savepoint,EXCEPTION,64,pg_subtrans,SubtransControlLock,WAL,XID | 来源:202111/20211103_02.md

Q:PostgreSQL 崩溃恢复时如何处理 prepared transaction?为什么它不能像普通未提交事务那样被回滚?

普通未提交事务崩溃后被视为 abort,但 prepared transaction 不能这样处理:它已经对外部事务管理器承诺"我准备好了",必须重启后继续等待最终决定。恢复路径:restoreTwoPhaseData() 在恢复开始时扫描 pg_twophase 把状态加入 TwoPhaseState;WAL redo 遇到 XLOG_XACT_PREPARE 时 xact_redo() 调用 PrepareRedoAdd() 重建 prepared 状态;遇到 prepared commit/abort 时先按事务结束记录处理,再调用 PrepareRedoRemove() 删除条目或文件;PrescanPreparedTransactions() 在启动阶段扫描 prepared xact 推进 nextXid、处理子事务范围;RecoverPreparedTransactions() 在恢复结束前重建 dummy PGPROC、子事务关系和锁;hot standby 还有 StandbyRecoverPreparedTransactions() 让备库查询把 prepared 当活跃事务处理。恢复测试 009_twophase.pl 和 023_pitr_prepared_xact.pl 覆盖了这些场景——PITR 到 PREPARE TRANSACTION 之后的 restore point,恢复出的节点仍需显式 COMMIT PREPARED 数据才可见。

关键词:2PC,崩溃恢复,WAL redo,PrepareRedoAdd,pg_twophase,PITR | 来源:202606/20260608_52.md

Q:PostgreSQL 的 2PC(两阶段提交)是如何工作的,代价是什么?

2PC 用 PREPARE TRANSACTION ‘gid’ 把本地事务推进到可提交/回滚状态并持久化,再由协调者统一发 COMMIT PREPARED 或 ROLLBACK PREPARED。prepared 事务会用 dummy PGPROC 继续持有锁和 XID,prepared 状态通过 WAL(XLOG_XACT_PREPARE)和跨 checkpoint 时的 pg_twophase 文件持久化。代价:占用锁和 MVCC 清理边界、额外 WAL、需要 max_prepared_transactions(默认 0 禁用)和外部事务管理器,长时间遗忘会拖住 vacuum。

关键词:2PC,PREPARE TRANSACTION,COMMIT PREPARED,max_prepared_transactions | 来源:202606/20260608_52.md

Q:PostgreSQL 的 MVCC 快照是如何判断一个行版本对当前事务是否可见的?xmin/xmax 各代表什么?

PostgreSQL 的 heap 表更新不是原地覆盖,而是产生新行版本,行版本头里有 xmin 和 xmax:xmin 记录创建该行版本的事务 ID,xmax 记录删除或更新该行版本的事务 ID(无效时为 0)。快照结构(snapshot.h)由 xmin、xmax、xip[]、subxip[] 组成:xmin 是小于它的事务都已结束的边界,xmax 是大于等于它的 XID 对快照不可见的边界,xip 是快照时刻仍在运行的顶层事务列表。可见性判断核心在 heapam_visibility.c 的 HeapTupleSatisfiesMVCC():xmin 未提交或在 xip 中→不可见;xmin 已提交且 xmax 无效→可见;xmin 可见且 xmax 只是锁行(非删除/更新)→可见;xmin 可见且 xmax 已提交且对该快照可见→不可见;xmin 可见但 xmax 在快照时仍在运行→可见(因为删除尚未发生)。hint bits 会缓存 XID 提交/回滚状态,减少反复查询 pg_xact 的开销。这解释了为什么 UPDATE 会产生膨胀:旧版本不能立即删除,因为可能有旧快照还需要看到它。

关键词:MVCC,快照,行版本可见性,xmin,xmax,hint bits,HeapTupleSatisfiesMVCC | 来源:202606/20260608_40.md

Q:PostgreSQL 的 Serializable 隔离级别是怎么实现的?为什么说它"不是加大锁"?

PG 的 Serializable 不是传统的 Strict Two-Phase Locking(严格两阶段锁),而是基于 Snapshot Isolation 之上增加 SSI(Serializable Snapshot Isolation)检测,核心在 src/backend/storage/lmgr/README-SSI 和 predicate.c。它监控并发事务之间的 rw-conflict(读写依赖)关系,读不阻塞写、写不阻塞读;只有当冲突图出现可能导致异常的"危险结构"(Tin -> Tpivot -> Tout 两个相邻读写冲突)时,才回滚某个事务。工程含义:1) Serializable 不等于没有代价,它需要谓词锁(SIReadLock)、冲突跟踪和可能的事务重试;2) 它也不一定更慢——如果你本来要显式表锁或大量 SELECT FOR UPDATE 来防业务异常,Serializable 反而可能减少阻塞;3) 应用必须按 SQLSTATE 40001 做完整事务重试,不能只重试最后一条 SQL;4) SERIALIZABLE READ ONLY DEFERRABLE 适合长报表,它可能在开始时等待一个安全快照,随后避免普通 Serializable 的冲突开销。可通过 pg_locks 中 mode=‘SIReadLock’ 观察谓词锁。

关键词:Serializable,SSI,谓词锁,SIReadLock,两阶段锁,rw-conflict,40001 | 来源:202606/20260608_40.md

Q:PostgreSQL 的 XID 为什么是 32 位?XID 回卷(wraparound)是什么,如何防范?

PostgreSQL 的 TransactionId(XID)是 32 位无符号整数,超过约 40 亿事务后会发生环绕(wraparound),重新从低值开始。为了防止"旧版本突然看起来像未来版本",每个表必须周期性 vacuum,并把足够老的行版本标记为 frozen(冻结)。相关参数和字段围绕这个边界工作:relfrozenxid、datfrozenxid、vacuum_freeze_min_age、vacuum_freeze_table_age、autovacuum_freeze_max_age。监控用 age(datfrozenxid)、age(relfrozenxid) 查看事务年龄,age 越大越接近回卷风险。冻结无法推进的典型根因是:idle in transaction、老 prepared transaction、复制槽的 xmin/catalog_xmin、长时间运行的报表查询,这些都会固定清理边界。极端情况下需要停库进入单用户模式手工执行 freeze 降低年龄。另外 PG 用 64 位 xid8(含 epoch)表达完整事务号,XID 在事务首次写数据时才分配,只读事务不消耗 XID(可用 pg_current_xact_id_if_assigned() 观测而不强制分配)。

关键词:XID,回卷,wraparound,freeze,冻结,relfrozenxid,age | 来源:202606/20260608_40.md

Q:PostgreSQL 的 advisory lock 有哪些应用场景?

advisory lock 是应用自定义的、由应用提供的 key 决定的锁,与数据库对象无关。典型场景:限制每个分组最多有多少条记录、实现分布式互斥、串行化某段业务逻辑、防止并发重复处理等。它分 session 级和 transaction 级(xact),session 级需显式 unlock,xact 级随事务结束自动释放。

关键词:advisory lock,应用锁,互斥,pg_advisory_lock | 来源:202606/20260608_52.md

Q:PostgreSQL 的 fast-path lock 是什么,fastpath_exceeded 指标说明什么?

fast-path lock 是 PG 为常见低冲突 relation 锁设计的快捷通道,优先放进 backend 自身的 fast-path 槽位,避免进全局主锁表(重路径)。fastpath_exceeded 统计本可走 fast-path 但因槽位不够(max_locks_per_transaction 限制)退回普通路径的次数,它不是锁冲突次数,而是锁获取路径退化压力指标,升高意味着锁管理成本变贵,常见于分区过多、事务过宽、单 SQL 接触大量对象。

关键词:fast-path lock,fastpath_exceeded,max_locks_per_transaction,锁路径 | 来源:202603/20260324_04.md

Q:PostgreSQL 的 fast-path lock 是什么?fastpath_exceeded 指标升高说明什么?

fast-path lock 是 PG 给常见低冲突 relation 锁准备的"快捷通道",核心目标是不让所有锁都进全局主锁表(主锁表是共享结构,并发高时更贵)。普通 SELECT/INSERT/UPDATE/DELETE 都会对涉及表取弱 relation 锁,若每次都抢主锁表分区 LWLock 会成为瓶颈。9.2 起每个 backend 可在自己的 PGPROC 里记录有限数量的弱锁(AccessShareLock/RowShareLock/RowExclusiveLock),靠 FastPathStrongRelationLocks 计数在强锁请求时把匹配弱锁迁移到主表。PG19 的 pg_stat_lock 视图新增 fastpath_exceeded 指标,统计"锁本可走 fast-path 但因 max_locks_per_transaction 槽位容量不够而退回普通路径的次数"。它升高不等于锁冲突或锁等待,而是"锁获取从便宜路径退化到昂贵路径的压力信号",典型根因是分区过碎、事务过宽、单条 SQL 访问对象过多。正确动作是先减对象数、减事务宽度、优化分区裁剪,最后才考虑调大 max_locks_per_transaction。

关键词:fast-path lock,fastpath_exceeded,pg_stat_lock,max_locks_per_transaction,锁退化 | 来源:202603/20260324_04.md

Q:PostgreSQL 的事务隔离级别和快照边界是怎样的?

PG 实现三个实质隔离级别:Read Committed 每条语句取新快照,防脏读但同一事务两次读可能不同;Repeatable Read 事务第一条非控制语句取快照,防不可重复读和幻读但仍可能 serialization anomaly;Serializable 在快照隔离上加 SSI 检测 rw-conflict 危险结构,成功提交可串行化但可能报 40001 需重试。READ UNCOMMITTED 按 READ COMMITTED 处理。

关键词:隔离级别,Read Committed,Repeatable Read,Serializable,快照 | 来源:202606/20260608_40.md

Q:PostgreSQL 的死锁检测算法是怎么工作的?为什么说它采用"乐观等待"?

PG 采用 optimistic waiting(乐观等待):进程拿不到锁时不立即做死锁检查,而是先睡眠,并设置 deadlock_timeout(默认 1 秒)的延时定时器;超时还没拿到锁才运行死锁检测代码。核心在 deadlock.c,把等待关系看成 waits-for graph(WFG):A 等 B 则有 A->B 的边。已持有冲突锁形成 hard edge;队列前方等待者因顺序挡住后方形成 soft edge。若从当前等待进程出发能回到自己,就存在涉及自己的死锁。检测算法 FindLockCycle() 递归沿 waits-for 边向外搜索:若所有路径终止于运行中的进程则无死锁;若回到起点则报告死锁并中止起点事务(cancel 一个请求即可打破环,不必杀掉全部事务);若回环到其他节点说明死锁不涉及自己,忽略。soft edge 引发的死锁可通过重排等待队列解除(topological sort 尝试),无法重排或全是 hard edge 才 abort 事务。谁先检测出死锁就 rollback 谁。

关键词:死锁,deadlock_timeout,waits-for graph,hard edge,soft edge,FindLockCycle,40P01 | 来源:202112/20211222_01.md

Q:PostgreSQL 的重量锁(heavyweight lock)和轻量锁(LWLock)有何区别?

重量锁(relation/tuple/transactionid 等)记录在锁表,可被用户查询(pg_locks),支持死锁检测,用于表、行、事务 ID 等用户级并发控制。轻量锁(LWLock)是内核内部共享内存结构的短临界区保护(如 buffer mapping、WAL、CLog),通常持有时间极短,不参与死锁检测,属于内核实现细节,高并发下 LWLock 争用会成为瓶颈。

关键词:重量锁,LWLock,轻量锁,pg_locks,死锁检测 | 来源:202606/20260608_40.md

Q:PostgreSQL 的重量锁(heavyweight lock)有哪些锁模式?冲突矩阵如何判断?

标准重量锁模式定义在 lockdefs.h:AccessShareLock(普通 SELECT,只与 AccessExclusiveLock 冲突)、RowShareLock(SELECT FOR UPDATE/SHARE,与 ExclusiveLock、AccessExclusiveLock 冲突)、RowExclusiveLock(INSERT/UPDATE/DELETE/MERGE,与 ShareLock 及更强锁冲突)、ShareUpdateExclusiveLock(VACUUM/ANALYZE/CREATE INDEX CONCURRENTLY)、ShareLock(非并发 CREATE INDEX)、ShareRowExclusiveLock(CREATE TRIGGER,自冲突)、ExclusiveLock(REFRESH MATERIALIZED VIEW CONCURRENTLY,只允许普通读并发)、AccessExclusiveLock(DROP/TRUNCATE/VACUUM FULL/多数 DDL,与所有模式冲突)。冲突规则不是 if/else,而是 lock.c 的 LockConflicts[] 位图(conflictTab[requested_mode] & lock->grantMask 快速判断)。注意:名字里带 ROW 的(RowExclusiveLock 等)也是表级锁,不是行锁;行锁信息存磁盘元组里,等待行锁通常表现为等待持有者的 transactionid。

关键词:重量锁,锁模式,冲突矩阵,LockConflicts,AccessExclusiveLock,RowExclusiveLock | 来源:202606/20260608_43.md

Q:PostgreSQL 锁等待队列的插入算法有什么特殊之处?为什么会出现"软阻塞"?

当请求与已授予锁或队列中更早的冲突请求不兼容时,进程进入 LOCK.waitProcs。正常情况下插入队尾,但有例外:如果当前进程已经持有该锁对象上的某些锁,而队列中已有等待者请求会被它挡住,那么当前进程会被插入到第一个这样的等待者之前(rearrange wait order)。这种插入方式的目的就是消除 soft deadlock——等待队列中也可能出现死锁(soft deadlock),通过调整等待顺序来解决。还有一个特殊情形:如果插入点之前没有冲突,就直接授予锁而不等待。这解释了生产现象:普通 SELECT 被挡住,不一定直接与当前持锁者冲突,可能是它排在一个等待 AccessExclusiveLock 的 DDL 后面,被等待队列顺序"软阻塞"了。死锁检测代码在必要时也会重排等待队列来打破只涉及 soft edge 的环。

关键词:等待队列,soft deadlock,rearrange wait order,JoinWaitQueue,软阻塞 | 来源:202112/20211222_01.md

Q:SKIP LOCKED 在 PG 中的典型应用是什么?

SKIP LOCKED 配合 SELECT … FOR UPDATE SKIP LOCKED,用于并发队列消费:多个 worker 同时从队列表取出未处理的行,每个 worker 只锁定并处理自己抢到的行,跳过已被其他 worker 锁定的行,避免互相阻塞,实现高效的任务分发。常配合 NOWAIT 使用。

关键词:SKIP LOCKED,FOR UPDATE,队列消费,并发 | 来源:202606/20260608_40.md

Q:advisory lock 的会话级和事务级有什么区别?连接池场景下有什么坑?

advisory lock 复用普通锁管理器,lock method 是 USER_LOCKMETHOD,SQL 层只暴露 shared/exclusive 两类语义。生命周期分两种:1) 事务级(pg_advisory_xact_lock / pg_try_advisory_xact_lock):到当前事务结束时自动释放,没有显式 unlock 函数,适合短临界区、请求内互斥、任务抢占。2) 会话级(pg_advisory_lock / pg_try_advisory_lock):COMMIT 或 ROLLBACK 后仍持有,需 pg_advisory_unlock / pg_advisory_unlock_all 显式释放,会话结束时服务器自动清理,DISCARD ALL 也会释放。连接池场景是最大坑:连接池里"关闭连接"往往只是归还给池,不是 session 结束,会话级锁会残留,下一个借用该连接的请求可能继承一个完全不知道的锁状态。规避:请求内临界区优先用事务级锁;必须用会话级时在 finally 中释放,或归还前执行 pg_advisory_unlock_all()。另外会话级锁多次获取会 stack,锁三次要 unlock 三次才释放(来自 LOCALLOCK 的 nLocks 计数)。

关键词:advisory lock,会话级,事务级,连接池,pg_advisory_xact_lock,unlock | 来源:202606/20260608_42.md

Q:advisory lock 能做哪些业务场景?它的局限是什么(为什么不能当约束)?

advisory lock 适合单库内的任务去重、leader election、后台 job 抢占、对不存在稳定数据行的资源做临时互斥,以及想避免锁表膨胀和异常退出清理成本的应用协议。典型场景:同一租户同一时刻只跑一个对账任务,用 pg_try_advisory_xact_lock(namespace_id, tenant_id) 抢锁。局限:1) 它不是约束,只是应用协议——别人只要不拿同一个 advisory key 就能照常 DML,绕过协议的代码不会被拦住;强一致规则(唯一性、库存非负、时间段不重叠)应交给 unique index、exclusion constraint、foreign key 或隔离级别。2) 它不写 WAL,不传播到 standby,主库拿锁不会阻塞备库查询,不能做主备一致互斥。3) 每个不同 key 占用共享锁表资源(受 max_locks_per_transaction 限制),大量细粒度 key 会耗尽共享内存。4) 阻塞版本函数可能让业务线程长期挂起,高并发服务应优先 try-lock + 退避。

关键词:advisory lock,业务互斥,约束,standby,不写WAL,共享内存 | 来源:202606/20260608_42.md

Q:cached plan must not change result type 错误的原因和解法是什么?

这个错误发生在使用 prepared statement(或 PL/pgSQL 中的 cached plan)时,同一个 SQL 文本在不同执行间返回结果集的结构(列类型/列数)发生了变化。因为 PG 会缓存执行计划,计划缓存假设结果类型不变,一旦类型变化(典型场景:SELECT * FROM 视图或函数返回类型变化、表结构变更、递归 CTE、多态函数参数变化等)就会报 “cached plan must not change result type”。解法:1) 让 SQL 的结果类型稳定,避免依赖会变化的结构;2) 使用 DEALLOCATE 或重新 prepare 使计划失效;3) 在 PL/pgSQL 中用 EXECUTE 动态执行(动态 SQL 不走 cached plan)绕过;4) 版本升级或结构变更后让依赖的计划重新生成。本质是 plan cache 与结果集结构的一致性约束,遇到此错误应检查是否 DDL 变更了涉及对象的返回结构,或 SQL 本身的结果类型依赖运行时变化。

关键词:cached plan,result type,prepared statement,plan cache,DEALLOCATE | 来源:201904/20190417_01.md

Q:fast-path 锁为什么需要 FastPathStrongRelationLocks 计数?强锁请求时如何处理?

fast-path 锁把弱 relation 锁(AccessShareLock/RowShareLock/RowExclusiveLock)放在 backend 本地 PGPROC 槽位里,不进主共享锁表。但这里有个正确性问题:如果所有弱锁永远留在本地,那么当有人请求强锁(如 AccessExclusiveLock)时,冲突判断看不到这些本地弱锁,会错误地授予强锁。解决机制是 FastPathStrongRelationLocks 计数:强锁请求会增加对应分区的 strong-lock 计数,然后扫描各 backend 的 fast-path 槽,把匹配的弱锁迁移到主共享锁表,保证冲突判断和死锁检测看到完整状态。这就是"平时读写少付成本,强 DDL 来时仍能获得正确冲突判断"的设计。同理,重量锁获取路径中,强 relation 锁会先阻止新的 fast-path,并把相关 fast-path 锁迁移进主表。所以 fast-path 不是无条件的优化,它有清晰的触发迁移条件来保证正确性。

关键词:fast-path,FastPathStrongRelationLocks,强锁,冲突判断,迁移,主锁表 | 来源:202606/20260608_43.md

Q:lock_timeout、statement_timeout、deadlock_timeout、idle_in_transaction_session_timeout 各控制什么?

这几个超时参数作用域不同:1) statement_timeout:限制整个语句执行时间(含 CPU/IO/锁等待),超时终止语句,适合防慢查询拖垮系统。2) lock_timeout:只限制等待锁的时间,锁等待超时立即失败(不终止整个语句的后续可能),适合 DDL 预检、防止雪崩,建议会话/角色/作业级别设置而非全局。3) deadlock_timeout:死锁检测的延时,进程拿不到锁先睡眠,超过该时间才运行死锁检测;默认 1 秒,调太小会频繁唤起死锁检测浪费 CPU,调太大真实死锁报告变慢。4) idle_in_transaction_session_timeout:空闲事务超时,超时终止连接(释放快照和锁),防 idle in transaction 固定 xmin;5) idle_session_timeout:空闲会话超时(PG14 支持,配合插件 pg_timeout 早期实现)。区别要记牢:statement_timeout 管整个语句,lock_timeout 只管锁等待,deadlock_timeout 不是超时而是检测延迟。log_lock_waits 在等待超过 deadlock_timeout 后记录锁等待日志。

关键词:lock_timeout,statement_timeout,deadlock_timeout,idle_in_transaction_session_timeout,idle_session_timeout | 来源:202606/20260608_43.md

Q:pg_statement_rollback 插件是怎么实现"语句级回滚"的?它比客户端方案好在哪?

PostgreSQL 原生在事务中遇到错误后整个事务 abort(current transaction is aborted),无法继续。Oracle/DB2 会在每条语句前隐式设 savepoint,失败可回滚到语句前状态。pg_statement_rollback 插件在服务端实现自动 savepoint 和语句级回滚:1) 每条写语句前自动执行 SAVEPOINT;2) 出错后应用调用 ROLLBACK TO SAVEPOINT “PgSLRAutoSvpt” 即可继续事务;3) 通过 pg_statement_rollback.enabled、savepoint_name、enable_writeonly 等 GUC 配置。相比 psql 的 ON_ERROR_ROLLBACK、JDBC 的 autorollback 等客户端方案,服务端方案省去了额外的 SAVEPOINT/RELEASE SAVEPOINT 网络往返,吞吐损耗很小(pgbench 实测 TPC-B 场景从 742 tps 降到约 722 tps,约 3% 开销)。注意:enable_writeonly 默认开启,避免对 SELECT 也自动 savepoint 而塞满子事务缓存(PGPROC_MAX_CACHED_SUBXIDS=64),如果事务内语句超 64 条会触发 pg_subtrans 磁盘扫描性能下降。

关键词:pg_statement_rollback,语句级回滚,savepoint,ON_ERROR_ROLLBACK,Oracle兼容 | 来源:202402/20240229_01.md

Q:pg_xact 和 pg_subtrans 分别存什么?每个事务状态占多少位?

pg_xact(历史名 CLOG)由 clog.c 管理,记录事务提交状态,每个事务状态占 2 bit(一个字节记录 4 个事务,一个 BLCKSZ 页面记录 BLCKSZ*4 个事务状态),TransactionIdSetTreeStatus() 会把顶层事务和子事务树状态一起设置。pg_subtrans 由 subtrans.c 管理,记录 subxid 的直接父 XID,它不是长期历史表,只需保留当前打开事务所需的信息,信息随包含事务结束即失效。子事务过多时,PGPROC 里最多缓存 PGPROC_MAX_CACHED_SUBXIDS(当前值 64)个 subxid,溢出后可见性检查会更多依赖 pg_subtrans(涉及 SubtransControlLock 竞争)。实践含义:不要在一个大事务里创建成千上万个 savepoint,也要警惕 PL/pgSQL EXCEPTION 在循环里隐式制造大量子事务。

关键词:pg_xact,CLOG,pg_subtrans,子事务,subxid,PGPROC_MAX_CACHED_SUBXIDS | 来源:202606/20260608_40.md

Q:plan_cache_mode 参数是什么?OLTP 和 OLAP 分别该怎么设置?

plan_cache_mode(PG12 引入)控制 prepared statement 的执行计划缓存策略,可选 auto / force_generic_plan / force_custom_plan。custom plan 是每次对新的参数值重新生成计划,generic plan 是重复执行时复用同一计划,默认 auto 自动选择。auto 的行为是前 5 次执行生成 custom plan,若 custom plan 成本始终不低于 generic plan 则切换到 generic plan,避免数据倾斜导致计划退化。设置建议:1) OLAP(复杂分析查询)并发低、每次条件输入选择性差异大,不同参数可能需不同执行计划,建议 force_custom_plan;可针对不同用户/数据库设置,如 alter role AP用户 set plan_cache_mode to force_custom_plan;2) OLTP 并发高、数据倾斜少,建议 auto;若数据保证完全不倾斜可用 force_generic_plan 减少 plan 生成开销。注意该设置在缓存计划被执行时生效而非 prepare 时,且计划缓存行为可能随版本变化,强制计划类设置应定期重评估。

关键词:plan_cache_mode,custom plan,generic plan,prepared statement,数据倾斜,OLTP,OLAP | 来源:201903/20190331_15.md

Q:plan_cache_mode 参数有哪几种模式,各适合什么场景?

plan_cache_mode 有三种值:auto(默认,自动选择)、force_custom_plan(每次用新参数重新生成计划)、force_generic_plan(复用同一通用计划)。OLAP 复杂分析查询条件选择性差异大,建议 force_custom_plan(可对特定 role/database 设置);OLTP 高并发数据不倾斜建议 auto 或 force_generic_plan。

关键词:plan_cache_mode,执行计划缓存,force_custom_plan,force_generic_plan | 来源:201903/20190331_15.md

Q:slotsync worker 遗漏释放 PostmasterContext 的问题是什么?log_lock_waits 测试增强有什么意义?

PG19 有两个修复:1) commit 93dc1ace 修复 slotsync worker 遗漏释放继承的 PostmasterContext 的问题。postmaster 启动时创建 PostmasterContext(工作内存上下文)用于分配启动数据;fork 出的子进程(autovacuum、syslogger 等)会正确释放它,但 slotsync worker 遗漏了这一步,导致该上下文在 slotsync 进程生命周期内持续保留未释放(虽然是内存泄漏式的资源浪费,且 slotsync 是逻辑复制中把 primary 上启用 failover 的逻辑复制槽同步到 standby 的重要 worker)。2) commit ca2b544 为 log_lock_waits 增加完整 TAP 测试覆盖——log_lock_waits 是重要的锁等待诊断参数(等待超 deadlock_timeout 后记录锁等待日志),之前缺乏专门的 TAP 测试验证其行为正确性。这两个"小"改动分别提升复制槽管理稳定性和锁等待日志行为的可靠性保障。

关键词:slotsync,PostmasterContext,log_lock_waits,TAP测试,内存上下文,PG19 | 来源:202604/20260407_05.md

Q:不同会话能同时更新同一条记录的不同字段吗?为什么?

不能。数据库最小粒度的锁是行锁,同一行的行级别排他锁在一个时刻只能被一个会话持有,其他会话要等待。即使更新的是不同字段(一个更新 info、一个更新 ts),也会互相阻塞。验证:会话 1 update t set info=‘abc’ where id=1 不提交,会话 2 update t set ts=now() where id=1 会阻塞,等待链条表现为 locktype=‘transactionid’,持锁方 Mode=ExclusiveLock granted=true,等待方 Mode=ShareLock granted=false(等待事务 ID 锁)。日志开启 log_lock_waits=on 会看到 “process 98 still waiting for ShareLock on transaction 735 after 1001.169 ms”。因为 PG 的 MVCC 和行锁是行粒度,更新任一行都会把整行加锁并产生新版本,无法字段级并行。业务层面的解法:1) 把需要并行更新的字段拆到多张表用 PK 关联;2) 把同一行更新合并到一个会话/事务;3) 产品层面期望未来能把锁粒度/多版本控制下推到字段甚至 JSON/array 元素级别(目前 PG 不支持)。

关键词:行锁,并发更新,transactionid,同一行,字段级,log_lock_waits | 来源:202404/20240416_01.md

Q:为什么 PG 高并发数据写入吞吐达不到磁盘极限?几个重大锁是什么?

高并发写入吞吐无法达到磁盘极限(如磁盘 4GB/s 但写不满)主要是几个重大锁的串行化:1) 申请 WAL 片段的串行排他锁;2) 高并发小事务的 ProcArrayEndTrans、GetSnapshotData 开销(快照计算);3) 每次数据文件空间不足时一次只扩展 1 个 block,批量写入时频繁扩展数据块——数据文件扩展串行排他锁、索引构建和页扩展串行排他锁;4) 扩展数据块导致文件长度变化需修改 inode,文件系统层面 inode 锁。极限测试法(可达 NVMe SSD 物理极限 3.6GB/s)用:unlogged table(避免写 WAL)、无索引无 PK/UK 约束(避免页分裂)、多表并行导入(避免单表扩展锁冲突)、大 block size(减少扩展冲突)、COPY 协议。PolarDB 支持 polar_bulk_extend_size 一次扩展多个数据块,缓解数据文件/索引页扩展的排他锁瓶颈,对 IOT/时序/feedlog 等高速写入场景收益大。

关键词:高并发,写入吞吐,磁盘极限,WAL片段锁,扩展锁,unlogged,PolarDB | 来源:202202/20220214_01.md

Q:为什么 PG 高并发短连接/小事务性能差?涉及的快照和可见性瓶颈在哪?

PG 多进程架构下,高并发小事务性能差的根本原因是几个高频共享元数据访问点:1) 快照获取 GetSnapshotData() 是 O(连接数) 的,且要扫描每个进程的 PGXACT(xmin 频繁修改导致 cacheline ping-pong,见 PG14 优化);2) tuple 可见性判断 XidInMVCCSnapshot() 要在 xip/subxip 数组中线性搜索 XID(PG16 用 SSE2 加速);3) 事务结束 ProcArrayEndTransaction 需拿 ProcArrayLock 排他锁更新活跃事务数组;4) WAL 插入的锁竞争;5) buffer 管理和锁表分区竞争。这些元数据访问点都会随连接数和事务密度上升而成为瓶颈。优化方向:连接池控制并发数(PG 对几千连接不友好,虽然 PG14 后 5000 连接仍可百万 tps 但应用仍应限制)、缩短事务、批量提交、减少无效写。这也是为什么连接池(pgbouncer 等)对 PG 尤其重要。

关键词:高并发,短连接,快照,可见性,ProcArray,WAL,连接池 | 来源:202202/20220214_01.md

Q:为什么 Serializable 的 SIReadLock 谓词锁不阻塞写?它和普通锁在 pg_locks 里都出现但有何不同?

SIReadLock(Serializable 隔离级别的谓词锁)用于记录并发事务之间的读写依赖(rw-conflict),不是用来阻塞访问的普通锁。它记录"这个事务读过哪些 relation/page/tuple",当另一个事务写这些目标时,通过 rw-conflict 检测潜在的危险结构(Tin -> Tpivot -> Tout),必要时回滚事务。因为它的目的是"事后检测异常"而不是"事前阻塞冲突",所以 SIReadLock 不阻塞写操作。相比之下,普通重量锁(relation、transactionid、advisory 等)的目的是通过冲突矩阵在访问前阻塞不兼容的操作。所以二者都出现在 pg_locks 里(locktype=‘SIReadLock’ 时 mode=‘SIReadLock’),但语义完全不同:谓词锁是 Serializable 的依赖跟踪工具,普通锁是并发互斥工具。这也解释了 Serializable 下读不阻塞写、写不阻塞读的原因。谓词锁粒度(tuple/page/relation)取决于执行计划,可能升级(锁升级会增加 serialization failure 概率)。

关键词:SIReadLock,谓词锁,Serializable,rw-conflict,pg_locks,不阻塞 | 来源:202606/20260608_40.md

Q:为什么 idle in transaction 事务危害很大?backend_xid 和 backend_xmin 分别代表什么?

idle in transaction(空闲事务)的危害:有 backend_xid 或 backend_xmin 的会话(除了 vacuum),不管处于什么状态,超出这个值之后新启动事务产生的垃圾 tuple 都不能被 vacuum 回收。区别:backend_xid 是当前事务本身分配的 XID(该事务写过数据);backend_xmin 是该事务快照中能看到的最老 XID(该事务只是读过数据,如 RR 隔离级别 select 后挂着)。影响:1) 若系统还有大量 update/delete,时间久了导致表、索引膨胀,浪费空间、性能变差、备份/恢复变长;2) 时间非常久可能触发事务回卷警告,极端需停库进入单用户模式手工 freeze。事务 abort 后会自动释放 snapshot(backend_xmin/xid 清空),所以 abort 的事务相对安全。解决方案:业务层避免框架自动开启事务;设置 idle_in_transaction_session_timeout 自动释放长时间空闲事务;设置 old_snapshot_threshold 避免 vacuum 长时间做不下去。空闲的只读事务(未获得过快照)不影响,因为没有 backend_xid/xmin。

关键词:idle in transaction,backend_xid,backend_xmin,膨胀,freeze,idle_in_transaction_session_timeout | 来源:202112/20211220_03.md

Q:为什么空闲事务和慢 2PC 会导致表膨胀(GetOldestXmin)?

GetOldestXmin 返回系统中最老的事务号,无论隔离级别,只看最老。RC 事务的 SQL 快照本应只是语句发起时,但空闲事务拿到过快照后,其 xmin 会卡住 GetOldestXmin,使之后产生的垃圾 tuple 无法被 vacuum 清理。未结束的 2PC 事务同理。优化思路:内核让空闲/2PC 事务的 oldestxmin 用当前最小未分配事务号代替;参数上可设 old_snapshot_threshold 或 idle_in_transaction_session_timeout。

关键词:GetOldestXmin,空闲事务,2PC,表膨胀,vacuum | 来源:201907/20190720_01.md

Q:为什么长时间等待业务处理不建议封装在一个长事务里?

长事务(begin; sql1; …等待业务处理…; sql2; …; end)有两个核心问题。问题 1:从最老的 backend_xid/backend_xmin 事务号之后产生的垃圾无法被回收,影响 freeze xid,导致:1) 表膨胀,存储成本增加、内存消耗增加、性能变差、备份/恢复时间变长;2) freeze xid 极端影响——XID 是 32 位需重复使用,长时间不 freeze 可能需停库进入单用户模式手工 freeze;3) 积累久了可能出现大量表同时需要 freeze,导致 IO 暴增、WAL 日志暴增、standby 延迟甚至中断、归档压力暴增。问题 2:长时间持有锁,堵塞未来的 SQL 锁请求,增加死锁隐患。解决办法:事前从业务层拆分大的原子操作为多个小原子操作并做好回退逻辑;数据库设置 statement_timeout、lock_timeout、idle_in_transaction_session_timeout、idle_session_timeout、old_snapshot_threshold 兜底。长时间不结束的 2PC 危害相同。

关键词:长事务,膨胀,freeze,锁,statement_timeout,lock_timeout | 来源:202112/20211221_03.md

Q:什么是 MultiXact?它和行锁、外键有什么关系?

MultiXact(multitransaction)是 PG 用来表示"多个事务同时以共享方式锁同一行"的结构。场景:多个事务同时对同一行执行 SELECT FOR SHARE(或 FOR KEY SHARE),单个 xmax 字段装不下多个事务 ID,PG 就用一个 MultiXactId 表示这组事务的集合。它和外键密切相关:外键约束检查时会对被引用行加 FOR KEY SHARE 锁,多个会话并发插入引用同一父行时,就会在该父行上形成 MultiXact。影响:1) 等待行锁时可能表现为等待 multixact 类型的锁而非单个 transactionid;2) MultiXact 有自己的 SLRU(pg_multixact)和回卷管理(relminmxid/mxid_age 监控);3) 大量 FOR SHARE/FOR KEY SHARE 并发(典型是外键热点父行)会造成 MultiXact 膨胀和争用,是"外键热点"性能问题的根源之一。SKIP LOCKED 遇到 MultiXact 时用 ConditionalMultiXactIdWait 条件等待。

关键词:MultiXact,multixact,行锁,FOR SHARE,外键,pg_multixact | 来源:202606/20260601_02.md

Q:在带 LIMIT 的查询里直接调用 advisory lock 函数有什么陷阱?如何安全批量加锁?

官方文档明确警告:不要假设 LIMIT 一定先于锁函数求值。危险写法 SELECT pg_advisory_lock(id) FROM foo WHERE id > 12345 LIMIT 100 中,优化器和执行器的表达式求值顺序可能导致锁函数在 LIMIT 之前对更多行求值,拿到超出预期的锁,尤其是会话级锁会形成难排查的残留。安全写法是先用子查询确定候选集合:SELECT pg_advisory_lock(q.id) FROM (SELECT id FROM foo WHERE id > 12345 ORDER BY id LIMIT 100) AS q,让"最多 100 个 id"这个集合先物化或形成边界,再对集合内 id 调用锁函数。另外 advisory lock 函数 proparallel=‘r’(parallel restricted),不要假设它可以安全下推到并行 worker,尽量在进入并行查询前完成锁控制。key 设计要有命名空间,两个 int key(namespace, resource_id)往往比 hash 后的 bigint 更易运维。

关键词:advisory lock,LIMIT,求值顺序,子查询,并行安全,命名空间 | 来源:202606/20260608_42.md

Q:如何快速定位是谁堵塞了某个等待中的进程?

用 pg_blocking_pids(pid) 函数,返回阻塞指定进程获取锁的 PID 数组(硬阻塞或软阻塞)。对于 SSI 隔离级别下请求安全快照冲突,用 pg_safe_snapshot_blocking_pids(pid) 返回阻塞其获取 safe snapshot 的 PID。结合 pg_stat_activity 的 wait_event_type/wait_event 可看到等待链。

关键词:pg_blocking_pids,锁等待,pg_safe_snapshot_blocking_pids,SSI | 来源:201902/20190201_02.md

Q:如何用 advisory lock 实现"堵塞式读、不堵塞写"(串行读、并行写)的变态需求?

需求:允许并行写,不允许并行读(同一行/同一资源的读要串行)。用 advisory lock 实现,因为普通写(不同行不冲突)天然并行,只需对"读"加互斥。两种方式:1) 不堵塞读但也不返回未拿锁的读结果:select * from a where id=? and pg_try_advisory_xact_lock(?),拿不到共享锁的行不返回(0 行),拿到才返回,事务结束自动释放。2) 堵塞读,等其他读结束:begin; select pg_advisory_xact_lock(?); select * from a where id=?,拿不到锁就等待,等前一个读事务结束释放后再读。3) 一句搞定用 CTE:with locks as (select 1 as locks from pg_advisory_xact_lock(1)) select a.* from a,locks where id=1。核心是 advisory lock 与事务生命周期绑定(xact_lock 事务结束自动释放),写操作不参与 advisory 锁所以不互相阻塞,读操作通过 advisory 锁串行化。

关键词:advisory lock,串行读,并行写,pg_advisory_xact_lock,CTE | 来源:202005/20200517_01.md

Q:如何用 advisory lock 实现串行读、并行写?

advisory lock 不依赖表结构,是应用自定义的锁。对同一行用 pg_try_advisory_xact_lock(id) 包在查询里:拿不到锁的会话不返回该行记录(0 rows),拿到锁的返回,事务结束自动释放锁。这样写操作互不冲突(只要不是同一行),读操作对同一行串行化,实现并行写、串行读。

关键词:advisory lock,pg_try_advisory_xact_lock,串行读,并行写 | 来源:202005/20200517_01.md

Q:用 CTID 实现 update/delete limit 时,并发 DML 下有什么隔离性问题?怎么解决?

用 ctid in (select ctid from tbl where …) 实现 update/delete limit 时存在并发隔离性问题:session1 的子查询先执行得到 ctid(如 (0,1)),期间 session2 更新了同一行(id 从 1 改成 2),因为存在 HOT(Heap-Only Tuple)链,ctid(0,1) 会链到 ctid(0,2) 再到 tuple2 的新版本,session1 按旧 ctid 变更时会把已经是 id=2 的行改成 3,产生错误的更新。三种解法:1) recheck——在 update 外层加回原条件 and id=1,recheck 后更新记录数为 0;2) RR 模式——使用 REPEATABLE READ 隔离级别,发现记录已被更新时抛出异常 could not serialize access due to concurrent update;3) for update 锁定——用 for update SKIP LOCKED 先锁住 limit 的行(如 ctid = any(array(select ctid from (select ctid from tbl where id=1 limit 1 for update SKIP LOCKED) t))),session2 会等待,session1 正常变更。核心:CTID 是物理行号,会随 HOT 更新和 VACUUM 变化,不能作为稳定的逻辑主键。

关键词:CTID,update limit,delete limit,HOT,并发,recheck,RR,for update | 来源:202204/20220407_01.md

Q:用 advisory lock 限制"每个分组最多 N 条记录"为什么必须用 Read Committed 隔离级别?

场景:表里有 gid 字段,要求每个 gid 最多 5 条记录。写法是写入时对同一个 gid 的写入互斥(advisory lock),检查该 gid 是否已满,不满则写入,写完释放锁。为什么只能 RC 隔离级别?因为 RR 和 SSI 隔离级别下,其他 gid(或同 gid 其他会话)在你事务开启后写入的记录,你看到的仍是事务开始时那个较老的快照,会误以为还没写满,从而突破上限——这就是并发下触发器 COUNT 看不到其他会话未提交插入的根本原因(MVCC 快照隔离)。只用触发器 COUNT 检查而不加锁,两个会话并发各插 3 条会同时通过检查,最终得到 6 条(复现了 depesz 博客的 bug)。因此正确方案是:同一 gid 写入前先拿 advisory lock 串行化,保证检查与写入的原子性;并在 trigger 中判断如果不是 RC 模式则报错。

关键词:advisory lock,分组限制,Read Committed,快照隔离,触发器,并发插入 | 来源:202101/20210121_04.md

Q:线上遇到锁等待,如何定位"谁堵塞了谁"?pg_blocking_pids 的原理是什么?

定位锁等待用 pg_blocking_pids(pid),它返回堵塞指定后端进程获取锁的 PID 数组;SSI 隔离级别下请求安全快照冲突用 pg_safe_snapshot_blocking_pids(pid)。实现位于 lockfuncs.c:它报告的 PID 包括"持有与该进程当前请求冲突的锁"(hard block)的进程,以及"请求了同样冲突锁且排在等待队列前面"(soft block)的进程。排查步骤:1) select distinct pid from pg_locks where not granted 找到被害者;2) select pg_blocking_pids(pid) 找到嫌疑人;3) 从 pg_stat_activity 看双方 state/query,从 pg_locks 看双方持有的锁类型和 granted 状态。推荐优先用 pg_blocking_pids() 而不是手写 pg_locks 自连接,因为手写很难正确处理冲突矩阵和等待队列顺序。对于多层级联阻塞,可用递归 CTE 沿 pg_blocking_pids 链向上追溯,找到最终源头(往往是 idle in transaction 的事务)。

关键词:pg_blocking_pids,锁等待,pg_locks,blocking,排查,hard block,soft block | 来源:201902/20190201_02.md

Q:行级锁在 pg_locks 里为什么看不到?等待行锁时看到的是什么?

PostgreSQL 的行级锁信息存储在磁盘元组(tuple)的 xmax 字段里,不直接以普通内存锁行的形式出现在 pg_locks。所以 pg_locks 里看不到具体的"行锁"对象。如果进程等待某个行锁,通常会表现为等待当前持有者的 transactionid——即 pg_locks 里出现 locktype=‘transactionid’ 的记录,等待方 mode=ShareLock granted=false,持锁方 mode=ExclusiveLock granted=true。这是因为 PG 的并发更新同一行时,等待者实际是在等待"持有该行的事务结束",这个等待通过事务 ID 锁(transactionid 类型的重量锁)来表达和参与死锁检测。同理 MultiXact(多个事务共享/锁同一行)场景会表现为等待 multixact 类型的锁。排查行锁等待时,用 pg_blocking_pids 找到持锁 pid,再从 pg_stat_activity 看持锁方的事务状态(往往是 idle in transaction)。

关键词:行锁,pg_locks,transactionid,tuple,xmax,MultiXact | 来源:202606/20260608_43.md

Q:连接池(pgbouncer 等)对 PG 为什么重要?事务模式和会话模式有什么区别?

PG 是多进程架构,每个连接一个后端进程,连接本身开销大(进程、私有内存、元数据缓存),且高并发短连接下 GetSnapshotData、ProcArray 等共享结构竞争随连接数上升而恶化。连接池的价值:1) 复用连接,避免频繁建立连接的开销;2) 限制到数据库的实际连接数,控制共享结构竞争;3) 降低每个进程缓存大量元数据导致的内存占用。pgbouncer 的事务模式(transaction pooling):每个事务完成后连接可被其他客户端复用,要求客户端不能依赖会话级状态(session-level 的 prepared statement、advisory lock、临时表、SET 等会话状态),否则会串号;会话模式(session pooling)保持连接与客户端绑定,兼容性更好但复用度低。pgbouncer 1.21 开始在事务模式支持 prepared statement。advisory 会话级锁在事务池下尤其危险(连接归还不等于 session 结束,残留锁影响下个请求)。

关键词:连接池,pgbouncer,事务模式,会话模式,prepared statement,advisory lock | 来源:202310/20231026_02.md

Q:重量锁的三层结构 LOCALLOCK / LOCK / PROCLOCK 分别解决什么问题?

重量锁不是一张大表,而是分本地和共享两层:1) LOCALLOCK:每个 backend 私有,记录自己对某个 LOCKTAG+LOCKMODE 获取了多少次、属于哪个 ResourceOwner,同一事务重复获取同一锁只增加本地计数(nLocks),不必反复改共享表;这也是"同一会话重复获取同一把锁总是成功"的原因。2) LOCK:共享内存中每个可锁对象一条,包含 grantMask(已授予位图)、waitMask(等待位图)、requested[]、granted[]、procLocks、waitProcs,负责对象级总体计数和等待队列。3) PROCLOCK:共享内存中某个 backend 对某个 LOCK 的持有/等待状态,包含 holdMask、releaseMask,同时挂到 LOCK 和 PGPROC 的链表上。这个分层是性能和正确性的折中:共享表只保存跨后端必须共享的信息,本地计数避免无意义的共享内存写入。获取路径 LockAcquire()→LockAcquireExtended() 先找 LOCALLOCK,已持有则本地计数,符合 fast-path 条件则走 fast-path 槽,否则进共享锁表分区判断冲突。

关键词:LOCALLOCK,LOCK,PROCLOCK,重量锁,锁表结构,ResourceOwner | 来源:202606/20260608_43.md

Q:锁等待场景下,为什么无法定位事务内"捣蛋的早期 SQL"?如何解决?

场景:session a 的事务里早期 sqla1 堵塞了 session b 的 sqlb2,但 pg_stat_activity 只能看到 session a 的 last query(sqla3),无法定位真正造成堵塞的 sqla1。原因:PG 只记录每个会话"当前"那条 SQL 和"当前"持有的锁,不记录事务内历史 SQL 及其对应的历史锁信息。解决前提是有地方存储 sqla1 及其锁信息、以及 sqlb2 请求的锁信息:1) SQL 审计日志(log_statement)存历史 SQL;2) trace_locks 参数(需编译时定义 LOCK_DEBUG)打印每次锁操作的详细信息;3) log_lock_waits 记录等待超时的会话;4) 用 pg_blocking_pids 找到堵塞 session,再结合审计日志和 trace_locks 时间线定位事务内哪条 SQL 导致堵塞。缺点是 trace_locks + SQL 审计不适合高 QPS 业务(性能影响大),更适合用 eBPF 采样方案(如 DBdoctor、pg-lock-tracer)低开销采集。畅想:若每个未结束事务在内存记录每条 SQL 及锁信息并通过视图展示,将极大方便分析锁冲突链路。

关键词:锁等待,trace_locks,SQL审计,log_lock_waits,pg_blocking_pids,LOCK_DEBUG | 来源:202406/20240606_01.md

Q:高并发下为什么会有大量 idle 连接?它和 idle in transaction 的危害有什么不同?

大量 idle 连接的产生通常是:DB 性能出现抖动导致业务请求拥塞,业务端通过新建更多连接处理拥塞请求,但没配置自动释放空闲连接或未到超时。idle(未开启事务)连接的危害主要是资源占用:1) 每个会话有私有内存,缓存访问过的对象元数据(尤其分区表每个分区独立元数据),长连接访问对象多时内存占用大,连接多了可能触发 OOM;2) 占满连接导致其他业务连接不足。而 idle in transaction(开启事务但空闲)的危害更严重,因为它还持有事务快照(backend_xmin/xid),固定 VACUUM 清理边界导致表膨胀、freeze 卡住,还可能持有锁。解决:idle 连接用 idle_session_timeout 自动释放(PG14+,早期用 pg_timeout 插件);idle in transaction 用 idle_in_transaction_session_timeout。同时业务端要做降级保护(丢请求或队列化),控制到 DB 的最大并发。

关键词:idle连接,idle in transaction,OOM,连接池,idle_session_timeout | 来源:202112/20211220_03.md

1.6 高可用 / 流复制(54 条)

Q:Ask 德哥:PG 增大字段长度会锁表吗,影响大吗?

增大字段长度(如 varchar(n) 调大)通常只修改 catalog 元数据,不重写表数据,加的锁级别较低(AccessExclusiveLock 但瞬时),对正常增删改查影响很小,一般很快完成。但如果是某些会重写表/改变物理存储的变更(如改类型、改精度导致重算),则可能锁表并重写数据,影响较大,需区分变更类型。

关键词:增大字段长度,锁表,catalog,DDL | 来源:202406/20240625_02.md

Q:CTID 物理行号在并发 DML 时的隔离性问题是什么?

CTID 是堆表中行的物理位置(页号+偏移),不是稳定的行标识。并发 UPDATE 会导致行版本移动或产生新 CTID,VACUUM 会回收空间改变 CTID。用 CTID 做行定位(如两次 UPDATE 之间用 CTID 找行)在并发下可能指向错误行或失效,应用应使用主键/唯一键而非 CTID 定位行。

关键词:CTID,物理行号,并发DML,行定位 | 来源:202109/20210902_13.md

Q:DB吐槽大会为何说 PG 不支持 update/delete skip locked, nowait 语法?

PG 的 SELECT 支持 FOR UPDATE SKIP LOCKED / NOWAIT,但 UPDATE、DELETE 本身长期不支持 SKIP LOCKED / NOWAIT 语法,导致在队列消费等场景下,想跳过已锁定的行只能绕道(如先用 SELECT … FOR UPDATE SKIP LOCKED 选出目标再更新)。这增加了并发消费场景的复杂度,是社区长期吐槽点。

关键词:skip locked,nowait,UPDATE,DELETE,队列消费 | 来源:202109/20210915_04.md

Q:DB吐槽大会为何说 PG 存储过程和函数内自治事务支持不完整?

PG 的 plpgsql 没有原生的自治事务(autonomous transaction),无法在函数/存储过程内部开启独立于外层的事务并独立提交/回滚。相比 Oracle 的自治事务,PG 只能用 dblink、临时表或模拟方式绕过,导致日志表写入、错误处理等场景不够优雅。

关键词:自治事务,存储过程,plpgsql,autonomous transaction | 来源:202109/20210929_05.md

Q:DB吐槽大会为何说 pg_stat_statements 缺乏 p99/p95 指标?

pg_stat_statements 只提供平均执行时间、总执行时间、次数等聚合指标,无法得到 p99、p95 等分位数延迟。这导致无法识别长尾慢查询(少数极慢请求拖垮体验),需要借助 pg_stat_statements + 额外采样或 pg_ash、pgpro_stats 等工具补充分位数分析。

关键词:pg_stat_statements,p99,p95,分位数,长尾 | 来源:202109/20210902_13.md

Q:Linux ftrace 如何用于 PG 性能分析和火焰图?

ftrace 是 Linux 内核跟踪工具,可记录函数调用和内核事件。对 PG 进程用 ftrace 采集函数级调用栈(配合 perf 等),再用 FlameGraph 脚本生成火焰图,可视化 CPU 热点和调用路径,定位内核态/用户态的性能瓶颈。是排查 PG 高 CPU、锁争用等问题的底层手段。

关键词:ftrace,火焰图,perf,性能分析,内核跟踪 | 来源:202101/20210119_02.md

Q:PG 流复制冲突有哪些分类,lock conflict(vacuum truncate)如何解决?

冲突分几类:lock conflict(vacuum truncate 表尾空页时与查询冲突)、buffer pin conflict、snapshot conflict 等。lock conflict 尤其指 vacuum 想 truncate 掉关系末尾空页,但查询正持有对这些页的 pin,导致回放被阻塞。解决:设置 hot_standby_feedback、调整 max_standby_*_delay 参数、缩短长查询、或临时关闭表的 autovacuum truncate。

关键词:流复制冲突,lock conflict,vacuum truncate,hot_standby_feedback | 来源:202011/20201117_02.md

Q:PG12 把 recovery.conf 合并进 postgresql.conf 后,如何配置 standby 和恢复目标?

PG12 起不再使用 recovery.conf,standby 和恢复配置直接写进 postgresql.conf。创建 standby 时在数据目录放一个空文件 standby.signal 表示以 standby 模式启动,放 recovery.signal 表示进入恢复(PITR)。恢复目标参数如 restore_command、recovery_target_time、recovery_target_lsn 等也移入 postgresql.conf。recovery_target_action 控制到达还原点后的行为(pause/promote/shutdown)。

关键词:recovery.conf,standby.signal,recovery.signal,PITR,PG12 | 来源:201905/20190503_05.md

Q:PG12 里在 standby 上 drop schema/drop database 为什么变快了,底层做了什么优化?

PG12 针对 standby 删除对象做了优化:主库释放被删对象的 shared buffer 用二分法查找,但从库此前每个对象删除都要遍历整个 shared buffer,非常慢,常导致从库延迟。PG12 把 smgrdounlink 优化为事务内删除多个对象时只扫描一次 shared buffer(smgrdounlinkall),大幅加速 standby 上 drop schema/database 的 WAL 回放。核心是避免对每个待删对象重复遍历整个 buffer pool。

关键词:standby,drop schema,smgrdounlinkall,shared buffer,复制延迟 | 来源:201903/20190331_02.md

Q:PG13 如何在 standby 节点直接监控主从延迟(latest_end_lsn)?

PG13 在 pg_stat_wal_receiver 视图新增 latest_end_lsn 字段,记录 wal receiver 最近一次接收到的 WAL 结束位置。在 standby 上查询 pg_stat_wal_receiver 的 latest_end_lsn 与 pg_last_wal_replay_lsn()(本地回放位置)的差值,即可在从库侧直接算出复制延迟,无需回主库对比。

关键词:pg_stat_wal_receiver,latest_end_lsn,主从延迟,PG13 | 来源:202005/20200520_03.md

Q:PG13 的 max_slot_wal_keep_size 参数是做什么的?

max_slot_wal_keep_size 用于限制复制槽保留 WAL 的上限。当某个复制槽需要的 WAL 超过该上限,PG 会主动 invalidate 该槽,避免 WAL 无限制膨胀撑爆磁盘。它是防止下游长期不消费导致 WAL 堆积的兜底参数,一旦槽被 invalidate 需重建才能继续复制。

关键词:max_slot_wal_keep_size,复制槽,WAL膨胀,PG13,invalidate | 来源:202007/20200720_03.md

Q:PG14 优化了流复制中因 replay lag 导致的 WAL 接收延迟吗?

是。PG14 之前,当 standby 的 startup 进程 replay 落后时,wal receiver 可能被不必要地延迟,导致 WAL 接收也变慢。PG14 修复了因 replay lag 造成的 streaming replication 不必要延迟,让 WAL 接收不再需要等待 startup 进程 replay 结束才继续,提升复制吞吐、降低延迟。

关键词:流复制,replay lag,wal receiver,PG14,复制延迟 | 来源:202010/20201010_07.md

Q:PG14 如何为逻辑复制槽启用 two_phase(两阶段)提交?

PG14 的 pg_create_logical_replication_slot 新增 two_phase 选项(true/false),启用后逻辑解码会输出 PREPARE TRANSACTION / COMMIT PREPARED / ROLLBACK PREPARED 事件,使下游能按 2PC 边界处理事务。适合需要跨资源一致性的 XA/分布式事务复制场景,但会增加解码和订阅端复杂度。

关键词:two_phase,逻辑复制槽,两阶段提交,PG14,XA | 来源:202103/20210304_05.md

Q:PG14 把 pg_stat_activity 等统计信息从 pgstat 代码拆出有何意义?

PG14 将活跃会话 pg_stat_activity、进程进度条 pg_stat_progress*、等待事件 wait_event 等信息从核心 pgstat 代码中拆出,重构了统计收集架构。这降低了对性能关键路径的影响,使统计子系统更模块化、易维护,为后续增加更多统计视图奠定基础。

关键词:pgstat,pg_stat_activity,重构,PG14,统计架构 | 来源:202101/20210119_02.md

Q:PG14 的 ALTER SYSTEM READ ONLY / READ WRITE 是什么?

PG14 支持 ALTER SYSTEM READ ONLY / ALTER SYSTEM READ WRITE 在运行时把整个实例切换为只读 barrier 模式或恢复可写,类似全局只读开关,比逐库设置 default_transaction_read_only 更彻底。适合维护窗口、备份、主从切换期间的全局只读控制,不需要重启。

关键词:alter system read only,只读barrier,PG14,全局只读 | 来源:202007/20200723_01.md

Q:PG14 的 pg_stat_progress_copy 增强监控什么?

PG14 的 pg_stat_progress_copy 增强,COPY 导入数据支持进度监控,可看到导入了多少行、排除了多少行(where filter 过滤掉的)。这让大文件 COPY 导入时能实时观察进度和过滤情况,便于估算完成时间和发现异常。

关键词:pg_stat_progress_copy,COPY,进度监控,PG14 | 来源:202101/20210119_02.md

Q:PG15 的 READ_REPLICATION_SLOT 流复制协议增强支持了什么?

PG15 增强流复制协议,READ_REPLICATION_SLOT 命令支持 physical slot(此前主要针对逻辑槽),同时 pg_receivewal 支持按 slot 位点拉取 WAL。这让物理复制工具(pg_receivewal)可以基于物理复制槽精确指定从哪个 LSN 开始接收,避免从 0 开始或只依赖 wal_keep_size。

关键词:READ_REPLICATION_SLOT,physical slot,pg_receivewal,PG15,流复制协议 | 来源:202110/20211026_01.md

Q:PG15 逻辑复制错误信息增加 errcontext(含 LSN)有什么作用?

PG15 在逻辑复制/订阅的错误信息中增加 errcontext,包含出错的 WAL LSN 和 origin 信息。结合 pg_replication_origin_advance 可以跳过冲突的 WAL 回放,即在订阅端报错时精确知道冲突位置,跳过该 LSN 继续复制,避免一个坏事务卡死整条逻辑复制链路。

关键词:errcontext,LSN,逻辑复制,pg_replication_origin_advance,PG15 | 来源:202203/20220309_02.md

Q:PG16 起 standby 支持逻辑复制,带来什么变化?

PG16 之前 standby 无法作为逻辑复制的发布端/订阅端(不能创建逻辑槽、不能应用逻辑变更),只读实例是孤岛。PG16 起 standby 支持逻辑复制,可以在从库上创建逻辑复制槽、作为 publisher 向下游输出逻辑变更,让只读实例也参与 CDC/逻辑复制链路,释放主库压力。

关键词:standby,逻辑复制,PG16,CDC,publisher | 来源:202304/20230403_01.md

Q:PG17 的 pg_createsubscriber 工具是做什么的?

pg_createsubscriber 用于把物理 standby 转换为逻辑复制订阅者(logical subscriber)。它基于物理从库已复制的数据,通过逻辑复制协议建立订阅关系,避免重新做全量逻辑初始化,是物理复制到逻辑复制平滑切换的工具,常用于大版本升级和零停机迁移场景。

关键词:pg_createsubscriber,物理转逻辑,订阅者,PG17,迁移 | 来源:202403/20240326_05.md

Q:PG17 的 pg_replication_slots.inactive_since 字段是什么?

inactive_since 记录复制槽从什么时候开始变为 inactive(断联)。物理/逻辑槽在下游断开连接后会变为 inactive,inactive_since 记录断联时间戳,用于监控哪些槽已长时间无人消费,辅助判断是否可以清理、评估 WAL 保留风险。

关键词:inactive_since,复制槽,断联,PG17,监控 | 来源:202403/20240330_03.md

Q:PG17 的逻辑复制槽 failover 和 standby_slot_names 是如何协同工作的?

PG17 支持逻辑复制槽 failover:创建槽时用 pg_create_logical_replication_slot(… failover=true) 标记该槽可随流复制同步到 standby,主从切换后 standby 上已同步的槽可继续被下游订阅。配套参数 standby_slot_names 指定一组 standby slot,主库保证这些 standby 已接收并 flush 所有逻辑槽发送逻辑数据对应的 WAL,从而在 failover 时逻辑槽安全可继续使用。

关键词:逻辑复制槽,failover,standby_slot_names,PG17,主从切换 | 来源:202401/20240126_01.md

Q:PG18 的 AIO 增强增加了哪些监控和诊断能力?

PG18 的 AIO(异步 IO)增强增加了监控工具、增强测试能力、清理代码、改进错误诊断。异步 IO 让 PG 的 IO 请求不阻塞进程,监控工具帮助观察 AIO 请求的排队、完成和错误情况,改进的诊断让 IO 问题更易定位。

关键词:AIO,异步IO,监控,诊断,PG18 | 来源:202101/20210119_02.md

Q:PG18 的 max_active_replication_origins 参数是做什么的?

PG18 新增 max_active_replication_origins,在订阅端控制可同时跟踪的 replication origins 数量,从而限制可创建的逻辑订阅数量。此前 origins 数量受 max_replication_slots 控制,但订阅端可能不需要 slot(如级联复制)却一定需要 origin,独立参数提供了更灵活的下游配置。默认 10,需预留表同步的余量,设置低于当前数量会导致无法启动。

关键词:max_active_replication_origins,replication origins,订阅,PG18 | 来源:202503/20250324_02.md

Q:PG18 的逻辑订阅冲突统计是什么?

PG18 新增逻辑复制冲突统计,收集订阅端应用变更时发生的冲突(如 insert 时主键已存在、update 找不到目标行、delete 无对应行等)。DBA 可通过统计视图观察冲突数量,判断双向复制/异构复制中数据不一致情况,便于调整冲突处理策略。

关键词:逻辑订阅,冲突统计,逻辑复制,PG18 | 来源:202409/20240904_01.md

Q:PG19 如何修复 Standby 晋升时 Slot 同步 Worker 阻塞问题?

原实现用 SIGUSR1 通知 slotsync worker 退出,但 worker 阻塞在 WaitLatch/网络 I/O 时 SIGUSR1 无法保证立即中断,导致晋升被无限期阻塞。PG19 引入专用进程信号 PROCSIG_SLOTSYNC_MESSAGE,通过 HandleSlotSyncMessageInterrupt 设置中断标志、ProcessSlotSyncMessage 执行退出,使 slotsync worker 能从任意等待状态立即脱离,保证晋升在合理时间内完成。

关键词:PROCSIG_SLOTSYNC_MESSAGE,晋升,slotsync worker,PG19 | 来源:202604/20260408_08.md

Q:PG19 对 pg_rewind 做了什么优化?

PG19 发了两个 pg_rewind 相关 patch 优化 WAL 拷贝量:一是把 isRelDataFile 重命名并扩展为 getFileContentType,能识别 WAL 文件;二是跳过分歧点之前生成的 WAL 段(要求双方同名段大小一致才跳过),只复制分歧点所在段及之后、以及 source 有而 target 无的段。这大幅降低 rewind 的 I/O 和网络传输,尤其当源库因 wal_keep_size/归档保留了大量历史 WAL 时。

关键词:pg_rewind,WAL拷贝,分歧点,PG19,优化 | 来源:202510/20251027_08.md

Q:PG19 的 WAIT FOR 优化如何避免 Hot Standby 恢复冲突?

WAIT FOR 用于等待 LSN 回放/刷新/写入。原实现构建返回元组描述符时用 TupleDescInitEntry 会访问 syscache,可能重新建立 catalog snapshot,在 standby 上引发 recovery conflict。PG19 改用 TupleDescInitBuiltinEntry(直接按内置类型 OID 查表,不碰 syscache),彻底消除该路径的 catalog 访问,避免 WAIT FOR 在热备上被取消或报错。

关键词:WAIT FOR,syscache,恢复冲突,TupleDescInitBuiltinEntry,PG19 | 来源:202604/20260407_03.md

Q:PG19 的 max_repack_replication_slots 参数解决什么问题?

REPACK CONCURRENTLY 底层依赖逻辑解码,执行时必须占用一个 replication slot,此前和逻辑复制订阅共用一个 max_replication_slots 池,容易耗尽报 all replication slots are in use。PG19 新增 max_repack_replication_slots(默认 5,PGC_POSTMASTER 级),在共享内存复制槽数组里逻辑上切出 REPACK 专用段,与普通槽独立计数、独立报错,实现槽资源按用途隔离。

关键词:max_repack_replication_slots,REPACK,复制槽,PG19,资源隔离 | 来源:202604/20260408_02.md

Q:PG19 的 pg_replication_slots.slotsync_skip_reason 是什么?

PG19 在物理 standby 的 pg_replication_slots 视图新增 slotsync_skip_reason 列,记录上一次槽同步被跳过的原因,主要针对 synced=true 的逻辑槽。取值有 wal_or_rows_removed、wal_not_flushed、no_consistent_snapshot、slot_invalidated,同步成功时为 NULL。持续非 NULL(尤其 wal_or_rows_removed、slot_invalidated)需 DBA 介入,否则 standby 提升后逻辑槽可能不可用。

关键词:slotsync_skip_reason,槽同步,物理standby,PG19 | 来源:202511/20251128_10.md

Q:PQTrace 是做什么的?

PQTrace 是 libpq 的协议层跟踪功能,可打印 frontend(客户端)和 backend(服务端)之间的协议交互内容(SQL 发送、结果返回、错误消息等)。用于调试客户端驱动、分析协议行为、定位应用与数据库交互问题。

关键词:PQTrace,libpq,协议跟踪,frontend,backend | 来源:202101/20210119_02.md

Q:Patroni 的 ttl/loop_wait/retry_timeout 三者约束关系是什么?

必须满足 loop_wait + 2 * retry_timeout <= ttl,默认 ttl=30、loop_wait=10、retry_timeout=10。loop_wait 决定 HA loop 频率(故障发现速度),retry_timeout 决定 DCS/PG 操作卡住时旧主停止写入的快慢,ttl 是 leader 租约时长。调小加快检测但放大误切,调大抗抖但延长故障窗口,本质在故障发现速度、误切概率、旧主停写窗口间取平衡。

关键词:Patroni,ttl,loop_wait,retry_timeout,HA参数 | 来源:202606/20260608_35.md

Q:Patroni 的 watchdog 和 failsafe 分别解决什么问题?

watchdog 解决本机不可信问题:Patroni 进程崩溃/OOM/高负载时,靠 OS/硬件设备在无 keepalive 时重置整机,避免 leader key 过期后旧主还继续写。failsafe 解决 DCS 暂时不可达但成员仍互通的窄场景:启用 failsafe_mode 后 primary 向 /failsafe 所有成员发 POST /failsafe,只有全部确认它仍是 primary 才允许继续写,否则 demote。两者都不能替代 DCS 共识。

关键词:Patroni,watchdog,failsafe,DCS,脑裂 | 来源:202606/20260608_35.md

Q:Patroni 的六层架构和核心 HA 逻辑是什么?

Patroni 是 PG 高可用模板,六层架构:DCS 层(存 leader lock、成员状态、动态配置、同步状态)、HA 状态机(每周期决定 start/promote/demote/follow/rewind/noop)、PG 管理层(启停、写配置、promote/follow)、REST API(健康检查、管理、成员互探)、CLI 层(patronictl)、外部路由(HAProxy/K8s Service)。核心是 leader 是 DCS 中有 TTL 的租约,只有持有 /leader 并按时更新的节点才允许当 primary。

关键词:Patroni,DCS,leader lock,HA状态机,六层架构 | 来源:202606/20260608_35.md

Q:PostgreSQL 主从切换发生脑裂后如何处理与预防?

脑裂即旧主和新主同时接受写入。处理用 pg_rewind 把旧主回退到新主时间线后重新作为 standby。预防手段包括:用 DCS leader lock 作为集群裁判、watchdog(本机不可信时整机重置)、failsafe(DCS 不可达但成员互通的窄场景)、时间线检查,以及用同步复制降低分叉风险。核心目标是确保任意时刻只有一个节点对外承诺写入。

关键词:脑裂,pg_rewind,时间线,DCS,watchdog,split brain | 来源:201907/20190719_01.md

Q:PostgreSQL 的 pg_stat_progress_copy 进度监控是什么?

pg_stat_progress_copy 是 COPY 操作进度监控视图,显示导入/导出的行数、排除的行数(WHERE 过滤掉的)、当前阶段等。PG14 增强支持,让大文件 COPY 导入时能实时观察进度,估算完成时间、发现异常。配合 pg_stat_progress_vacuum、pg_stat_progress_create_index 等构成进度监控体系。

关键词:pg_stat_progress_copy,COPY,进度监控 | 来源:202101/20210119_02.md

Q:libpq 如何配置连接在多个后端节点之间的读写倾向和 failover?

libpq 连接串支持 target_session_attrs 参数(read-write/read-only/any/prefer-standby 等),配合多 host 列表(host=host1,host2)实现读写倾向与 failover。例如 target_session_attrs=read-write 优先连主库,read-only 连从库。驱动层会依次尝试每个 host 直到找到匹配节点,实现透明的读写分离和故障转移。

关键词:libpq,target_session_attrs,读写分离,failover,多host | 来源:201909/20190901_07.md

Q:pg-ferret 是什么?

pg-ferret 是基于 eBPF 的低 overhead 采样 All-in-one tracing toolkit,用于 PostgreSQL 的全链路追踪。利用 eBPF 在内核态低开销地采集 PG 的调用栈、等待、IO 等,避免传统插桩的性能损耗,适合生产环境做细粒度 tracing 和性能诊断。

关键词:pg-ferret,eBPF,低开销,采样,tracing | 来源:202101/20210119_02.md

Q:pgCluu 是什么监控工具?

pgCluu 是 PostgreSQL 集群利用率(Cluster utilization)监控和审计工具,采集 PG 和系统指标,生成报告展示数据库集群的负载、连接、缓存、锁、vacuum、IO 等利用率情况,帮助 DBA 评估集群健康度和资源使用。

关键词:pgCluu,集群利用率,监控,审计 | 来源:202101/20210119_02.md

Q:pgSCV 是什么?

pgSCV 是 PostgreSQL 的 metrics exporter(指标导出器),用于把 PG 的运行指标(监控图表、报告、日志、建议、推荐)导出给 Prometheus 等监控系统,类似 node_exporter 之于系统监控。它聚合多个 pg_stat* 视图的指标,提供查询建议和配置推荐,是 PG 监控体系的数据采集端。

关键词:pgSCV,metrics exporter,Prometheus,监控 | 来源:202101/20210119_02.md

Q:pg_auto_failover 1.4 的 quorum based multi-standbys 是什么?

pg_auto_failover 1.4 支持 quorum(仲裁)based 多从库:通过复制仲裁决定哪些从库必须确认才算同步提交,并支持把一个节点从复制 quorum 中移除。它依赖一个 monitor 节点存储集群状态并决策 failover,运行时只依赖 PG(支持 PG10-13)。quorum 机制降低了单个慢副本对同步提交的影响。

关键词:pg_auto_failover,quorum,multi-standbys,monitor,仲裁 | 来源:202010/20201011_01.md

Q:pg_upgrade 升级会销毁所有 replication slot 吗?

会。pg_upgrade 在跨大版本升级时会销毁(不保留)所有 replication slots,因为 slot 依赖的 WAL 格式和状态无法跨版本迁移。升级前需记录并在升级后重新创建物理/逻辑复制槽,否则下游复制会中断。

关键词:pg_upgrade,replication slot,大版本升级 | 来源:202107/20210714_02.md

Q:pg_wait_sampling 插件记录什么?

pg_wait_sampling 是等待事件采样统计插件,记录等待事件的次数(calls),但不记录每次等待的时间。它周期性采样各进程的等待事件并聚合计数,可配合 powa 等展示等待事件维度的统计,帮助发现高频等待,但无法区分单次长等待还是多次短等待。

关键词:pg_wait_sampling,等待事件,采样,次数 | 来源:201610/20161006_01.md

Q:recovery_min_apply_delay 如何防止主从切换后下游时间线错乱?

recovery_min_apply_delay 让 standby 延迟应用 WAL,人为制造回放滞后窗口。这样在主从切换时,如果下游(级联 standby 或逻辑订阅)发现新主回放位置异常,可以靠这段延迟窗口留出纠错时间,避免下游立即跟随到错误时间线。它是一种防时间线错乱的缓冲手段,代价是引入可控的复制延迟。

关键词:recovery_min_apply_delay,时间线,级联复制,主从切换 | 来源:201909/20190914_01.md

Q:savepoint 的内存开销和子事务溢出问题是什么?

大量使用 savepoint 会创建子事务,每个子事务消耗 XID 和内存,子事务过多时 PGPROC 缓存(默认最多 64 个)溢出,可见性检查会更多依赖 pg_subtrans 追溯顶层 XID,检查成本上升。PL/pgSQL 的 EXCEPTION 块在循环里隐式制造大量子事务,是常见性能杀手,应避免在一个大事务里创建成千上万个 savepoint。

关键词:savepoint,子事务,溢出,pg_subtrans,EXCEPTION | 来源:202109/20210902_13.md

Q:standby 上的查询冲突有哪些典型来源,如何解决?

典型冲突:vacuum 清理正在回放事务可能要访问的旧版本、truncate 掉查询已 pin 的页、锁冲突、buffer pin 冲突、快照冲突等。解决手段:开启 hot_standby_feedback 让主库知道从库正在读的 xmin(会带来主库膨胀风险)、设置 max_standby_archive_delay/max_standby_streaming_delay 延长回放等待、或缩短长查询。核心是查询快照与回放清理之间的竞争。

关键词:standby冲突,hot_standby_feedback,vacuum,恢复冲突,max_standby_delay | 来源:202005/20200518_01.md

Q:为什么 PG 的 multi-master(多主)支持不友好?

PG 内置逻辑复制 pub/sub 对同一张表只能单向复制,双向复制会无限循环打环;且无法很好解决并发写同一行导致的数据冲突(如两边同时 update 同一条记录)。实现 multi-master 需业务自己开发同步工具加事务标记防打环,或用 krahodb、postgrespro postgres_cluster、pglogical 等第三方工具,但会引入复杂度、工具可靠性、复制冲突、全局序列等问题。

关键词:multi-master,双向复制,数据冲突,逻辑复制,打环 | 来源:202109/20210929_01.md

Q:为什么会出现大量 idle in transaction 事务,有什么危害?

idle in transaction 是事务已开启(BEGIN 后)但客户端未继续提交/回滚、处于空闲的状态,常见于应用开启事务后长时间等待外部操作(人工审批、远程调用)或连接池泄漏。危害:持有快照和 xmin,阻止 vacuum 清理旧版本导致表膨胀;可能持有锁阻塞其他事务;长期占用连接资源。

关键词:idle in transaction,长事务,表膨胀,连接泄漏 | 来源:202109/20210902_13.md

Q:为什么会发生死锁?

死锁是多个事务互相等待对方持有的锁形成的循环等待。典型如事务 A 持有行1锁等行2,事务 B 持有行2锁等行1。PG 有死锁检测器,检测到后回滚其中一个事务(报 deadlock detected)。避免死锁的方法:统一加锁顺序、缩短事务、使用 SKIP LOCKED/NOWAIT、减少事务内锁粒度。

关键词:死锁,循环等待,锁,deadlock detected | 来源:202109/20210902_13.md

Q:同步复制配置变更后,walsender 如何立即释放等待者?

此前修改 synchronous_standby_names(如从 ANY 2 降级 ANY 1)后,已陷入等待的 backend 不会立即释放,要等从库下一条消息触发,甚至需手动 kill。新 commit 让 walsender 在检测到配置重载时立即调用 SyncRepReleaseWaiters(),一旦新配置满足当前已传输 LSN,就即时释放所有符合条件的等待进程,把切换时延从网络随机量变成指令执行常量,消除僵尸等待。

关键词:同步复制,降级,walsender,SyncRepReleaseWaiters,僵尸等待 | 来源:202602/20260224_03.md

Q:用 pg_basebackup 建异地 standby 的关键步骤和参数是什么?

核心是 pg_basebackup 加 -X stream(流式拉 WAL)、–write-recovery-conf(生成 primary_conninfo)生成 standby 配置,同时配置 primary_conninfo 指向主库,主库 pg_hba.conf 放行 replication。主库需创建物理复制槽(pg_create_physical_replication_slot)保证 WAL 不被清理。之后启动从库即可持续流复制。

关键词:pg_basebackup,异地从库,-X stream,物理复制槽,primary_conninfo | 来源:201911/20191112_01.md

Q:逻辑复制槽的 restart_lsn 和 confirmed_flush_lsn 有什么区别?

confirmed_flush_lsn 是消费者已确认接收数据的 LSN(逻辑槽),重启后从此继续;restart_lsn 是消费者可能仍需要的最旧 WAL 位置,用于 WAL 保留边界。因事务按提交顺序发布、且并发事务可能乱序,restart_lsn 可能早于 confirmed_flush_lsn。大型或长时间运行的事务会卡住 restart_lsn 前进导致 WAL 膨胀,所以应尽量避免大事务。

关键词:restart_lsn,confirmed_flush_lsn,逻辑槽,WAL保留,大事务 | 来源:202508/20250808_06.md

Q:逻辑复制的 row filter(行过滤)是什么,何时引入?

逻辑复制 row filter 允许在发布端只复制满足 WHERE 条件的行,用于选择性复制,减少下游数据量和网络开销。该功能在 PG15 正式引入(此前为 devel preview),配置在 publication 的表级 WITH (WHERE …) 子句上,被过滤掉的行不会发送到 subscriber。

关键词:逻辑复制,row filter,行过滤,publication,PG15 | 来源:202202/20220222_01.md

Q:阿里云 RDS PG 的 HA 保护模式(最大保护/最高可用/最大性能)分别是什么?

三种保护模式对应不同同步策略:最大保护(全同步)要求所有同步副本确认才提交,副本故障会阻塞写入,RPO=0;最高可用(半同步)至少一个同步副本确认,副本全挂时自动降级为异步保证可用;最大性能(异步)不等待副本确认,性能最好但可能丢数据。本质是同步复制强度在一致性与可用性之间的权衡。

关键词:HA保护模式,最大保护,最高可用,最大性能,同步复制 | 来源:202002/20200205_01.md

1.7 备份恢复 / PITR(35 条)

Q:DB吐槽大会为何说 PG 不支持 Partial PITR?

PG 原生 PITR 是整库级别的,无法只恢复库里的某张表或某个 schema 到过去某个时间点,而 Oracle 等支持表空间级/对象级恢复。要实现 Partial PITR 需要额外的表空间备份 + 手动组装,或借助第三方工具,运维复杂、成本高。

关键词:Partial PITR,整库恢复,表空间,PITR | 来源:202109/20210902_12.md

Q:DB吐槽大会为何说 PG 无法 PITR 恢复到物理全量备份过程中的时刻?

PG 的在线备份是 pg_start_backup 到 pg_stop_backup 之间完成的,备份文件本身可能处于不一致的中间状态(备份过程中某 block 写一半被拷贝),必须回放到 stop 点之后的 WAL 才能保证一致。因此无法把 PITR 目标设到备份过程中某个时刻,只能恢复到 stop point 及之后的时间点。

关键词:PITR,在线备份,pg_stop_backup,一致性 | 来源:202305/20230510_01.md

Q:DB吐槽大会为何说 PG 长期没有 block 级增量备份恢复?

此前 PG 原生只支持全量备份 + WAL 归档的 PITR,块级增量备份要靠 pg_rman、pg_probackup、ptrack、ZFS 快照等第三方方案。block 级增量备份可以只备份自上次备份以来变化的数据块,大幅节省空间和时间。直到 PG17 才内置了块级物理增量备份(WAL summarizer + pg_combinebackup)。

关键词:块级增量备份,pg_rman,ptrack,PG17,增量备份 | 来源:202109/20210907_01.md

Q:PG 全库一致性逻辑备份时,大表备份有哪些隐患?

全库一致性逻辑备份(pg_dump)需要一致性快照,大表备份耗时且需持有锁,可能引发锁等待和表膨胀。备份期间长期持有快照会阻止 vacuum 清理旧版本,导致表膨胀;大表 COPY 也可能长时间占用资源。建议大表用物理备份(pg_basebackup)或表级并行备份,配合合理的备份窗口。

关键词:逻辑备份,大表,锁等待,膨胀,一致性快照 | 来源:201908/20190804_03.md

Q:PG 在线备份中,恢复的最小 WAL 范围(startpoint 到 stoppoint)是如何确定的?

pg_start_backup 后执行 checkpoint,backup_label 记录该 checkpoint 的 redo 位置(START WAL LOCATION),从这个位置开始有需要的 FPW(full page write)。备份文件中可能有 block 写一半被拷贝,必须回放到该 block 在 checkpoint 后第一次修改产生的 FPW,才能保证一致。stoppoint 是 pg_stop_backup 写入 WAL 的结束标记 LSN(standby 上则是 ControlFile->minRecoveryPoint)。t0~t3 之间的 WAL 是恢复的最小需求。

关键词:在线备份,backup_label,startpoint,stoppoint,FPW | 来源:202401/20240113_02.md

Q:PG 崩溃恢复如何通过 prefetch 预读加速?

PG14/15 的 recovery 支持 prefetch 预读:提前把接下来要恢复的 WAL record 相关的 data block 读入 shared buffer,加速 WAL record 与 data block 的合并过程,减少恢复时的磁盘随机读等待。PG15 进一步支持异步 prefetch,覆盖崩溃恢复、逻辑/物理流复制、归档恢复等多种恢复场景。

关键词:prefetch,预读,崩溃恢复,recovery加速,PG15 | 来源:202104/20210409_03.md

Q:PG 的 pg_checksums 在线校验和限速能力如何?

pg_checksums 1.0 起支持在线校验 block checksum(早期版本需停库),并支持限速(rate limit),兼容 9.3 以上所有 PG 版本。限速能力让校验大库时可以控制对磁盘 I/O 的冲击,避免影响在线业务。

关键词:pg_checksums,在线校验,限速,checksum | 来源:201910/20191027_02.md

Q:PG12 的 pg_stat_database 新增 checksum 失败统计有什么意义?

PG12 在 pg_stat_database 新增 block checksum 失败计数列,统计属于该库的数据文件发生的 checksum 校验失败次数,包括正常 backend 处理时的失败和 base backup 检测到的失败。这能帮助尽早发现底层 I/O 系统的问题(坏块、静默数据损坏)。

关键词:pg_stat_database,checksum失败,坏块,IO问题,PG12 | 来源:201904/20190405_03.md

Q:PG14 支持 startup(恢复)进程与 backend 进程的死锁检测吗?

支持,PG14 引入了 startup 进程与 backend 进程之间的死锁检测(backpatch 到 9.6)。此前恢复进程与用户进程之间的死锁可能无法被检测,导致恢复被永久卡住。该特性在恢复冲突场景下检测恢复进程和用户查询之间的死锁并打破,避免 standby 恢复停滞。

关键词:死锁检测,startup进程,backend进程,恢复冲突,PG14 | 来源:202104/20210415_04.md

Q:PG14 的 DropRelFileNodeBuffers 优化解决了什么恢复性能问题?

SaaS 类用户在 drop 大量表/索引时,主库释放被删对象 shared buffer 用二分法查找很快,但从库每个对象删除都遍历整个 shared buffer,shared buffer 很大时一万个对象可能延迟数小时。PG14 在 recovery 路径优化 DropRelFileNodeBuffers:当待 truncate 的 block 数低于阈值时通过 BufMapping 表查找,避免全 buffer pool 扫描,性能提升百倍以上。

关键词:DropRelFileNodeBuffers,recovery,shared buffer,drop对象,PG14 | 来源:202101/20210113_01.md

Q:PG14 的 idle_session_timeout 和 idle_in_transaction_session_timeout 有何区别?

idle_in_transaction_session_timeout 只针对 idle in transaction(事务内空闲)的会话超时;PG14 新增的 idle_session_timeout 针对所有空闲会话(包括纯 idle)超时,自动断开空闲连接。两者都用于清理长期空闲会话、释放连接资源,避免连接风暴和资源占用。

关键词:idle_session_timeout,idle_in_transaction_session_timeout,空闲会话,PG14 | 来源:202104/20210415_04.md

Q:PG14 的 log_recovery_conflict_waits 参数有什么用?

PG14 新增 log_recovery_conflict_waits,控制当 startup 进程因恢复冲突等待超过 deadlock_timeout 时是否打印日志。日志包含冲突对应的锁类型、导致冲突的 backend pid 等信息,方便观察冲突发生的历史事件,判断恢复冲突是否阻碍了 WAL 回放。

关键词:log_recovery_conflict_waits,恢复冲突,deadlock_timeout,PG14 | 来源:202101/20210108_02.md

Q:PG14 的 pg_locks 新增 wait_start 字段有什么用?

PG14 在 pg_locks 视图新增 wait_start 字段,记录锁等待开始的时间。这样 DBA 可以知道某个锁等待已经持续多久,便于结合 now() 判断等待时长,快速定位长时间未获得的锁,辅助分析锁争用和死锁风险。

关键词:pg_locks,wait_start,锁等待时长,PG14 | 来源:202104/20210415_04.md

Q:PG14 的逻辑解码如何支持 2PC(两阶段事务)?

PG14 的逻辑解码新增对 2PC(两阶段事务、XA 事务)的支持。逻辑复制槽启用 two_phase 后,逻辑解码会输出 PREPARE TRANSACTION、COMMIT PREPARED、ROLLBACK PREPARED 事件,使订阅端能按两阶段边界处理分布式事务,保证跨资源提交的一致性语义可被复制。

关键词:逻辑解码,2PC,两阶段,XA,PG14 | 来源:202104/20210415_04.md

Q:PG15 为 archive_command/restore_command 等新增了什么等待事件?

PG15 新增了针对 archive_command、archive_cleanup_command、restore_command、recovery_end_command 等外部 shell 命令的等待事件。当这些命令执行缓慢时,可在 pg_stat_activity 的 wait_event 中看到对应等待,便于定位归档/恢复命令卡顿问题。

关键词:等待事件,archive_command,restore_command,PG15 | 来源:202111/20211123_01.md

Q:PG15 支持自定义归档 WAL 日志模块是什么意思?

PG15 允许通过模块(如 basic_archive 或第三方扩展)自定义归档 WAL 日志的行为,而不只是用 archive_command shell 命令。这提供了更灵活、可编程的归档方式,便于集成到对象存储、云归档等场景。

关键词:自定义归档,WAL归档模块,PG15,archive_library | 来源:202202/20220208_02.md

Q:PG15 的 basebackup_to_shell 扩展插件是做什么的?

PG15 支持在插件中增加 pg_basebackup target,并提供内置的 basebackup_to_shell 扩展。配合 pg_basebackup,可以触发数据库 server 端执行自定义 shell 备份动作(如把备份直接写到挂载盘或远程),把备份逻辑下沉到服务端,扩展了 pg_basebackup 的备份目的地。

关键词:basebackup_to_shell,pg_basebackup target,shell备份,PG15 | 来源:202203/20220316_02.md

Q:PG15 的 log_startup_progress_interval 参数有什么用?

PG15 新增 log_startup_progress_interval,支持打印 startup 进程长时间的恢复进度。当崩溃恢复/PITR 回放耗时较长时,按配置的时间间隔周期性输出恢复进度日志,让 DBA 知道恢复进行到哪一步、还差多少,避免恢复过程长时间无反馈。

关键词:log_startup_progress_interval,恢复进度,startup进程,PG15 | 来源:202110/20211026_02.md

Q:PG15 的 pg_basebackup 在压缩方面有哪些增强?

PG15 的 pg_basebackup 增强压缩能力:支持客户端压缩和服务端(DB 端)压缩,压缩算法支持 gzip、lz4、zstd,并可指定压缩比选项(如 zstd 支持内置并行 workers)。服务端压缩可减轻网络传输量(代价是主库 CPU 开销),客户端压缩减轻磁盘占用。

关键词:pg_basebackup,压缩,gzip,lz4,zstd,PG15 | 来源:202201/20220125_01.md

Q:PG16 的 pg_dump 批量加表级共享锁解决什么问题?

PG16 的 pg_dump 改为批量加表级共享访问锁,减少加锁交互次数和时长。此前逐个对象加锁交互多、耗时,改进后提升备份启动效率,也降低了备份期间与 DDL 交互的死锁窗口。

关键词:pg_dump,共享锁,批量加锁,PG16 | 来源:202301/20230104_01.md

Q:PG17 内置的块级增量备份(pg_combinebackup)是如何工作的?

PG17 新增 WAL summarizer 进程,自动生成 WAL summary 文件(存于 $PGDATA/pg_wal/summaries),记录一段 LSN 范围内每个 relation 被修改的 block 列表、文件创建/销毁、truncate 到的最小长度等信息。pg_basebackup –incremental=PATH_TO_MANIFEST 上传上一备份的 manifest 后生成增量备份(文件名为 INCREMENTAL.原名),pg_combinebackup 把全量+一个或多个增量合并为新的全量。

关键词:pg_combinebackup,增量备份,WAL summarizer,PG17,summarize_wal | 来源:202312/20231222_01.md

Q:PG17 的 pg_restore –transaction-size=N 是什么?

PG17 的 pg_restore 新增 –transaction-size=N 选项,支持把 N 个对象封装为一个事务提交。这样在恢复大量对象时,可以控制每个事务包含的对象数量,平衡事务大小与失败重试粒度,避免一个超大事务恢复失败全部回滚,也避免每个对象单独提交导致恢复过慢。

关键词:pg_restore,transaction-size,恢复事务,PG17 | 来源:202404/20240402_01.md

Q:PG19 的逻辑复制数据库级快照优化是什么?

PG19 对逻辑复制初始同步的数据库级快照做了优化(相关 patch 聚焦于 logical replication 的 snapshot 处理),改进快照生成与一致性维护方式,降低逻辑复制建链时对源库的影响,提升大库逻辑初始同步的效率。

关键词:逻辑复制,数据库级快照,初始同步,PG19 | 来源:202604/20260407_09.md

Q:PITR 恢复时,最后一个 WAL 文件没有事务结束 record 或 target name,能恢复到指定时间点吗?

能 promote。类似数据库 COPY 大量数据过程中 crash,最后一个有效 WAL 文件可能没有事务结束 record,但从检查点开始恢复、CLOG 恢复正常,仍能到一致性状态。能否区分是否恢复结束取决于 recovery_target_action:pause 时查 pg_is_wal_replay_paused() 是否返回 true,promote 时看是否已激活,shutdown 时看是否已停库。

关键词:PITR,事务结束record,recovery_target_action,一致性 | 来源:201906/20190610_02.md

Q:PITR 恢复过程中如何手工得到下一个需要的 WAL 文件名?

默认由 restore_command 自动获取,若需手工得到,可用三种方法:一是让 restore_command 在找不到文件时把 %f 追加到日志文件(如 cp … || echo “%f” » /tmp/needwalfile);二是看数据库日志里 cp cannot stat 的输出;三是改内核用 UDF 获取(但受 hot_standby 限制)。恢复目标支持时间、还原点名字、事务 ID、WAL LSN 四种。

关键词:PITR,restore_command,WAL文件名,recovery_target | 来源:201903/20190305_01.md

Q:PostgreSQL 的增量备份和增量还原基本流程是什么?

基于 PG17 内置能力:先做一次全量备份(记录 manifest),之后用 pg_basebackup –incremental=PATH_TO_MANIFEST 生成增量备份(只含变化块),最后用 pg_combinebackup 把全量 + 一串增量合并还原为一个新的全量数据目录。WAL summarizer 后台进程负责统计每个 LSN 范围内变化的 block,summarize_wal 控制开关,wal_summary_keep_time 控制 summary 文件保留时长(默认 10 天)。

关键词:增量备份,增量还原,pg_combinebackup,manifest,WAL summarizer | 来源:202606/20260608_65.md

Q:minimum recovery point(minRecoveryPoint)在恢复过程中如何推进?

minRecoveryPoint 是控制文件中的最小恢复点,表示数据库至少恢复到这个 LSN 才一致。恢复过程中它不断推进,记录已经安全应用到控制文件的重做位置。如果恢复中途 crash,必须重新到达这个点数据库才一致。在线备份在 standby 上执行时,备份结束位置就是 minRecoveryPoint。

关键词:minRecoveryPoint,最小恢复点,恢复一致性,控制文件 | 来源:202107/20210729_02.md

Q:pg_dump 并行备份为什么可能失败,报 ACCESS EXCLUSIVE lock 错误?

并行备份时 parent 进程先对所有对象加 shared lock,worker 备份每个表前再加 shared lock NOWAIT。若有客户端在此期间请求 ACCESS EXCLUSIVE 锁,该锁会排队并阻塞后续所有访问(包括 worker 的 shared lock NOWAIT),导致 worker 拿锁失败、整个 pg_dump 中止。解决:备份期间不要执行 DDL,或给用户设置 lock_timeout。

关键词:pg_dump,并行备份,ACCESS EXCLUSIVE,死锁,lock_timeout | 来源:201904/20190417_03.md

Q:pg_filedump 是做什么用的?

pg_filedump 用于查看和诊断 PG 数据文件/数据页的底层内容,可 dump 出 page header、tuple header、行数据等二进制结构。当数据块损坏、需抢救数据或分析页结构时,用它直接读取堆文件内容,是数据块级恢复和排障的常用工具。

关键词:pg_filedump,数据块,页结构,恢复,排障 | 来源:202107/20210715_03.md

Q:pg_verify_checksums / pg_checksums 工具是做什么的,有什么限制?

pg_verify_checksums 用于校验 PG 数据文件块的 checksum 一致性,需在停库(离线)状态下执行,识别到错误会直接退出。PG12 起重命名为 pg_checksums,并支持把数据文件从无 checksum 转为有 checksum(enable/disable)。数据文件块尾部记录 LSN,checksum 校验可验证恢复后的数据块是否逻辑一致。

关键词:pg_verify_checksums,pg_checksums,checksum,数据块校验,离线 | 来源:201902/20190213_02.md

Q:pg_waldump 和 pg_verifybackup 分别用于检查什么?

pg_waldump 用于检查 WAL 文件、归档文件是否损坏,原理是校验 WAL record 的 CRC(WAL checksum 强制开启)。pg_verifybackup 检查 pg_basebackup 备份的数据文件是否有损坏,会调用 pg_waldump 解析备份中 WAL。注意 WAL 文件循环使用可能残留未初始化内容导致 pg_waldump 误报,属正常现象。

关键词:pg_waldump,pg_verifybackup,WAL校验,CRC,备份校验 | 来源:202203/20220318_01.md

Q:为什么基于表空间的在线备份和完全恢复是可行的?

恢复模式下 backup_label 文件的 START WAL LOCATION 优先级高于控制文件的 checkpoint 位置,PG 会从 backup_label 标记的 WAL 位置开始恢复。因此只需 backup_label + 表空间备份 + WAL 归档,就能把表空间恢复到最新状态。但如果要 PITR 恢复到过去某时刻(而非最新),还必须备份全局数据($PGDATA),否则全局数据块是未来的,元数据可能出错。

关键词:表空间,在线备份,backup_label,完全恢复,PITR | 来源:202401/20240110_01.md

Q:为什么开启归档但 archive_command 为空字符串会导致 WAL 堆积?

当 archive_mode 开启而 archive_command 是空字符串(默认)时,WAL archiving 被临时禁用,但服务器会继续累积 WAL 段文件并保留 archive_status 目录中的 .ready 状态文件,等待将来提供命令。若想开启归档但暂不真实拷贝,可配置一条返回 true 的命令(如 /bin/true)避免堆积,但会打断归档恢复所需的 WAL 链,应谨慎。

关键词:archive_command,archive_mode,WAL堆积,归档 | 来源:202010/20201003_01.md

Q:如何实现可选择性表空间(Selectivity Tablespace)备份和时间点恢复?

如果要只对部分表空间做备份并支持 PITR,必须同时备份全局数据($PGDATA)+ backup_label + 目标表空间 + WAL 归档。因为全局数据文件是最新的,若不能回放完整 WAL 到最新状态,全局数据里某些 block 可能是未来的,元数据内容会出错。只有时间线未分叉、redo 文件完整时理论上才安全。

关键词:选择性表空间,备份,PITR,backup_label,全局数据 | 来源:202401/20240107_01.md

Q:开启 checksum 后遇到损坏 block 导致恢复失败,如何跳过?

可以临时设置 ignore_checksum_failure=on(仅 superuser 可改),使系统忽略 checksum 失败(仍报 warning)并继续处理,从而恢复出未损坏的元组。但该行为可能传播或隐藏损坏、导致 crash 等严重后果;若 block header 本身损坏仍会报错。默认 off,只建议在抢救数据时短暂开启。

关键词:ignore_checksum_failure,checksum,损坏块,数据抢救 | 来源:202101/20210118_02.md

1.8 逻辑复制 / CDC / 异构同步(26 条)

Q:PG 什么时候必须用 HugePages?

当 shared_buffers 很大(如 ≥8GB)、连接数多、且 relcache/catcache/plancache 等热工作集大时,使用 HugePages(大页)可显著降低 TLB miss,避免大量 4KB 小页带来的页表遍历开销。大页把页表项从千万级降到万级,减少内存访问延迟和缺页中断,尤其适合大 shared_buffers、多连接、多对象的高并发场景。启用需要配置 vm.nr_hugepages 并让 PG 进程有权限用大页,否则启动会失败。

关键词:HugePages,TLB miss,shared_buffers,relcache,大页,页表 | 来源:202608/20260809_02.md

Q:PG 同步逻辑复制有哪些『巨坑』?

坑主要在语义和时机上:一是 failover=true 的槽如果备库没及时同步,切主后订阅端可能缺数据;二是 hot_standby_feedback 会把备库的 catalog_xmin 反馈给主库,主库清理 catalog 死元组被阻塞,可能造成系统表膨胀;三是槽同步依赖物理备库与主库的 LSN 追赶,网络抖动会导致槽同步延迟。使用前要确认 sync_replication_slots 与物理复制配置一致,并监控 catalog_xmin 前进情况,否则高可用反而引入新故障。

关键词:同步逻辑复制,坑,failover,hot_standby_feedback,catalog_xmin,膨胀 | 来源:202512/20251222_01.md

Q:PG14 如何解决大事务逻辑复制的延迟问题?

PG14 引入 streaming 流式复制:对超过 logical_decoding_work_mem 的大事务,逻辑解码边产生边发送变更,而不是等事务提交才一次性落盘 spill 文件再发送,从而大幅缩短大事务的端到端延迟。之前大事务要等提交后才能解码发送,导致长时间无数据流动、订阅端延迟剧增。通过流式接口(pg_logical streaming API)把变更增量流式吐出。

关键词:streaming,大事务,逻辑复制,PG14,流式,spill | 来源:202105/20210512_01.md

Q:PG15 发布支持发布整个 schema 里的所有表吗?

支持。PG15 允许发布某个 schema 下的所有表(Allow publishing the tables of schema),类似之前 FOR ALL TABLES,可针对指定 schema 一键发布。配合后续 PG19 的 EXCEPT TABLE 黑名单,发布配置越来越灵活:既可按 schema 发布,又可排除个别表,让逻辑复制的表集合管理更接近生产需要,减少逐表 CREATE PUBLICATION 的维护成本。

关键词:PG15,schema发布,publication,FOR ALL TABLES,逻辑复制 | 来源:202110/20211028_01.md

Q:PG15 逻辑复制对 2PC(两阶段提交)事务做了什么支持?

PG15 支持逻辑解码和订阅回放 2PC 两阶段提交事务:PREPARE TRANSACTION 的变更先被解码输出,等 COMMIT PREPARED 再确认应用,保证分布式场景下事务原子性在逻辑复制流里正确表达。此前逻辑复制无法正确处理 2PC,会导致事务边界错乱。开启后订阅端能正确重放跨节点协调的两阶段事务,配套 publication/subscription 的 two_phase 相关选项。

关键词:2PC,两阶段提交,逻辑复制,PG15,PREPARE TRANSACTION | 来源:202106/20210630_02.md

Q:PG16 为什么允许 standby 上做逻辑解码?

PG16 允许在物理 standby(从库)上建立逻辑复制槽并进行逻辑解码,让订阅端可以直接从从库消费,把逻辑复制的解码负载从主库转移出去,减轻主库压力。这需要 standby 开启 wal_level=logical 且保留足够 WAL,主库把逻辑解码所需信息随 WAL 同步过来。这样主库专注写,从库承担 CDC/订阅读取,是读写分离在复制侧的延伸。

关键词:standby,逻辑解码,PG16,从库,CDC,wal_level=logical | 来源:202304/20230410_07.md

Q:PG16 对大事务逻辑复制做了什么并行优化?

PG16 支持订阅端并行回放大事务:设置 subscription 参数 streaming=‘parallel’ 后,apply worker 会把大事务拆分给多个并行 apply worker 同时回放,突破单线程回放的瓶颈。使用并行回放要注意 max_parallel_apply_workers_per_subscription 等参数,且并行回放下事务内依赖顺序仍需保证。PG18 起把默认行为改为 parallel,进一步释放大事务复制性能。

关键词:并行回放,streaming=parallel,apply worker,PG16,PG18 | 来源:202301/20230110_03.md

Q:PG18 对大事务逻辑复制性能做了什么改进?

PG18 把大事务逻辑复制的默认行为升级为并行应用(parallel apply),并把流式解码与并行回放结合,减少大事务在订阅端的延迟。同时继续优化逻辑解码内存管理和 spill,让超过 logical_decoding_work_mem 的大事务复制更平滑。整体方向是让大事务从『提交后一次性解码』演进为『流式+并行』,把复制延迟压到接近实时的水平。

关键词:PG18,大事务,并行,逻辑复制,流式解码 | 来源:202410/20241028_02.md

Q:PG19 发布端 EXCEPT TABLE 黑名单是干什么的?

EXCEPT TABLE 允许发布端用 CREATE PUBLICATION … FOR ALL TABLES EXCEPT (表名) 的方式,把『除指定表外的所有表』纳入发布,本质是黑名单机制。此前 FOR ALL TABLES 只能全量发布,没法排除个别不需要复制的表(如临时表、日志表)。EXCEPT TABLE 让全库发布的配置更灵活,新增表自动纳入发布的同时又能排除例外,是逻辑复制易用性的一大改进。

关键词:EXCEPT TABLE,黑名单,PG19,publication,全表发布 | 来源:202603/20260314_05.md

Q:PG19 在逻辑复制可靠性上又改进了什么?

PG19 再次提高逻辑复制可靠性,重点是给 pg_sync_replication_slots() 增加 retry 重试逻辑,在同步逻辑复制槽时遇到瞬时失败可自动重试,减少因网络抖动导致的槽同步失败。同时持续完善同步逻辑复制槽的故障转移语义,让主备切换后逻辑订阅的接续更可靠。整体趋势是把同步逻辑复制槽打磨成生产可用的高可用组件。

关键词:PG19,逻辑复制,可靠性,retry,pg_sync_replication_slots | 来源:202512/20251215_02.md

Q:PG19 的 foreign server 独立订阅(CREATE SUBSCRIPTION … SERVER)是什么?

PG19 宣布支持在 CREATE SUBSCRIPTION 时用 SERVER 指定一个已定义的 foreign server,把订阅的连接信息与 foreign server 解耦。好处是连接参数(主机、端口、认证)集中在一个 foreign server 对象里管理,多个订阅可复用同一 server 定义,改连接信息只需改 server 一处。这让逻辑复制的连接管理更规范,也为跨服务器统一配置铺路。

关键词:foreign server,CREATE SUBSCRIPTION,SERVER,PG19,连接管理 | 来源:202603/20260314_02.md

Q:PostgreSQL 逻辑复制的基本架构和核心对象是什么?

逻辑复制基于『发布(publication)+ 订阅(subscription)+ 复制槽(replication slot)+ 逻辑解码(pgoutput)』四件套。发布端用 CREATE PUBLICATION 声明要复制的表,订阅端用 CREATE SUBSCRIPTION 指定连接和发布,内核通过逻辑解码把 WAL 里的变更还原成逻辑行(INSERT/UPDATE/DELETE),经 pgoutput 协议发送,订阅端 walsender/apply worker 回放。复制槽保证订阅端断线期间 WAL 不被回收,是逻辑复制的基石。

关键词:逻辑复制,publication,subscription,replication slot,pgoutput,逻辑解码 | 来源:202606/20260608_37.md

Q:WalMiner 是什么,和官方逻辑解码有什么区别?

WalMiner 是一个 WAL 日志解析 SQL 工具,能直接把 PostgreSQL 的 WAL 记录解析成对应的 SQL 语句(redo),并支持生成逆向 SQL(undo),用于误操作找回、审计和数据分析。它不要求 wal_level=logical,而是直接解析物理 WAL,对历史 WAL 也能回放;而官方逻辑解码(pgoutput)依赖 logical 级别 WAL 且只能从解码开始点向后。WalMiner 3.0 起更名并增强,4.0 预览版进一步优化了解析能力与精确性。

关键词:WalMiner,WAL,解析SQL,redo,undo,wal_level,误操作 | 来源:202211/20221102_01.md

Q:WalMiner 精确解析依赖什么条件,undo 靠什么实现?

WalMiner 要精确还原某行数据的修改,需要依赖 checkpoint 之后的 full page write(FPW)拿到整页数据作为基准,再叠加后续 WAL 记录重建行内容;如果解析起点早于 checkpoint、没有 FPW 则可能无法精确还原。undo(逆向 SQL)是根据 WAL 里记录的新旧值对,生成反向的 UPDATE/DELETE 把数据改回去。因此保留足够的 WAL 和合理的 checkpoint 间隔是 WalMiner 能精确找回数据的前提。

关键词:WalMiner,FPW,full page write,checkpoint,undo,WAL解析 | 来源:201902/20190211_01.md

Q:pg_logical_emit_message 函数是干什么用的?

pg_logical_emit_message(transactional, prefix, content) 可以向 WAL 写入自定义的逻辑解码消息,返回 pg_lsn。用途是传递控制消息、审计信息、DDL 等不落地到 table 的定制内容,直接写 WAL 且不依赖 pg_catalog 元数据结构。它是 pgstream 实现 DDL 复制、以及其他逻辑解码应用传递旁路消息的基础,比把消息塞进临时表再解码更简洁高效。

关键词:pg_logical_emit_message,WAL,逻辑解码,控制消息,pgstream | 来源:202104/20210406_05.md

Q:pglogical 2.x 相比内置逻辑复制有什么优势?

pglogical 是 2ndQuadrant 开发的成熟逻辑复制插件,早期内置逻辑复制(PG10 前没有)时它就是主流方案。pglogical 2.x 支持行过滤、列过滤、跨版本复制、级联订阅、冲突检测等内置逻辑复制缺失的高级能力,部署也比手工配置 publication/subscription 更灵活。随着 PG10+ 内置逻辑复制成熟,很多场景可用内置方案替代,但 pglogical 的过滤和冲突处理能力仍优于内置。

关键词:pglogical,逻辑复制,行过滤,冲突检测,级联订阅 | 来源:202203/20220304_01.md

Q:pgstream 如何解决 PG 逻辑复制不支持 DDL 的问题?

PG 原生逻辑复制只复制 DML,不支持 DDL。pgstream 是开源方案,通过事件触发器捕获 DDL,配合 pg_logical_emit_message 把 DDL 作为消息写入 WAL 并随逻辑复制流发送,订阅端接收后在回放事务前先执行对应 DDL,从而实现 DDL 的复制。pgstream v1.0 已把这条『DDL 复制』链路做通,弥补了 PG 逻辑复制长期被吐槽的短板。

关键词:pgstream,DDL复制,事件触发器,pg_logical_emit_message,逻辑复制 | 来源:202602/20260224_10.md

Q:同步逻辑复制槽(sync replication slot)是什么,为什么要用?

同步逻辑复制槽把主库的逻辑复制槽同步到物理 standby,配合 failover=true 和 hot_standby_feedback,实现主备切换后逻辑订阅『不断流』——standby 升级为主后,原订阅端能直接从新主继续消费,不丢数据。关键参数包括 failover=true(槽支持故障转移)、sync_replication_slots=on(主库把槽同步到备库)、synchronized_standby_slots(限制同步范围)。PG 还提供 pg_sync_replication_slots() 函数,PG19 给它加了 retry 逻辑提高可靠性。

关键词:同步逻辑复制槽,failover,sync_replication_slots,hot_standby_feedback,pg_sync_replication_slots | 来源:202512/20251223_01.md

Q:复制槽的关键 LSN 字段 restart_lsn/confirmed_flush_lsn/catalog_xmin 分别代表什么?

restart_lsn 是最早可能需要重新解码的 WAL 位置,主库保留 WAL 至少要保留到它,否则订阅端追不上就要重建。confirmed_flush_lsn 是订阅端已确认持久化的位置,用于衡量复制延迟和判断 standby 同步进度。catalog_xmin 是复制槽持有的最老 catalog 版本号,主库清理系统表死元组时不能早于它——如果订阅端长期不消费,catalog_xmin 长期不前进,会导致主库 pg_catalog 膨胀、vacuum 失效。

关键词:restart_lsn,confirmed_flush_lsn,catalog_xmin,复制槽,WAL,膨胀 | 来源:202104/20210417_01.md

Q:如何用内置逻辑复制做 minimal downtime 大版本升级?

方案是在旧版本实例上建发布(含目标表),新版本实例建订阅做初始数据同步,增量持续通过逻辑复制追赶;数据基本同步后,短暂停写、切应用连接、确认槽追上最后 LSN、再删订阅完成切换。相比直接 pg_upgrade 停机升级,逻辑复制方案可以把停机时间压缩到切换瞬间(秒级到分钟级),代价是需要先建逻辑复制链路、且对 DDL 敏感、要求有主键。

关键词:minimal downtime,大版本升级,逻辑复制,pg_upgrade,切换 | 来源:202312/20231214_01.md

Q:无主键表怎么做逻辑复制?

PG 逻辑复制默认按主键定位行,无主键表无法可靠更新/删除。早期可用隐藏列(如 oid 或 replica identity)作为行标识,PG 通过设置 REPLICA IDENTITY FULL(用整行做标识,代价高)或 USING INDEX 指定唯一索引来解决。最推荐的做法是给表加主键或至少一个非空唯一索引,否则 REPLICA IDENTITY FULL 会复制整行旧值、性能差,且无法精确表达部分列更新。

关键词:无主键,REPLICA IDENTITY,隐藏列,逻辑复制,oid | 来源:201908/20190804_04.md

Q:正确配置 Debezium 捕获 PG 逻辑增量要注意什么?

Debezium 的 PostgreSQL connector 基于逻辑解码,要求 wal_level=logical、安装 decoderbufs 或 wal2json 等输出插件,并给连接账号足够的复制权限。生产上要避免 Debezium 2.2~3.0 之间的已知 bug(如快照/类型映射问题),建议用修复后的版本。还要监控复制槽不消费导致的 WAL 膨胀,为每个捕获任务建独立槽,保证 max_wal_size 合理,否则 Debezium 停摆会把主库 WAL 撑爆。

关键词:Debezium,CDC,wal_level=logical,decoderbufs,wal2json,复制槽 | 来源:202011/20201127_02.md

Q:触发器在逻辑复制的订阅端会不会被执行?

默认会。逻辑复制回放变更时,订阅端表上的触发器会照常触发,这与物理流复制(从库不重放触发器)不同。这既有用(可以在订阅端做审计、转换)也有坑(可能重复触发业务逻辑)。如果不想触发,可以用 ALTER TABLE … DISABLE TRIGGER 或让触发器判断 session_replication_role,PG 在回放时把 session_replication_role 设为 replica,触发器可据此跳过。

关键词:触发器,逻辑复制,订阅端,session_replication_role,replica | 来源:202107/20210708_03.md

Q:逻辑复制如何防止双向复制打环(数据回环)?

通过 origin 机制防环:每个变更记录其来源 origin,逻辑解码输出时带上 origin,回放端用 origin=none 或跳过自身 origin 的变更,从而避免 A→B→A 的无限循环。在配置双向/多主逻辑复制时,订阅端要正确设置 origin,让从 A 复制到 B 的数据再被 B 发布时,A 能识别并忽略,否则会产生打环和重复应用。

关键词:origin,防打环,双向复制,逻辑复制,回环 | 来源:202107/20210719_03.md

Q:逻辑复制开始时还没结束的事务会不会丢失?

不会丢失,但要注意时序:逻辑复制的复制槽在创建时记录一个初始 LSN,从该 LSN 之后提交的事务才会被解码。如果在创建订阅/槽时某个事务尚未提交,它的变更尚未写入 WAL 对应位置,只有当它后续提交并落在解码范围才会被发送。核心是逻辑解码只输出『已提交』事务,未提交的事务不会出现在解码流里,因此不会丢已提交数据,但『快照一致性』和初始数据同步要分开处理。

关键词:逻辑复制,未提交事务,初始LSN,解码,快照 | 来源:201905/20190523_03.md

Q:逻辑解码的内存参数 logical_decoding_work_mem 和 spill 是什么?

logical_decoding_work_mem 是逻辑解码器在做事务内变更排序时使用的内存上限,默认 64MB。当单个事务的解码数据超过该上限时,会把部分变更 spill(溢出)到磁盘,避免内存暴涨,但会带来 IO 开销。PG16 引入 logical_decoding_mode=buffered/immediate 控制是否允许缓冲溢出,buffered 会尽量缓冲、超出才落盘,immediate 则即时输出不缓冲。控制好该参数和溢出行为对大批量变更复制的性能影响很大。

关键词:logical_decoding_work_mem,spill,逻辑解码,64MB,logical_decoding_mode | 来源:202301/20230103_01.md

1.9 分区表(44 条)

Q:Citus 的 Subquery/CTE Push-Pull Execution 是什么?为什么需要它?

Citus 是 PG 的 sharding 插件(被微软收购后仍开源)。处理复杂 SQL 时它用推拉模型做跨节点数据交换:push 是 shard -> coordinator,pull 是 coordinator -> worker。当子查询/CTE 无法与主查询在同一次 fragment 内联执行时(例如子查询带 LIMIT,无法作为 fragment 的一部分),Citus 会递归规划:先独立执行子查询,把结果通过 PG COPY 协议汇总到 coordinator 作为 intermediate results(中间结果存成 FILE),再把这些中间结果推回各 worker,worker 通过 read_intermediate_result 函数(Function Scan)读取 FILE 参与外层 JOIN,最后把结果拉回 coordinator。这套 push-pull 机制让 Citus 能支持更多复杂 SQL 和混用多种 executor。

关键词:Citus push-pull 中间结果 intermediate_result sharding COPY 递归规划 | 来源:201903/20190316_01.md

Q:DB 吐槽大会:PG 不支持在线 split/merge 分区,业务怎么应对?

PG 早期不支持在线 split/merge 分区,拆分/合并要靠 detach+attach 手动操作,期间有锁和迁移成本。业务上通常在低峰期做,或用 pg_pathman 等工具。PG17 起原生支持 ALTER TABLE … MERGE PARTITION / SPLIT PARTITION 命令,解决了这个痛点。

关键词:在线split merge 分区拆分 分区合并 detach attach PG17 | 来源:202109/20210902_11.md

Q:DB 吐槽大会:PG 分区表不能自动创建/扩展分区,业务上如何规避?

PG 分区表不会在数据超出分区范围时自动创建新分区,这是被吐槽的痛点。业务上通常需要提前创建足够的未来分区(如按月提前建好一年的分区),或用定时任务/事件触发器在数据到达前自动建分区。牺牲的是需要额外维护脚本和提前规划分区边界,未来产品迭代方向是支持 interval/自动扩展分区(类似 pg_pathman 的 interval 分区)。

关键词:自动创建分区 interval分区 分区扩展 分区边界 定时任务 | 来源:202109/20210908_02.md

Q:DB 吐槽大会:PG 分区表没有全局索引、不支持分区索引,带来什么问题?如何规避?

PG 分区表只有本地索引(每个分区各一棵),没有全局索引,也不支持把索引本身按分区组织(分区索引)。问题:本地索引无法跨分区保证唯一性/主键(非分区键字段无法做全局唯一约束),不带分区键的点查要探测多个分区。规避:业务层保证唯一性或加路由表;用 partial index + 多棵树模拟;未来方向是全局索引(leaf 页需 keyvalue -> tableoid + ctid 以知道记录在哪个子表)。

关键词:全局索引 本地索引 分区索引 唯一约束 分区键点查 | 来源:202109/20210903_08.md

Q:DuckDB 如何用 parquet 文件实现分区表/Delta Lake 能力?

DuckDB 支持 parquet 外部存储直接读写、pushdown/projection 下推、多目录/通配符,非常适合用 parquet 文件实现 Delta Lake。用多个 parquet 文件模拟分区,导出到分区文件目录(如按分区字段的路径组织),parquet_scan 可配置 HIVE_PARTITIONING 和 FILENAME 参数增加虚拟字段(分区字段名、文件路径)。分区条件可下推,收敛需要扫描的 parquet 文件——输入一级/二级分区条件时只扫对应文件,未含分区条件则扫全部。注意分区字段名不能与表字段重名。

关键词:DuckDB parquet 分区表 Delta Lake HIVE_PARTITIONING 下推 | 来源:202209/20220905_01.md

Q:PG hash 分区表如何扩容、缩容?hash 算法和 MODULUS/REMAINDER 有什么关系?

hash 分区通过 MODULUS(模数)和 REMAINDER(余数)定义分区。扩容/缩容的关键是对齐 MODULUS 与 REMAINDER:例如 1024 个分区合并到 512 个,或 512 扩到 1024,只要是倍数关系即可避免数据全部重新计算。hash 分区的 hash 算法是 hash_any/hashint4 等(代码在 partbounds.c/partition.h),注意:对值做 hashint4 取余后的结果与子分区 REMAINDER 没有直接关系,不能用简单取模来预测数据落在哪个分区——要用专门的 hash 分片计算函数。一个分区表甚至可以有不同的 MODULUS 子分区。

关键词:hash分区 扩容 缩容 MODULUS REMAINDER hash_any 分片计算 | 来源:202104/20210422_01.md

Q:PG 内置 sharding(基于 FDW)的演进到了什么程度?还缺什么?

PG 社区在基于 FDW 接口演进内置 sharding。目前 FDW 已能实现 DML 和 query,并支持下推 sort/filter/agg/join,也支持 FDW 分区表,已具备 sharding 雏形。但尚需改进:一是 FDW 分区串行运行,多分区查询性能不线性(而 plproxy/citus/pg-xc/greenplum 已支持异步并行);二是缺少 replica table(join with replica table)优化;三是尚缺 shard 语法与 GSM(Global Snapshot Manager 全局快照管理器)。PG11 已可通过 hint 让多分区并行,未来会支持更好。

关键词:内置sharding FDW 下推 异步并行 replica table GSM | 来源:201906/20190607_03.md

Q:PG12 之前操作单个分区会锁所有分区,PG12 之后锁粒度有什么变化?

PG12 之前对分区表执行 DML 时,会对所有分区加锁(从 pg_locks 可见大量 p0~p255 的 RowExclusiveLock),即使只写一个分区。PG12 优化为只对目标分区和主表加锁,操作单一分区时 LOCK 仅单个分区以及主分区。这大幅降低了锁竞争,是高并发下分区表写入性能提升的关键因素之一。

关键词:锁粒度 分区表 RowExclusiveLock 主表锁 单分区 | 来源:201903/20190331_01.md

Q:PG12 分区表性能提升百倍是怎么测出来的?关键数字是多少?

对比单表与 1024 个分区的分区表(各 1 亿记录)的查询和 upsert:单表性能基本持平(查询 116 万 qps 左右、upsert 33 万 qps 左右),但 1024 分区表在 PG11 下查询仅 1163 qps、upsert 2885 qps,PG12 beta1 提升到查询 545602 qps(469 倍)、upsert 246627 qps(85 倍)。根因是 PG12 之前优化器对分区表会为所有分区创建 RangeTblEntry 和 RelOptInfo 元数据,分区多时 overhead 巨大。

关键词:分区表 性能提升 469倍 85倍 1024分区 upsert 查询 | 来源:201905/20190521_01.md

Q:PG12 对分区表外键(PK 作为其他表的 FK)做了什么支持?

PG12 支持分区表的主键(PK)作为其他表的外键(FK),补齐了分区表在引用完整性上的能力缺口。

关键词:分区表 主键 外键 FK PK 引用完整性 PG12 | 来源:201904/20190405_04.md

Q:PG12 的 plan-time partition pruning 解决了原生分区表什么性能问题?带来多大提升?

PG12 之前,优化器无论 SQL 只操作单个分区还是多个分区,都会为所有分区创建 RangeTblEntry 与 RelOptInfo 结构并加锁,分区一多开销巨大。PG12 把这个过程推迟到处理完 query、识别出 restriction quals 并做完 partition pruning 之后:对 plan time 就能确定不会访问的分区,直接不创建其数据结构、不打开其 relation。带来的收益是内存降低、plan 更快、TPS 提升——256 个分区的写入测试从 PG11 的 11348 tps 涨到 PG12 的 267447 tps,提升约 23.57 倍;1024 分区下查询提升 469 倍、upsert 提升 85 倍。实际可支持的分区数上限也从约 100 个提升到几千个。

关键词:plan-time partition pruning RangeTblEntry RelOptInfo 分区裁剪 PG12 锁粒度 | 来源:201903/20190331_01.md

Q:PG12 里 psql 用什么快捷命令列出分区表?

PG12 起 psql 新增快捷命令 \dP 用来列出分区表(此前没有专门的快捷命令)。

关键词:psql \dP 分区表 快捷命令 | 来源:201904/20190409_01.md

Q:PG13 pgbench 的 tpcb 内置模型对分区表做了什么支持?

PG13 的 pgbench 内置 tpcb 模型支持把 pgbench_account 表建成分区表,可通过选项指定 range 或 hash 分区,省去了手工创建分区表的繁琐步骤,方便快速测试分区带来的开销(如 hash 分区对简单 select 的开销)。

关键词:pgbench tpcb 分区表 range hash PG13 | 来源:201909/20190901_02.md

Q:PG14 在分区裁剪和 UPDATE/DELETE 上又做了哪些优化?

PG14 有两个相关优化:一是 ExecInitModifyTable 分区裁剪精细化,不再 touch 不必要的分区;二是 Rework planning and execution of UPDATE and DELETE——减少传导不必要的列 value、避免为每个分区生成 subplan,降低分区表 DML 的执行开销。

关键词:ExecInitModifyTable 分区裁剪 UPDATE DELETE subplan PG14 | 来源:202104/20210407_01.md

Q:PG15 postgres_fdw 的异步增强对基于 FDW 的 sharding 有什么意义?

PG15 postgres_fdw 支持更多异步操作,增强基于 FDW 的 sharding 能力:包括 DML 异步写入、分区表、union all、union 等。此前 PG14 已引入 FDW 异步执行接口和 postgres_fdw 异步 append,这次进一步扩展到更多操作,让基于 FDW 的 sharding 写性能和并行能力更好。

关键词:postgres_fdw 异步 DML异步 append sharding PG15 | 来源:202204/20220408_04.md

Q:PG15 的「未裁剪分区 bitmapset」优化解决了什么?

PG15 在 RelOptInfo 中记录未裁剪分区的 Bitmapset(Track a Bitmapset of non-pruned partitions),避免重复计算裁剪结果,降低 plan time,进一步提升分区表的规划性能。

关键词:Bitmapset 未裁剪分区 RelOptInfo plan time PG15 | 来源:202108/20210803_01.md

Q:PG16 的「分区缓存」优化解决什么问题?适用什么场景?

PG16 的分区查找优化(分区缓存)针对同一会话中连续写入同一分区的场景:缓存上次命中的分区,减少每次二分法查找分区的开销,提升分区表批量写入性能。不适用的场景是写入在分区之间频繁跳转的情况。

关键词:分区缓存 二分法查找 批量写入 PG16 同一分区 | 来源:202208/20220808_04.md

Q:PG17 的 ALTER TABLE … MERGE|SPLIT PARTITION 是什么?

PG17 实现了 ALTER TABLE … MERGE PARTITION 和 SPLIT PARTITION 命令,原生支持分区的合并与拆分,结束了此前只能靠 detach+attach 手工操作、不支持在线 split/merge 的历史。

关键词:MERGE PARTITION SPLIT PARTITION PG17 分区合并 分区拆分 | 来源:202404/20240407_02.md

Q:PG17 还做了哪些分区表相关改进?

PG17 的分区表改进包括:支持修改分区表的 access method(如切换存储引擎/表访问方法);减少 partitionwise join 的内存消耗;以及实现 ALTER TABLE … MERGE|SPLIT PARTITION 命令。

关键词:access method partitionwise join 内存 PG17 分区表 | 来源:202403/20240326_04.md

Q:PG18 为什么移除了对分区表 unlogged 的支持?作者怎么看?

PG18 的 patch 移除分区表 unlogged 支持:原因是此前分区表被创建为 unlogged 时,分区并没有继承该属性,导致分区表实质上仍是 logged 的。社区选择直接不支持分区表 unlogged(设置时报错),作者吐槽这是「不解决问题、解决提问题的人」——分区表不配 unlogged,如果是国产数据库这么干估计要被骂死。

关键词:unlogged 分区表 PG18 移除 logged relkind | 来源:202410/20241008_01.md

Q:PG19 的 COPY 分区表 TO 相比之前有什么改进?

PG19 支持直接 COPY 分区表 TO 导出。此前分区表只能用 COPY (SELECT … FROM 分区表) TO 实现,多了一次 query 处理,性能更差。注意 RLS(行安全策略)在 copy to 中依旧有效,看不到的数据无法导出。

关键词:COPY 分区表 TO RLS PG19 导出 | 来源:202510/20251021_12.md

Q:PGcat 中间件相比 pgbouncer/pgpool-II/citus 的定位是什么?

pgbouncer 效率高但是单进程;pgpool-II 支持读写分离但本身效率一般;citus 支持 sharding 但需装插件、对非微软云的 RDS 不友好。pgcat 是 Rust 写的 PG 中间件,同时支持 sharding+连接池+读写分离+负载均衡+故障转移:应用层(OSI 7)负载均衡,理解 wire protocol,支持 RR/随机/最少活跃连接策略,可把 SELECT 路由到副本、其他 query 路由到主库;维护实时健康主机列表,副本健康检查失败自动切负载(不对 primary 做故障转移);支持事务/会话模式连接池;用原生 PG 解析器提取分片键做 sharding 路由,跨分片查询在内存组装结果。

关键词:pgcat 连接池 读写分离 sharding 负载均衡 Rust | 来源:202211/20221116_01.md

Q:ShardingSphere 的三种模式(Sharding-JDBC/Proxy/Sidecar)如何选?适合什么业务?

ShardingSphere 是与 MySQL sharding 中间件类似的 PG 分库分表中间件,适合分片彻底、数据库逻辑极其简单的业务。三种模式:Sharding-JDBC(任意数据库、仅 Java、损耗低、无中心化、连接消耗高)、Sharding-Proxy(MySQL/PG、任意语言、损耗略高、有静态入口)、Sharding-Sidecar(MySQL/PG、任意语言、损耗低、无中心化、连接消耗高)。使用注意:自定义函数内部若有写操作会路由到只读库导致报错;sql.show 建议关闭否则打印大量日志影响性能。

关键词:ShardingSphere Sharding-JDBC Sharding-Proxy Sharding-Sidecar 分库分表 | 来源:202002/20200209_01.md

Q:Yugabyte 在 SaaS 多租户场景如何用 RLS + GEO 分区实现隔离与就近存储?

Yugabyte 是兼容 PG 的分布式全球数据库,支持 multi-region,可用 geo tablespace 实现数据就近存储(如 A 用户数据放欧洲表空间)。SaaS 多租户隔离分两种:逻辑隔离用 RLS(行安全策略,也叫 VPD),物理隔离用不同表。通常按数据量、用户等级选择——VIP 客户常用物理隔离。Yugabyte 演示了 pgbench + RLS + geo tablespace + 分区表组合,做到新租户不增加额外资源(共享 database/连接池/schema)又通过 RLS 保证安全隔离。

关键词:Yugabyte RLS VPD geo分区 多租户 SaaS 就近存储 | 来源:202110/20211008_02.md

Q:pg_dump 对分区表和继承表做了什么过滤支持?

PG16 的 pg_dump 支持对分区表和继承表的条件过滤项,可以在导出时按条件过滤子表(分区/继承子表),便于选择性备份。

关键词:pg_dump 分区表 继承表 条件过滤 PG16 | 来源:202303/20230315_02.md

Q:pg_pathman 分区表如何无损转换为 PG12 原生分区表?

PG12 原生分区性能已与 pg_pathman 持平,因此可以把 pg_pathman 分区表转换为原生分区表,且无需迁移数据,只改继承关系:pg_pathman 的 hash 分区转原生 list 分区(因其底层用 get_hash_part_idx(hashint4(id), n) 定义,对应原生 list),range 分区直接转换。做法是 NO INHERIT 解除继承、再 attach 到原生分区表。注意作为 list 分区的表达式必须是 immutable 函数,需修改函数属性。转换后原生写入速度与 pg_pathman 一样。

关键词:pg_pathman 原生分区 转换 attach no inherit list分区 immutable | 来源:201911/20191113_01.md

Q:pg_rewrite 插件如何在线把普通表转换为分区表?有什么限制?

pg_rewrite(cybertec 开源)解决从非分区表变更为分区表的长时间锁问题:用 logical replication 从非分区表增量复制数据到新的分区表,同步完成后只需短暂的排他锁切换表名(有参数控制锁超时,如 100ms 重试 3 次)。限制:非分区表必须有 PK;分区表的 check/not null/FK/default 等约束要与非分区表保持一致;serial 字段要处理妥当。

关键词:pg_rewrite 在线转分区表 logical replication 排他锁 表名切换 | 来源:202112/20211209_01.md

Q:pgbench 的 client_id 变量有什么用?能解决什么问题?

client_id 是 pgbench 中唯一标识客户端会话的变量(从 0 开始)。用它可以模拟数据隔离的更新操作,避免多个连接更新到相同记录导致的锁冲突;或用 mod 让每个 client 更新不同的 ID,确保不同会话行级锁互不重叠。实测不用 client_id 时锁冲突严重,qps 从 25 万降到 18 万。client_id 也期望将来能作为动态表名后缀,实现不同线程操作不同表(类似分区表的压测隔离),但 pgbench 暂未支持 identify 字段中放变量。

关键词:pgbench client_id 锁冲突 压测 数据隔离 | 来源:201908/20190828_02.md

Q:pgdog 相比 pgcat/pgbouncer 的 sharding 能力有什么特点?

pgdog 是支持「分片/负载均衡/连接池」于一体的 PG 代理:理解 PG wire protocol,代理多个副本和主库并按 RR/随机/最少活跃连接均衡,能把 SELECT 发副本、其他 query 发主库;维护实时健康主机列表,副本健康检查失败自动切负载(对 primary 不做切换只重试);支持事务/会话模式连接池(事务模式允许数十万客户端只用几个后端连接);sharding 用原生 PG 解析器理解 query、提取分片键确定路由,跨分片查询在内存组装转换结果。相比 pgbouncer(单进程)、pgpool-II(效率一般)、citus(需插件、云服务不友好),pgdog 无需插件且功能更全。

关键词:pgdog 分片 负载均衡 连接池 wire protocol 路由 | 来源:202509/20250905_08.md

Q:plproxy 是什么?它的定位和特点是什么?

plproxy 是基于函数接口的 PG sharding 插件,用于分库分表,非常灵活、性能损耗很低,早在 200x 年就被 Skype 广泛使用。使用它需要写存储过程接口,应用侵入最大,但性能最好。plproxy 2.9 版本支持 PG 11 和 12。

关键词:plproxy sharding 分库分表 函数接口 Skype | 来源:201909/20190928_02.md

Q:为什么全文检索 bm25 得分排序不建议使用分区表?

pg_textsearch(timescale)把计算 BM25 得分所需信息存在索引里,但对分区表每个分区维护自己的(分区本地)统计信息,没有全局索引,导致跨分区按 bm25 得分排序无意义:每个分区的 IDF 值依赖分区本地的文档总数和词频统计,相同查询词在不同分区产生不同得分,跨分区得分不可直接比较。单分区查询得分准确,跨分区查询则不可比。

关键词:bm25 分区表 全局索引 IDF 分区本地统计 pg_textsearch | 来源:202601/20260116_02.md

Q:为什么分区表分区过多会导致性能下降?用分区表的正确动机是什么?

用分区表的根本动机是规避「单表太大」的通用危害:1) 垃圾回收/冻结是单表单进程粒度,表大导致回收慢、膨胀、xid 可能耗尽;2) 单表逻辑备份/恢复无法并行、耗时变长;3) 单表只能放一个表空间/文件系统,无法用多块盘并行吞吐;4) 逻辑复制初始全量同步无法并行、中断后要重来;5) 表可能超出寻址边界(CTID 4 字节 blockid,8K block 最大 32TB);6) 按时间清理历史数据时没有分区只能 delete,产生大量 WAL 和膨胀。但分区过多本身也有害:relcache 内存暴增、执行计划变慢、可能 rte 溢出、全表查询要大量 open/close fd。所以分区要在「规避单表危害」和「分区过多开销」之间权衡。

关键词:分区过多 性能下降 autovacuum freeze 逻辑备份 单表危害 relcache | 来源:202112/20211224_01.md

Q:为什么应用端直接计算 hash 分区能绕过 catalog 开销提速 20 倍?

PG hash 分区用确定性哈希把 tuple 分布到各分区。查询父表时 PG 必须做 catalog 查找才能把 query 路由到正确分区,高吞吐 OLTP(尤其多级分区)下这是明显开销——多级分区要遍历更深的 catalog 结构。有人用 Ruby 库嫁接 PG 内置哈希分区计算代码(hashfn.c/hashfunc.c),在应用端直接算出目标分区、直接访问分区表,绕过 catalog 查找,分区查找性能提升 20 倍。前提是应用能自主识别确定分区。

关键词:hash分区 catalog开销 直接访问分区 提速20倍 hashfn 应用端路由 | 来源:202508/20250825_06.md

Q:为什么要把原生分区表转回普通表?怎么做?

业务预估过多时,开发可能把所有表都建成了分区表,实际并不需要。分区表的代价:高并发下引入优化器损耗;分区多会让会话 relcache 内存增加,长连接+高并发+未用 huge page 可能 OOM。转换方法是解除继承关系、把分区数据并入新普通表(或切换表名)。需注意 serial 字段的 sequence 与表挂钩问题:删除旧表会导致序列被删、新表默认值被清,要先解除 sequence 的 owner 依赖。

关键词:分区表转普通表 relcache OOM serial sequence 依赖 | 来源:202002/20200225_01.md

Q:为什么要经常手工对分区表的主表执行 ANALYZE?

分区表是「入口分区 -> 分支分区 -> 叶子分区」的分层结构,数据只存在叶子分区,autovacuum 触发垃圾回收和自动统计信息收集时只收集叶子分区的统计信息,不修改非叶子(入口/分支)分区的统计信息。但实际使用大量查询走的是入口(主表),如果主表统计信息不及时更新,会导致很差的执行计划。所以需要经常手工对主表执行 ANALYZE 更新统计信息。

关键词:ANALYZE 主表 统计信息 叶子分区 autovacuum 执行计划 | 来源:202203/20220329_01.md

Q:什么是「非对称分区表智能 JOIN」?它想解决什么?

某些场景下需要把分区数据 append 后再 JOIN,必须改写 SQL 才能做到基于每个分区 JOIN 后合并结果。非对称分区表智能 JOIN(PG15 期待的特性)旨在自动优化这种 SQL 改写:当两个分区表 JOIN 字段类型一致、分区在 JOIN 字段上、分区类型一致(枚举/LIST/范围/HASH)、分区个数一致时,优化器自动选择 partitionwise join,让子分区各自 JOIN 子分区,类似 MPP 的 co-located join。

关键词:非对称分区表 智能JOIN partitionwise join append MPP | 来源:202106/20210615_04.md

Q:分区表 ORDER BY 分区键时,为什么 PG12 可以避免 merge sort?

当分区表按分区字段 ORDER BY 且各分区本身有序时,各分区返回的结果天然有序,直接 append 拼接即可,不需要 merge append(merge sort)的额外归并排序开销。PG12 支持分区表 order by 分区键时使用 append(ordered scan partition),PG15 进一步把这个能力扩展到更多 order by key 场景——例如 list 分区里一个分区含多个 value 时,只要保证分区内有序也能走 append scan,避免 merge append 的 mergesort 计算。

关键词:ordered scan partition append merge append merge sort 分区键排序 | 来源:201904/20190409_03.md

Q:分区表全局索引与分布式数据库全局二级索引分别解决什么问题?核心取舍是什么?

分区表全局索引:单库分区表中,本地索引无法直接跨分区保证唯一性或点查效率——如果订单表按 created_at 分区,而业务按 order_no/user_id 查一条记录,本地索引要探测多个分区。全局索引维护一套跨分区索引键空间,用非分区键直接定位行,解决三类问题:跨分区点查(非分区键查少量记录不扫多分区)、跨分区唯一性(order_no/email/id_card 整表唯一)、访问路径与生命周期解耦。分布式数据库全局二级索引是同一类问题的分布式版本,只是「分区」变成可切分/复制/迁移的 range。两者实现不同但取舍相同:把读路径的多分区扫描,换成写路径/事务路径/维护路径的全局成本——每次写入要写全局索引,分区 DROP/DETACH/TRUNCATE 要处理对应条目,唯一性检查跨分区延迟扩大,全局索引本身可能成为热点(单调递增键、低基数键、集中写入键)。

关键词:全局索引 全局二级索引 本地索引 跨分区唯一 点查 分布式 写放大 | 来源:202606/20260601_20.md

Q:分区表跨分区排序 + limit 怎么用 merge append 减少扫描量?

分区表跨分区按非分区字段排序再 limit 输出时,用归并排序(merge append sort)减少扫描量:各分区分别有序返回,再做归并。多个分段 SQL 按某字段排序 limit 分页返回,也可用 union all + merge append sort 优化。核心是让每个分段(分区)内返回有序结果,MergeAppend 归并取 top-N,避免全量排序。

关键词:merge append sort 跨分区排序 limit 归并排序 减少扫描 | 来源:202208/20220823_01.md

Q:分区过多会导致什么错误?为什么分区不是越多越好?

分区过多(超过 65535 个)会导致 range table entry 溢出报错 too many range table entries。分区过多的通用问题:高并发时需要更多内存存 relcache、执行计划变慢、内存暴增;可能溢出;全表查询性能变差(大量 open/close fd)。作者建议不要为几万条记录就建一个分区,几亿记录也没必要分区;应只在遇到瓶颈时考虑分区,例如垃圾回收、freeze、创建索引、表级逻辑备份。经验值:频繁更新的表每分区 1 亿以内较好,插入量大更新少查询多的表可考虑 10 亿单分区。

关键词:too many range table entries 分区过多 relcache 65535 溢出 | 来源:202003/20200314_01.md

Q:如何把 PolarDB PostgreSQL 的大表平滑转换为分区表?

思路:先建好目标分区表(如按月分区),用迁移工具做全量+增量同步(如 NineData 社区版,基于逻辑复制建 replication slot 同步),到业务低谷时切换表名,有约束关系的再迁移约束,把对业务影响降到最低。需要 wal_level=logical 支持增量,pg_hba 允许迁移工具连接(含流复制协议)。

关键词:大表转分区表 PolarDB 逻辑复制 增量同步 表名切换 | 来源:202503/20250306_02.md

Q:如何根据分区键的值计算它落在哪个 hash 分区?

PG 的 hash 分区分片计算代码在 partbounds.c(partition.h 定义相关结构),通过 hash 函数对分区键值做哈希再映射到分片。可以通过 SQL 接口函数把原始值转换为 hash 分片 ID(从 0 开始计数),int4/text/uuid 等类型分别实现。验证方法是:用该函数算出的分片与 EXPLAIN 执行计划中显示的目标分区对照,返回 0 条差异即说明正确。注意 hashint4 取余结果与 REMAINDER 无直接关系,不能直接拿 mod 结果当分区号。

关键词:hash分片ID 计算 partbounds.c 分区键 hash函数 | 来源:202109/20210908_01.md

Q:如何用 detach/attach 对分区表做拆分和合并?PG 支持什么样的分区布局?

PG 支持通过 ALTER TABLE … DETACH PARTITION 解绑分区、ATTACH PARTITION 绑定分区来实现拆分与合并。拆分例子(hash):先 detach 掉某个分区,再创建一个二级分区表,把数据迁移进去,最后把二级分区表 attach 回原分区上,这样原来一个分区就被一个二级分区表替代。PG 支持非常灵活的分区布局:支持任意层级、每个分区深度可不一致(非平衡分区表),甚至可以把某个分区改成别的分区方法(如 hash 改 list)。这特别适合数据分布不均的场景——例如某 id 落在同一分区但数据量巨大,可对它再做二级分区。

关键词:detach attach 拆分分区 合并分区 非平衡分区表 二级分区 | 来源:201906/20190621_02.md

Q:推荐系统「已读过滤」导致大量 CPU/IO 浪费时,用 hash 分片+partial index 怎么优化?

场景:10 亿 user、10 亿 video,按 weight 排序选 vids 并过滤已读(用 HLL 记录 vid hash 判断已读)。已读列表越大,按 weight 倒排查出的记录大量是已读的,浪费大量时间在 HLL 运算上。优化思路:把表按随机索引分区(如 20 个分区),每次只查询一个分区,查询范围缩小到 1/20,该分区内的已读量也变成 1/20,offset 量降低 20 倍,性能明显提升(实测 147.7ms 降到 12.1ms)。代价是与业务略有偏差(只查到部分记录),但从整体拉平看,用户请求次数足够多时随机能覆盖所有记录。

关键词:已读过滤 HLL hash分片 partial index 推荐系统 offset 降过滤量 | 来源:202006/20200610_02.md

1.10 监控 / 诊断(66 条)

Q:Linux 下如何用 gcore/gdb/pstack/strace 排查 PG 进程 hang 的问题?

PG 进程 hang 无法用 pg_terminate_backend 杀掉时,用这些工具抓现场:pstack/gstack 是脚本(最终调用 gdb),用 gdb -p –batch -ex “thread apply all bt” 打印所有线程堆栈,可看到进程卡在哪个函数(如 epoll_pwait → WaitEventSetWait → secure_read → pq_getbyte → PostgresMain,说明在等客户端消息)。gcore 生成 core dump(core.)用于离线分析。strace -CvTt -p 追踪系统调用和信号,看进程在做什么 syscall、耗时多少(如 lseek/brk/sendto/recvfrom 各占多少时间)。lsof 查打开的文件,删除文件后空间未释放时可 lsof 找谁还打开着该文件。blktrace/blkparse/btt 用于块设备 IO 延迟分析(见下一问)。这些是 PG 进程 hang、crash 排查的必备工具。

关键词:gdb,gcore,pstack,strace,lsof,进程hang | 来源:202311/20231129_01.md

Q:PG 的 wait_event 体系分哪 9 大类?每类大概代表什么?

PG 9.6 起引入 wait_event 体系,PG 14+ 细分了 IO 类型。9 大类:Activity(空闲主循环)、BufferPin(等 buffer 排他锁)、Client(等客户端收发,如 ClientRead/ClientWrite)、IO(等数据文件/WAL/control file,如 DataFileRead/WALWrite/ControlFileSync)、IPC(等子进程/并行 worker)、Lock(重量级锁,如 transactionid/tuple)、LWLock(共享内存轻量锁,如 buffer_mapping/lock_manager/WALWriteLock)、Timeout(故意 sleep,如 PgSleep)、Extension(扩展自定义)。第一性原理:wait_event 告诉你这一刻这个 backend 为什么不在跑,是定位瓶颈的最强武器。

关键词:wait_event,wait_event_type,9大类,等待事件,IO,LWLock | 来源:202607/20260709_01.md

Q:PG 等待事件统计为什么需要’时间’而不只是’次数’?采样和精确统计各有什么利弊?

pg_stat_activity 只有当前等待状态,pg_wait_sampling 只记采样次数不记耗时。但 Oracle 文档明确指出:应关注等待时间最多的事件,而不是次数最多的事件——有的事件次数多但每次很短(如 buffer_content lock),有的次数少但单次很长(如慢 IO、锁),只有等待时间才能判断影响和 justify 处理方案。采样(Oracle ASH 式)的缺点:1)不精确,会漏掉间歇性短等待;2)过采样耗资源(10ms/1ms 采样导致数据量大、后台采样进程阻止 CPU 空闲);3)无法判断是一次长等待还是多次短等待。精确统计(记录每次 wait 的 elapsed time)的顾虑是 gettimeofday 开销,Tom Lane 指出在 hot code path(如 lwlock.c)里调用计时不可接受,且 pgstat_report_wait_start/end 需保证无副作用。折中:可能以插件形式存在,用户自由开关。

关键词:等待事件,采样,gettimeofday,ASH,wait time,性能损耗 | 来源:202001/20200101_01.md

Q:PG12 对 incomplete startup packet 日志做了什么改进?哪些日志仍然会打印?

监控探测、端口扫描、HA 工具等连接 5432 端口但不发送 startup 报文,PG12 以前会为每次这样的探测打印 incomplete startup packet 错误日志,导致日志文件暴涨和多余 IO。PG12 的 patch 342cb650e 约定:连接被关闭且未发送任何数据时不记录任何日志(例如监控工具打开连接后立即关闭)。但以下仍会打印:1)客户端发送了数据但报文非法 → invalid length of startup packet;2)服务端读包时客户端已丢失(未正常握手关闭)→ could not receive data from client: Connection reset by peer(这个日志不会消失,因为对应 pq_recvbuf 读包时发现对端没了)。复现:for i in {1..100}; do nc -zv localhost 5432; done。正常存活探测建议用 pg_isready 命令。

关键词:incomplete startup packet,日志,PG12,Connection reset by peer,监控探测 | 来源:201912/20191206_01.md

Q:PG14 新增 pg_stat_replication_slots 视图监控什么?关键字段含义是什么?

PG14 commit 98681675 新增 pg_stat_replication_slots,跟踪每个 logical replication slot 的 decode 统计,特别是超过 logical_decoding_work_mem 内存导致的 ReorderBuffer 落盘(spill)操作。视图每个 logical slot 一行,字段:name(集群唯一 slot 标识)、spill_txns(因 logical decoding 内存超限而落盘的事务数,含 top-level 和子事务)、spill_count(落盘次数,事务可能重复落盘,每次触发都累加)、spill_bytes(落盘的已解码事务数据量)、stats_reset(上次重置时间)。配套函数 pg_stat_reset_replication_slot(text),参数为 slot 名或 NULL(NULL 表示重置所有 slot),默认仅 superuser 可执行。如果 spill 增长频繁,说明 logical_decoding_work_mem 配得不够,需要调大。

关键词:pg_stat_replication_slots,logical slot,spill,logical_decoding_work_mem,PG14 | 来源:202010/20201010_01.md

Q:PG14 的 PQtrace 相比之前有哪些改进?如何用协议层日志排查慢的问题?

PQtrace 是 libpq 记录客户端-服务端协议交互的函数。PG13 及以前输出无时间戳、message identifier/server 长度/content 分行显示、难读难分析。PG14 改进四点:1)加时间戳;2)方向代码直观化 F(frontend)/B(backend);3)输出正式 message 名而非标识符(如 Query、CommandComplete、ReadyForQuery 代替 Q/C/Z);4)有意义的协议消息一行输出。新增 PQsetTraceFlags 控制是否输出时间戳。价值:通过日志时间戳差可判断应用突然变慢时是服务端还是客户端处理慢;不输出时间戳时可用于回归测试对比。典型输出形如:2021-06-30 09:21:56.366741 F 133 Query “…"。未来方向:限制日志文件大小、用环境变量/连接参数控制日志目录。

关键词:PQtrace,PQsetTraceFlags,libpq,协议层,协议消息,时间戳 | 来源:202107/20210719_04.md

Q:PG14 的 pg_stat_replication_slots 视图监控什么?

PG14 新增 pg_stat_replication_slots 视图,每个逻辑复制槽一行,统计逻辑解码 ReorderBuffer 因超过 logical_decoding_work_mem 而落盘的事务数(spill_txns)、落盘次数(spill_count)、落盘字节数(spill_bytes)。若 spill 增长频繁,说明逻辑解码内存不足,应调大 logical_decoding_work_mem。

关键词:pg_stat_replication_slots,spill,logical_decoding_work_mem,PG14 | 来源:202010/20201010_01.md

Q:PG14 给 pg_stat_database 新增了哪些 session 相关计数器?各代表什么?

PG14 commit 960869da 为 SaaS 场景(serverless、按库计费)新增数据库维度 session 统计:session_time(该库所有会话总耗时,仅在状态切换时更新,长期 idle 不计入);active_time(执行 SQL 的时间,对应 active 和 fastpath function call 状态);idle_in_transaction_time(事务内空闲时间,对应 idle in transaction 及 aborted 状态);sessions(建立过的会话总数);sessions_abandoned(因客户端连接丢失而终止的会话数);sessions_fatal(因 fatal 错误终止的会话数);sessions_killed(被管理员操作终止的会话数)。这些指标让云厂商能按 database 维度统计每个租户消耗的 CPU/会话资源,用于计费和容量评估。

关键词:pg_stat_database,session_time,active_time,sessions,PG14,SaaS | 来源:202101/20210118_01.md

Q:Planner 执行计划失准的 5 大根因是什么?各有什么对策?

1)数据倾斜:rows 估算严重偏高 → CREATE STATISTICS ON a,b FROM t 扩展统计;2)bulk load 后没 ANALYZE:全走 Seq Scan → COPY 后立即 ANALYZE;3)长时间小批量写入:统计陈旧 → 调小 autovacuum_analyze_scale_factor=0.025;4)关联列无统计:rows 估算为乘积 → CREATE STATISTICS 多维统计;5)数据分布随时间漂移:老统计不反映新常态 → 周期性 ANALYZE 或 cron。另外 random_page_cost=4(默认)会让 planner 认为随机 IO 很贵倾向顺序扫描,SSD 盘要调到 1.1(云盘 1.5、NVMe 1.0);plan_cache_mode=auto 时前 5 次选 plan 后固化(plan sniping),可用 force_custom_plan 对比。自检:select schemaname, relname, last_analyze, n_mod_since_analyze from pg_stat_user_tables order by n_mod_since_analyze desc。

关键词:Planner失准,ANALYZE,CREATE STATISTICS,random_page_cost,plan_cache_mode | 来源:202607/20260709_01.md

Q:PoWA4 是什么?它依赖哪些插件,各自贡献什么能力?

PoWA(PostgreSQL Workload Analyzer)是 PG9.4+ 的性能分析工具,通过插件采集统计并做分析诊断,带 WEB 展示,支持远程采集和把数据存到其他 PG 库。依赖插件:pg_stat_statements(TOP SQL 统计)、pg_qualstats(SQL 真实过滤性/选择性统计,用于判断是否需要索引)、pg_stat_kcache(buffer/OS cache/disk 命中统计,区分 page cache 与真实磁盘 IO)、pg_wait_sampling(等待事件采样,说明问题根源)、pg_track_settings(跟踪数据库配置变更)、HypoPG(虚拟索引,用于索引推荐)。它能展示 QPS、缓存命中率、SQL 洞察、等待时间统计、索引推荐等,是历史回溯和 TOP SQL 分析较强的方案。

关键词:PoWA,pg_qualstats,pg_stat_kcache,HypoPG,pg_track_settings,监控工具 | 来源:201905/20190520_01.md

Q:PostgreSQL 的 pgcenter 是什么?

pgcenter 是采样、统计、性能诊断、profile 的 CLI 小工具,通过 SQL 接口定期采样 PG 的各类统计视图,提供类似 top 的实时面板和 profile 功能,方便在命令行快速观察数据库负载、等待、IO、SQL 等指标,无需部署重型监控。

关键词:pgcenter,采样,性能诊断,profile,CLI | 来源:202603/20260327_02.md

Q:PostgreSQL 的等待事件采样(ASH 理念)为什么重要?

pg_stat_activity 只显示会话当前等待状态,无法回答某事务/某 SQL 有多少种等待、各等了多少次多久。等待事件统计(类似 Oracle ASH/performance insight)记录每次等待的次数和耗时,能精准定位瓶颈。纯采样会漏掉短暂等待,纯计数没有时间无法判断影响,所以需次数+时间结合。性能损耗(gettimeofday)是引入完整计时的主要顾虑。

关键词:等待事件,ASH,performance insight,采样,gettimeofday | 来源:202001/20200101_01.md

Q:SlowQL 是什么,解决什么问题?

SlowQL 是离线 SQL 静态分析器,不需要连接数据库,针对 SQL 源文件、迁移脚本、dbt/Jinja 模板和应用代码里的 SQL 字符串做分析,内置 279 条规则覆盖 14 种 SQL 方言,六大维度(安全、性能、可靠性、质量、成本、合规)。价值在于把 SQL 风险拦截在代码提交前(治理左移),支持跨文件理解迁移、基线增量治理、CI 门禁和 SARIF 集成。

关键词:SlowQL,SQL审核,静态分析,治理左移,CI | 来源:202603/20260327_02.md

Q:SlowQL 这类 SQL 静态分析工具解决什么问题?它的治理落地路径是什么?

SlowQL 是离线 SQL 静态分析器,不需要连接数据库,针对 SQL 源文件、迁移脚本、dbt/Jinja 模板、应用代码里的 SQL 字符串做分析,内置 279 条规则覆盖 14 种方言,把数据库治理从’人肉经验’升级为’工程系统’——在代码提交前把高风险 SQL 拦下来(SQL 是源代码资产,应像 Java/Go 一样做静态检查、CI 门禁、基线管理)。落地路径:1)本地先跑(pipx install slowql; slowql queries.sql);2)增量治理(–update-baseline 建基线,–git-diff 只分析变更文件,不碰存量烂账);3)门禁分层(–fail-on critical|high|medium,核心库 fail-on high);4)规范写进 slowql.yaml 配置;5)例外显式记录(slowql-disable-line 注释抑制);6)接 GitHub(GitHub Action 或 SARIF 给 code scanning)。适用前提:SQL 在源码里可治理,且问题属于源码层可判定(危险模式/反模式/结构引用错误),运行时数据分布/锁竞争等问题仍需执行计划分析和监控。

关键词:SlowQL,SQL静态分析,CI门禁,基线管理,SARIF,SQL审核 | 来源:202603/20260327_02.md

Q:auto_explain 如何配置?为什么大流量场景必须抽样?

auto_explain 是 PG 自带模块,把超过阈值的 SQL 执行计划自动落盘。配置:shared_preload_libraries=‘auto_explain’,auto_explain.log_min_duration=‘3s’、log_analyze=on、log_buffers=on、log_format=‘json’(PG10+ 便于 ELK 解析)、log_timing=on、log_verbose=on、sample_rate=1。必须加载到 shared_preload_libraries 才能跨 session 全局生效。大流量(>5000 QPS)必须抽样:sample_rate=0.01~0.1,因为 log_analyze=on 会让每次捕获都真正 EXPLAIN ANALYZE 一次,全量会让 CPU 翻倍。注意 log_min_duration=3s + sample_rate=0.01 有盲区:平时 0.5s、事故时偶发 4s 的致命 SQL 可能一条都采不到,建议 log_min_duration=1s + sample_rate=0.05 起跳,配合 pg_stat_statements 快照双轨。

关键词:auto_explain,log_min_duration,sample_rate,log_analyze,慢SQL执行计划 | 来源:202607/20260709_01.md

Q:blktrace/blkparse/btt 如何分析一次 IO 的生命周期和各阶段延迟?

blktrace 采集块设备 IO 轨迹,blkparse 解析成可读文本,btt 做统计分析。一次 IO 生命周期 actions:Q(产生 IO 意向插入队列)→ G(发实际请求)→ P(plugging 插入,等待更多请求以便优化)→ I(调度,请求成型)→ U(unplugging 拔出,传给驱动)→ D(发布给驱动器)→ C(完成,返回状态,进程号为 0 表示成功)。时间指标:Q2Q(请求间时间)、Q2G(排队到分配 request)、G2I(分配到插入队列)、I2D(插入到实际下发驱动)、D2C(设备服务时间)、Q2C(块层总耗时,=Q2I+I2D+D2C)。用 btt -i sda.blktrace.bin -l sda.d2c_latency 看各阶段 MIN/AVG/MAX,D2C 是表征块设备性能的关键指标、Q2C 是客户端请求到响应时间。blkiomon 可按周期输出 d2c 直方图。这些能区分 IO 慢是设备问题(D2C 大)还是调度/排队问题(I2D 大)。

关键词:blktrace,blkparse,btt,D2C,Q2C,IO延迟 | 来源:202311/20231129_01.md

Q:ftrace 如何做内核函数级追踪?function_graph tracer 怎么用?

ftrace 是内置内核的追踪程序(内核态 strace),API 位于 debugfs 的 /sys/kernel/debug/tracing。依赖内核开关:CONFIG_FUNCTION_TRACER、CONFIG_FUNCTION_GRAPH_TRACER、CONFIG_STACK_TRACER、CONFIG_DYNAMIC_FTRACE(启动后 mcount 转 NOP 保证性能,打开 tracer 时才转回跟踪)。用法:echo 0 > tracing_on 关;echo function_graph > current_tracer 设 tracer;echo ksys_pread64 > set_graph_function 指定跟踪函数;echo funcgraph-tail > trace_options、echo funcgraph-proc > trace_options 加注释;echo 1 > tracing_on 开;执行目标程序后关掉,cat trace 看输出。示例展示了 pread64 完整调用链(ksys_pread64 → vfs_read → __vfs_read → xfs_file_read_iter → generic_file_read_iter → pagecache_get_page),能精确看到某次 read 是否命中 page cache(无物理 IO)及各函数耗时,用于数据库 IO 深潜。

关键词:ftrace,function_graph,内核追踪,pread64,page cache,tracefs | 来源:202112/20211216_01.md

Q:pgBadger 在监控生态里定位是什么?日志相关参数应如何配置以便分析?

pgBadger 是解析 pg_log 生成 HTML 报告的日志分析工具,偏日志分析、适合 DBA 巡检。要让它有效工作,日志参数需配合:logging_collector=on、log_destination=‘csvlog’(或 stderr,pgBadger 能解析多种格式)、log_min_duration_statement=3s(慢 SQL 阈值,OLTP 15s、OLAP 30s5min)、log_lock_waits=on(记录锁等待)、log_temp_files=0(全部记录临时文件)、log_autovacuum_min_duration=0、log_checkpoints=on、log_connections/log_disconnections=off(减少噪音)、log_line_prefix=’%m [%p] %q%u@%d from %h ‘、log_statement=‘ddl’(PG17+ 推荐只记录 DDL)。log_rotation_age=1d、log_rotation_size=1GB 控制切割。csvlog 格式便于 ELK/pgBadger 结构化解析,是日志分析的基础配置。

关键词:pgBadger,日志分析,csvlog,log_min_duration_statement,log_line_prefix | 来源:202607/20260709_01.md

Q:pgCluu 是什么?它如何做 PG 集群的监控和审计?

pgCluu(PostgreSQL Cluster utilization)是 Perl 编写的 PG 性能监控和审计工具,分两部分:1)collector(pgcluu_collectd)用 psql 命令抓取 PG 集群统计,用 sysstat 包的 sar 抓系统性能;2)纯 Perl grapher(pgcluu)生成 HTML 和图表报告,图表用 Javascript 库渲染、浏览器完成绘图,无需额外依赖。若不需要系统报告或不装 sysstat 可禁用(远程监控时 sar 自动禁用),也能单独从 sar 数据文件生成系统图表。安装:PGDG 仓库 apt/yum install pgcluu,或源码 perl Makefile.PL; make; make install。适合 DBA 巡检、生成全量审计报告,弥补 pgbadger 只做日志分析的空白。

关键词:pgCluu,监控审计,collector,sar,grapher,HTML报告 | 来源:202403/20240314_04.md

Q:pgSCV 是什么?它支持哪些采集能力和运行模式?

pgSCV 是 PostgreSQL 生态的 metrics exporter,采集系统、PostgreSQL、Pgbouncer 等统计,通过 HTTP /metrics 端点以 Prometheus 格式暴露指标。特性:Pull 模式(监听 /metrics 供 Prometheus/Vmagent 抓取);Push 模式(抓取自身 /metrics 推送到指定 HTTP 服务);多服务采集;服务自动发现(自动发现 Postgres 及生态服务);远程服务支持;Bootstrap 自安装(需 root);自动更新;用户自定义 metric;collector 管理和过滤(按块设备/网卡/文件系统/用户/库等 label 过滤)。只能跑 Linux。Charts 覆盖:数据库活动、运行中查询、等待事件与锁、运行负载、后台服务、第三方工具、系统负载、存储利用率。适合云原生 Prometheus + Grafana 方案,多实例(>5)首选。

关键词:pgSCV,Prometheus,metrics exporter,Pull,Push,监控 | 来源:202106/20210615_01.md

Q:pg_ash 插件是如何实现 PG 性能洞察(ASH)的?

pg_ash 是纯 SQL/PLpgSQL 实现的反插件(Anti-extension),不碰内核、免编译免重启,靠 pg_cron 每秒采样 pg_stat_activity 和 pg_stat_statements。它把会话信息编码成 integer[] 数组(每条约 100 字节),用 TRUNCATE 循环清空旧数据避免膨胀,保留最近 2-3 天。可事后回放任意时间段(如 top_waits_at)的等待事件和 TOP SQL,兼容 RDS 等云数据库。

关键词:pg_ash,ASH,performance insight,pg_cron,采样 | 来源:202602/20260226_01.md

Q:pg_ash 是什么?它为什么被称为’反插件’,实现原理和代价是什么?

pg_ash 是纯 SQL + PL/pgSQL 实现的 ASH(Active Session History)插件,定时采样 pg_stat_activity 和 pg_stat_statements,可分析过去任意时间段的等待事件、TOP SQL,纯 SQL 接口、RDS 和自建都适用。它被称为’反插件’(Anti-extension):不写 C、不改 shared_preload_libraries、不用重启数据库,只要有 pg_cron(主流云都自带)跑一遍 SQL 就装好。原理:每秒由 pg_cron 对 pg_stat_activity 拍快照,把会话信息压缩编码成 integer[] 数组(每条约 100 字节,一天几十 MB),用 TRUNCATE 循环清理只保留 2-3 天(零碎片不 bloating)。代价:1 秒采样会产生约 2.4GB/天 WAL,写压力大可改 5 秒采样。查询示例 select * from ash.top_waits_at(‘2026-02-26 09:00’,‘2026-02-26 09:10’)。建议配合 pg_stat_statements 自动关联 SQL 文本。

关键词:pg_ash,ASH,活跃会话历史,pg_cron,采样,等待事件 | 来源:202602/20260226_01.md

Q:pg_ash 的 CPU 标志和 WAL 开销分别需要注意什么?*

pg_ash 报告里的 CPU* 标志不一定代表 CPU 真的忙,它表示 wait_event_info=0,大多数情况是 CPU 执行,但也可能包含 PG 内核尚未 instrument 的’未知等待’路径,看到 CPU* 要结合系统监控一起看,不要机械理解成精确 CPU 时间。WAL 开销:pg_ash 每秒采样虽存储小(每条约 100 字节,一天几十 MB),但会产生约 2.4GB/天的 WAL 日志量,若数据库写压力极大或带宽/存储贵,可改为 5 秒采样:select ash.start(‘5 seconds’)。部署注意:RDS/Supabase 使用前确保启用 pg_cron;强烈建议开启 pg_stat_statements,pg_ash 能自动关联它直接显示 SQL 文本而不是冷冰冰的 query_id。

关键词:pg_ash,CPU*,WAL开销,pg_cron,pg_stat_statements | 来源:202602/20260226_01.md

Q:pg_stat_activity 有哪些核心字段?如何用它定位当前正在等待的慢 SQL?

pg_stat_activity 关键字段包括:pid(后端进程ID)、datname/usename/application_name、client_addr/client_port、backend_start/xact_start/query_start/state_change(时间戳)、wait_event_type/wait_event(等待事件)、state(active/idle/idle in transaction/idle in transaction (aborted)/fastpath function call 等)、backend_xid/backend_xmin、query、backend_type。定位慢 SQL 可用:select pid, now()-query_start during, query, wait_event_type, wait_event from pg_stat_activity where wait_event is not null order by query_start limit 1;。结合 wait_event_type/wait_event 判断该 backend 正在等 IO、锁还是 LWLock,是性能诊断的第一入口。

关键词:pg_stat_activity,wait_event,state,query_start,慢SQL | 来源:201903/20190309_01.md

Q:pg_stat_activity 里 query 字段显示的 SQL 有什么局限?如何在函数内部拿到当前会话最外层执行的 SQL?

pg_stat_activity.query 记录的是当前(或该连接最后一次)最外层 SQL,当一条 SQL 内部调用了函数、函数里又执行了别的 SQL 时,函数内部的 SQL 不会出现在这里。想要在函数里跟踪当前最外层 SQL,可以自定义函数查当前会话自身:create or replace function getquery() returns text as $$ select query from pg_stat_activity where pid=pg_backend_pid(); $$ language sql strict;。然后在任意 SQL 中调用 getquery() 即可拿到整条外层语句(例如 select getquery() as sql,oid from pg_class limit 1 会返回完整的外层 SQL 文本)。这在 DDL 审计、触发器记录来源 SQL 等场景很有用。

关键词:pg_stat_activity,query,最外层SQL,pg_backend_pid,函数 | 来源:201907/20190712_01.md

Q:pg_stat_bgwriter 有哪些关键列?buffers_backend 过大说明什么?

pg_stat_bgwriter 反映 bgwriter、checkpoint、backend 三方刷盘情况,关键列:buffers_checkpoint(checkpoint 写出的 buffer)、buffers_clean(bgwriter 写出的)、buffers_backend(backend 进程自己主动写出的)、checkpoints_timed/checkpoints_req(按时/请求触发的 checkpoint 次数)、maxwritten_clean、buffers_alloc。buffers_backend 过大或相比 buffers_checkpoint/buffers_clean 没小很多,代表 shared_buffers 没维护好,后端进程不得不自己刷盘,说明 bgwriter 不给力或 shared_buffers 偏小,应调大 bgwriter_lru_maxpages 或 shared_buffers。checkpoints_req 远多于 checkpoints_timed 则是雪崩式 checkpoint,需调整 max_wal_size。也可用它算写入量:8*(buffers_checkpoint+buffers_clean+buffers_backend)/1024 得总写 KB。

关键词:pg_stat_bgwriter,buffers_backend,buffers_clean,checkpoints_req,bgwriter | 来源:202011/20201127_03.md

Q:pg_stat_database 有哪些关键指标?如何用它做数据库总览和健康判断?

pg_stat_database 是数据库级累计统计视图,关键字段:numbackends(当前连接数)、xact_commit/xact_rollback(提交/回滚数)、blks_hit/blks_read(缓存命中/落盘块)、deadlocks(死锁次数)、temp_bytes(临时文件字节)、blk_read_time/blk_write_time(IO 耗时)、stats_reset。总览 SQL:select datname, numbackends conns, xact_commit, xact_rollback, round(100.0xact_rollback/nullif(xact_commit+xact_rollback,0),2) rollback_pct, round(100.0blks_hit/nullif(blks_hit+blks_read,0),2) cache_hit_pct, deadlocks, temp_bytes, age(datfrozenxid) xid_age from pg_stat_database where datname not in (’template0’,’template1’,‘postgres’);。阈值经验:回滚率>5% 持续=应用层 BUG;连接>80%=拒连风险;缓存命中率应看趋势(OLTP 稳定 95~98% 突然掉到 80% = 热点被踢出 buffer),不宜当硬阈值。

关键词:pg_stat_database,xact_commit,xact_rollback,cache_hit,deadlocks,temp_bytes | 来源:202607/20260709_01.md

Q:pg_stat_kcache 插件跟踪什么指标?

pg_stat_kcache 2.2.0 支持 PG13,用于跟踪每条 SQL 的 CPU 使用和文件系统真实读写行为(实际 IO 次数和字节数)。结合 pg_stat_statements,可看到每条 SQL 的真实资源消耗(CPU 时间、物理读、物理写),区分逻辑读与真实磁盘 IO,帮助定位真正吃资源的热点 SQL。

关键词:pg_stat_kcache,CPU,文件系统IO,真实读写 | 来源:202009/20200920_04.md

Q:pg_stat_kcache 解决什么问题?它如何区分 page cache 与真实磁盘 IO?

PG 的 shared buffer 统计容易误导人:shared_buffers 配得小,命中率看着低,但实际上 read 可能发生在 OS page cache,并未产生真实磁盘 IO,这些是文件系统接口完成的,数据库内核不知情。pg_stat_kcache(powa 团队出品)跟踪文件系统层真实读写行为,通过 getrusage 的 page fault 区分:major page fault(majflts)说明发生了真实磁盘访问,minor page fault(minflts)说明命中 page cache。它需要依赖 pg_stat_statements,加到 shared_preload_libraries=‘pg_stat_statements,pg_stat_kcache’。提供 pg_stat_kcache 视图(数据库级 exec_user_time/exec_system_time/exec_minflts/exec_majflts/exec_reads_blks/exec_writes_blks 等)和 pg_stat_kcache_detail 视图(按 query 明细),可精确判断某 SQL 到底落了多少真实盘。

关键词:pg_stat_kcache,page cache,major page fault,真实磁盘IO,getrusage | 来源:202012/20201215_02.md

Q:pg_stat_progress_copy 在 PG14 有哪些增强?COPY 进度监控能看哪些信息?

PG14 commit 9d2d4570 增强 COPY 进度上报。通过 select * from pg_stat_progress_copy(底层 pg_stat_get_progress_info(‘COPY’))可看到:pid、datid/datname、relid、command(CASE param5:1=COPY FROM、2=COPY TO)、type(param6:1=FILE、2=PROGRAM、3=PIPE、4=CALLBACK)、bytes_processed/bytes_total(已处理/总字节)、tuples_processed(已处理元组数,原 lines_processed 改名以消除 CSV/BINARY 歧义)、tuples_excluded(被 WHERE 子句排除的元组数)。这让你能监控大批量 COPY 导入导出的进度、速度,以及 COPY FROM 里 WHERE 过滤掉了多少行,对大表数据迁移和 ETL 很有用。

关键词:pg_stat_progress_copy,COPY,进度监控,tuples_excluded,PG14 | 来源:202103/20210310_02.md

Q:pg_stat_statements 只有累计值,如何做趋势分析?queryid 有什么稳定性边界?

pg_stat_statements 默认只给累计值,没有历史趋势,这是新手最常踩的坑。做法是外部定时器(cron/pg_cron)+ 历史表 + 趋势 SQL:建 pg_stat_statements_history 表(snap_ts, queryid, query, calls, total_exec_time, rows, blks),每分钟 insert into … select now(), … from pg_stat_statements where calls>0,再按 date_trunc(‘hour’, snap_ts) 聚合出 7 天 TOP SQL 趋势。queryid 的稳定性边界:同一 major 版本内 + 同一规范化 SQL 文本才稳定;PG 大版本升级(14→15、16→17)会因内部算法微调而变化,不能说跨实例/跨版本稳定,做历史比对时要记住这一点。

关键词:pg_stat_statements,快照,趋势,queryid,历史表 | 来源:202607/20260709_01.md

Q:pg_stat_statements 缺乏 p99/p95 指标会带来什么问题?如何评估 SQL 响应时间稳定性?

pg_stat_statements 提供 SQL 调用次数、平均 RT(mean_exec_time)、stddev(标准差)等,但缺乏 p99/p95 分位指标。p99/p95 含义:某 SQL 99% 请求 RT 低于某值、95% 低于某值,能说明 RT 稳定性。缺乏它的影响:只有平均值和方差,无法掌握 RT 稳定性边界,难与业务达成 benchmark 目标,尤其对高并发小事务(KV 查询)单次 RT 严苛的场景。业务上可用 stddev 评估抖动但不精确,基本无解。这也是 pgpro_stats、pg_wait_tracer 等插件通过 histogram 延迟分布补足的原因。希望 PG 未来在 pg_stat_statements 支持 RT 的 p99/p95 指标。

关键词:pg_stat_statements,p99,p95,分位指标,RT稳定性,stddev | 来源:202110/20211002_05.md

Q:pg_wait_sampling 插件如何采集等待事件?它提供哪些视图和 GUC?

pg_wait_sampling(Postgres Professional 出品)是基于采样的等待事件统计插件,需加 shared_preload_libraries(要额外共享内存并启动 background worker),支持 PG9.6+。它采集两类统计:History(内存 ring buffer,按周期记录每个进程的等待事件样本)和 Profile(内存 hash 表,按 pid/事件累计采样次数,可 reset)。提供视图:pg_wait_sampling_current(当前等待事件)、pg_wait_sampling_history(历史样本,含 ts 时间戳)、pg_wait_sampling_profile(profile 计数),函数 pg_wait_sampling_get_current(pid)、pg_wait_sampling_reset_profile()。GUC:pg_wait_sampling.history_size(默认5000)、history_period/profile_period(默认10ms)、profile_pid、profile_queries(配合 pg_stat_statements 按 query 统计)。它只记录等待次数(采样计数),不记录真实等待耗时。

关键词:pg_wait_sampling,等待事件采样,ring buffer,profile,background worker | 来源:202011/20201115_05.md

Q:pg_wait_tracer 是什么?

pg_wait_tracer 用 BPF 硬件 watchpoint 把 PostgreSQL 的等待事件变成实时诊断。它利用硬件断点/观察点在低开销下跟踪进程等待状态变化,生成等待事件的实时时间线,帮助 DBA 像看电影一样观察等待事件的起止和切换,定位瞬时等待和瓶颈。

关键词:pg_wait_tracer,BPF,watchpoint,等待事件,实时诊断 | 来源:202603/20260327_02.md

Q:pg_wait_tracer 用 BPF 硬件 watchpoint 实现等待事件全量追踪,原理是什么?有哪些诊断视图?

pg_wait_tracer 不用 patch、不装 extension、不重启数据库,通过 BPF + CPU 硬件 debug register/watchpoint 盯住 PGPROC->wait_event_info 字段。backend 每次进入/退出/切换等待事件都会写这个字段,watchpoint 触发后 BPF 程序用 bpf_ktime_get_ns() 计算前一状态持续时间,把 timestamp、pid、old/new_event、duration、query_id 发到 ring buffer,用户态消费聚合。核心卖点是 no sampling:捕获每一次 wait event transition 而非采样,克服短事件易漏、顺序不完整、难做精确 latency histogram 的采样盲点。7 个诊断视图:time_model(DB Time 总入口,CPU*/IO/LWLock/Lock/Client 等占比)、system_event(Top 等待事件)、session_event(按 backend 看 CPU/Wait 比例)、histogram(16 个 log2 bucket 延迟分布)、query_event(归因到 query_id,需 compute_query_id=on)、active(类 top 当前视图)、transitions(Sankey 状态转移图)。支持 interactive/daemon/replay 三种模式。

关键词:pg_wait_tracer,BPF,watchpoint,wait_event_info,no sampling,等待事件追踪 | 来源:202604/20260416_05.md

Q:pgcenter 有哪些子命令?它的 profile 命令如何给慢 SQL 的 PID 做等待事件画像?

pgcenter 是 CLI 管理工具,子命令:config(配置 PG 配合)、profile(等待事件 profiler)、record(记录统计到文件)、report(基于快照生成报告)、top(top 类实时视图)。找慢 SQL 后:select pid, now()-query_start during, query, wait_event_type, wait_event from pg_stat_activity where wait_event is not null order by query_start limit 1; 拿到 PID,然后 pgcenter profile -h host -p port -U user -d db -P -F 10(每秒采样 10 次),输出该 PID 每条 SQL 的等待时间占比(如 97.9% Running、1.47% IO.DataFileExtend、0.63% IO.DataFileRead、LWLock.WALWriteLock 等)。report 命令支持 -A(activity)、-S(表大小)、-D(database)、-T(表)、-I(索引)、-V(vacuum)、-X(statements) 等多维度报告,本质是采样各统计视图打快照,与 AWR、performance insight 类似。

关键词:pgcenter,profile,等待事件画像,report,慢SQL PID | 来源:201903/20190309_01.md

Q:pgpro_stats 相比 pg_stat_statements 增加了哪些能力?

pgpro_stats 基于 pg_stat_statements 增强:保存查询的执行计划(plan)、支持配置采样率(query_sample_rate)降低开销、计算每类查询的等待事件统计(基于 profile_period 时间采样,默认 10ms)、支持自动化监控 metric 配置。可通过 pgpro_stats_statements 视图查看 query、plan、wait_stats,帮助分析执行计划和等待分布。

关键词:pgpro_stats,pg_stat_statements,执行计划,等待事件,采样率 | 来源:202009/20200920_04.md

Q:pgpro_stats 相比 pg_stat_statements 增加了哪些能力?它的等待事件采样如何工作?

pgpro_stats(Postgres Professional)基于 pg_stat_statements,额外提供:1)存储查询计划(plan、planid 列,可对比同一 queryid 的多个执行计划);2)可配置采样率 query_sample_rate(0.0~1.0 随机选查询统计,降低开销);3)等待事件统计 wait_stats(JSON 列,如 {“IO”:{“DataFileRead”:10}});4)自定义 metric(metric_N_name/query/period/db/user 配置,pgpro_stats_metrics 视图查看)。等待事件采样用时间采样:按 pgpro_stats.profile_period(默认10ms)周期采样,若进程正在等待就把该周期计入对应事件时长,因此即使周期变化时间估算仍有效;enable_profile=false 可关闭。关键参数还有 pgpro_stats.max(默认5000,最少执行语句被丢弃)、track(top/all/none)、track_utility、save、plan_format(text/xml/json/yaml)。

关键词:pgpro_stats,pg_stat_statements,等待事件采样,query_sample_rate,执行计划 | 来源:202009/20200920_04.md

Q:pgsentinel 插件如何记录活跃会话历史?相比 pg_stat_activity 增加了哪些列?

pgsentinel 是记录活跃会话历史的插件(类似 Oracle ASH),通过 background worker 以可配置周期采样 pg_stat_activity,存入内存 ring buffer,并可配合 pg_stat_statements 关联 query 统计。需加 shared_preload_libraries=‘pgsentinel’(需重启)。GUC:pgsentinel_ash.sampling_period(采样周期,默认1秒)、pgsentinel_ash.max_entries(ring buffer 大小,默认1000)、pgsentinel_pgssh.enable(是否采样 pg_stat_statements 历史)。它可视为 pg_stat_activity 的采样,额外增加了列:ash_time(采样时间)、top_level_query(PL/pgSQL 场景的最外层语句)、query(未归一化的真实语句,能看到具体值)、cmdtype(SELECT/UPDATE/INSERT/DELETE/UTILITY/UNKNOWN/NOTHING)、queryid(关联 pg_stat_statements)、blockers/blockerpid/blocker_state(阻塞者数量和 pid,直接定位谁堵了谁)。

关键词:pgsentinel,ASH,活跃会话历史,ring buffer,blockerpid,采样 | 来源:202003/20200324_25.md

Q:pgsentinel 插件是如何记录活跃会话历史的?

pgsentinel 是记录历史活跃会话的扩展,需加入 shared_preload_libraries。它用后台 worker 按 sampling_period(默认 1 秒)周期采样 pg_stat_activity,写入内存 ring buffer(max_entries 默认 1000),可回看最近一段时间的历史会话状态,并关联 pg_stat_statements。相比只看当前状态,能回溯过去任意时刻谁在跑、谁被阻塞。

关键词:pgsentinel,活跃会话历史,ASH,采样,pg_stat_statements | 来源:202003/20200324_25.md

Q:powa4 是什么监控工具?

powa4 是 PostgreSQL Workload Analyzer,带 WEB 展示的监控工具,提供索引推荐、等待事件分析、命中率、配置变更跟踪等功能。它聚合 pg_stat_statements、pg_wait_sampling 等插件数据,帮助 DBA 分析负载、发现慢 SQL 和缺失索引、跟踪配置变更历史。

关键词:powa4,Workload Analyzer,索引推荐,等待事件,监控 | 来源:201905/20190520_01.md

Q:为什么 ANALYZE 后执行计划反而变差?可能的原因有哪些?

罕见但真实,原因:1)ANALYZE 触发扩展统计重建,但表数据量极小(<100 行)时统计信息不稳定;2)ANALYZE 时 default_statistics_target 过大(>1000),导致 plan 过分依赖极小概率事件;3)表刚 bulk load,ANALYZE 在最热路径上与业务 DML 冲突。证伪:把 default_statistics_target 调回 100 重新 ANALYZE,或对大表分区独立 ANALYZE 对比。这说明统计信息并非’越细越好’,样本过小或采样过大都可能导致 planner 过拟合,需要结合 n_live_tup 规模合理设置 default_statistics_target。

关键词:ANALYZE,default_statistics_target,执行计划,统计信息,过拟合 | 来源:202607/20260709_01.md

Q:为什么 GIN 索引有时不快?如何诊断和修复 pending list 问题?

GIN 索引更新走’快路径’(放 pending list),只在 VACUUM 时才合并到主索引。pending list 越大,查询时遍历 pending list 的开销越大,RT 升高。诊断:create extension pageinspect; select * from gin_metapage_info(get_raw_page(‘idx_xxx’, 0)); 看 n_pending_pages 字段,越大越慢。修复:VACUUM tbl 触发 pending list 合并。第一性原理:GIN 为’读多写少’设计,高频写时必须配套高频 vacuum(对应 JSONB/数组/全文搜索索引)。这也是为什么大量写入的 JSONB 表要频繁 vacuum、否则查询越来越慢的原因。

关键词:GIN,pending list,gin_metapage_info,pageinspect,VACUUM,JSONB | 来源:202607/20260709_01.md

Q:为什么 OFFSET 大分页会慢?正确做法是什么?

LIMIT 20 OFFSET 1000000 必须把前 100 万+20 条按 ORDER BY 排好序,再扔掉前 100 万条——OFFSET 不是’跳过’,是’排序再扔’。EXPLAIN ANALYZE 会看到 Sort + 大量 Buffers: shared read。正解是 Keyset 分页:select * from t where id > $last_seen_id order by id limit 20; 固定排序键+应用层记上一页最大 ID,走 Index Scan 不再 OFFSET。边界:Keyset 不支持随机跳页,跨页查询(‘跳到第 1000 页’)仍要用 OFFSET。自检 SQL:EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM t ORDER BY id LIMIT 10 OFFSET 1000000。

关键词:OFFSET,Keyset分页,LIMIT,慢SQL,分页优化 | 来源:202607/20260709_01.md

Q:为什么 count(*) 会扫表?为什么 index-only scan 有时还是会回表?

count(*) 扫表:PG 没有’记录总数’缓存(不像 MySQL InnoDB),必须扫可见版本链——MVCC 让每行有多个版本,count 必须判断哪些版本对当前事务可见。优化:用 pg_class.reltuples(统计估算,精度±10%)、物化视图、计数器表、采样估算(T-digest/HLL)。index-only scan 回表:它有 visibility map(VM)前提,只有当 VM 标记页面全部可见时才能纯索引返回,若页面有未提交事务产生的 dead tuple,仍需回表确认 visibility。诊断:VACUUM 后 index-only scan 概率升高(因为 VACUUM 维护 VM);查 pg_stat_all_tables 的 heap_blks_hit/idx_blks_read 或 pg_statio 系列看回表情况。

关键词:count(*),MVCC,index-only scan,visibility map,VACUUM,回表 | 来源:202607/20260709_01.md

Q:为什么 push/pull 大量数据慢?如何优化批量数据搬运?

核心原因:走 simple query 协议(每个语句单独解析/规划/执行),大量 round-trip;以及单条事务的 fsync。第一性原理:网络 round-trip + 单条事务 fsync = 大量数据搬运的两大成本。优化方向:1)用 prepared + bind(PREPARE p1 AS … EXECUTE)走 extended query 协议,省去重复解析;2)用 COPY 替代 INSERT(10x~100x 提速);3)批量提交(单事务 1000 行比单行快 100 倍,少 1 万次 fsync,参考 56 核 NVMe 上单行提交约 1500 行/s vs 单事务 1000 行约 145 万行/s);4)异步提交 SET synchronous_commit=off(配合 wal_writer_delay=10ms,最坏丢 3×wal_writer_delay)。

关键词:simple query,extended query,COPY,批量提交,synchronous_commit,fsync | 来源:202607/20260709_01.md

Q:为什么 shared_buffers 设太大反而慢?PG16+ 有什么改进?

shared_buffers=RAM×1/4 是经验值。PG16 之前,超过 RAM 25% 后 buffer mapping 的 LWLock 争用急剧上升——所有 backend 抢 buffer tag 的 hash 表,表现为 wait_event 大量 LWLock:buffer_mapping。PG16+ 引入 8 个 buffer mapping 分区,大幅缓解争用,可以设到 40% 甚至更高,但仍需权衡:shared_buffers 越大 → OS page cache 越小,而 OS page cache 命中率对 planner 估算的 effective_cache_size 影响变小。判断:若 wait_event 分布中 buffer_mapping 占比高,说明 shared_buffers 偏大,应调小或升级 PG16+。

关键词:shared_buffers,buffer_mapping,LWLock,PG16,8分区 | 来源:202607/20260709_01.md

Q:为什么 vacuum 不能并行回收同一张表?有什么替代方案?

PG 的 vacuum 是单进程扫表(maintain single relation lock),即使开 8 个 autovacuum worker,也只能在不同表上并行,同一张表内 vacuum 只能串行——这是大表 vacuum 慢的根因。替代方案:1)用 pg_partman 把大表分区,让 vacuum 在分区级并行(不同分区不同 worker);2)PG14+ 的 vacuumdb –parallel 仅对 index cleanup 阶段并行(主扫描仍串行);3)用 pg_prewarm 主动加载热点。理解这点有助于解释’大表为什么 vacuum 总是慢’,并指导大表按时间/范围分区以分散 vacuum 压力。

关键词:vacuum,并行,单进程,分区,pg_partman,vacuumdb –parallel | 来源:202607/20260709_01.md

Q:为什么要监控事务年龄 datfrozenxid?xid 回卷会导致什么灾难?

PG 的 xid 是 32-bit 无符号整数(PG17+ 可选 64-bit),最多 2^32≈43 亿,循环使用(wraparound)。当某表 relfrozenxid 距回卷点 <200000000(autovacuum_freeze_max_age)时,autovacuum 强制 freeze;xid 真正回卷后,原本’过去’的事务会变成’未来’的事务,数据突然消失,数据库进入保护模式拒绝写入只允许 VACUUM(著名’PG 库变只读’事故)。监控:select datname, age(datfrozenxid) from pg_database order by 2 desc; 任一库>2 亿报警、>15 亿紧急。治理:平时保持 autovacuum_freeze_max_age=200000000(默认不要改)、大表单独 SET 更大值、紧急手动 VACUUM FREEZE,绝对不要用 pg_resetwal 等清零工具。

关键词:datfrozenxid,xid回卷,wraparound,autovacuum_freeze_max_age,VACUUM FREEZE | 来源:202607/20260709_01.md

Q:分层定位漏斗如何用于故障诊断?报警后 5 分钟内该走哪条路径?

任何报警先分层:OS 层健康?(CPU/IO/内存/磁盘/网卡)→ 网络层?(带宽/RTT/丢包/防火墙)→ PG 实例存活?(连接打满/postmaster 死/crash)→ 数据库级?(锁等待/长事务/autovacuum 风暴)→ 表/索引级?(膨胀/统计失准)→ 最后才是单条 SQL。适用边界:本地单实例 PG 适用;托管 RDS 上 OS/网络层由云厂负责,只能拿到 PG 层指标。核心观点:SQL 层优先 + 漏斗排查补充——先用 pg_stat_statements 擒贼擒王(命中大多数场景),再按 OS/长事务/2PC 漏斗排查(命中突发场景)。证伪:OS、PG 实例、锁、autovacuum 都没事但业务还慢,说明不是 DB 层,去查 APP 层(连接池、ORM、GC、上下游)。

关键词:分层漏斗,故障诊断,擒贼擒王,OS层,APP层 | 来源:202607/20260709_01.md

Q:半小时用 Sampler 搭建 PG 简易监控,应监控哪几个关键指标?SQL 怎么取?

Sampler 是 Go 写的轻量监控工具,无需 agent/数据库,用 shell 命令取样展示。应监控:1)数据库年龄:select age(datfrozenxid) from pg_database where datname=current_database()(21 亿事务限制,到 2^31-1000 万打印 WARNING,剩 100 万变只读);2)写入量:基于 pg_stat_bgwriter,8*(buffers_checkpoint+buffers_clean+buffers_backend)/1024 得总写 KB,buffers_backend 过大说明 shared buffer 没维护好;3)缓存命中率:round(sum(blks_hit)100/sum(blks_hit+blks_read),2) from pg_stat_database(未考虑 page cache);4)事务提交回滚率:round(100(xact_commit/(xact_commit+xact_rollback)));5)服务器负载/CPU/内存;6)连接监控:按 state 分组 count(active/idle/idle in transaction),PG 是进程模型需防连接风暴。表膨胀、锁、vacuum 也可扩展。

关键词:Sampler,简易监控,缓存命中率,连接数,事务年龄,pg_stat_bgwriter | 来源:202011/20201127_03.md

Q:如何判断一个会话是否使用了 SSL 连接?pg_stat_ssl 视图和 sslinfo 插件怎么用?

客户端连接时可以选择 sslmode(disable/prefer/require 等),服务端要判断具体会话是否走了 SSL,两种方法:1)sslinfo 插件:create extension sslinfo; select * from ssl_is_used(), ssl_cipher(); ssl_is_used() 返回 t/f,ssl_cipher() 返回如 ECDHE-RSA-AES256-GCM-SHA384。2)pg_stat_ssl 视图:select * from pg_stat_ssl where pid=pg_backend_pid(); 字段 pid、ssl(布尔)、version(如 TLSv1.2)、cipher、bits(如256)、compression、clientdn。PG12 增加客户端证书信息输出:新增 client_serial、issuer_dn 列,并把 clientdn 改名为 client_dn。可用于安全审计、确认哪些连接是明文哪些是加密。

关键词:pg_stat_ssl,sslinfo,SSL,TLS,ssl_is_used,连接加密 | 来源:201909/20190908_02.md

Q:如何根据 wait_event 的主导事件快速判断瓶颈并采取动作?举几个典型映射。

常用映射:IO:DataFileRead 主导 → iostat -x 1 看 r_await>10ms,pg_prewarm 预热热点或换 SSD;IO:WALWrite → iostat 看 w_await,检查主备复制延迟/同步复制降级;IO:ControlFileSync → checkpoint 风暴,设 checkpoint_completion_target=0.9;LWLock:buffer_mapping → shared_buffers 设太大(>RAM 25%),调小或升级 PG16+(8 分区优化);LWLock:lock_manager → 单实例连接数>500,上 pgbouncer;Lock:transactionid → 看 pg_blocking_pids,应用层事务顺序不一致;Lock:tuple → 看具体 SQL + blocking,用 SKIP LOCKED 改写。若 state=active 且 wait_event IS NULL,说明在 CPU 上跑(大排序/哈希聚合),用 perf top -p pid 判断是否 CPU bound。

关键词:wait_event,DataFileRead,WALWrite,buffer_mapping,lock_manager,瓶颈定位 | 来源:202607/20260709_01.md

Q:如何理解 Linux read 调用的 IO 分层和各层测量工具的差异?

Linux 分层次:Userspace(应用、glibc)→ Kernelspace(系统调用接口、子系统 VFS/内存/进程、架构代码/驱动)→ Hardware(物理设备)。测量 IO 延迟时要注意:1)测量是平均还是绝对(平均值掩盖峰值,采样时间越长越平均);2)测量来自哪一层:iostat/sar/node_exporter 从 /proc 取(level 5 设备层);bcc 的 xfsdist/xfsslower 来自 level 3;biosnoop/biolatency 来自 level 5;perf trace/strace 来自 level 3;应用数据来自 level 1。不同层包含不同工作量,数值可能不同,且 strace/perf 自身会引入显著延迟,生产要极其谨慎。还要区分 buffered IO(用 page cache)和 direct IO(O_DIRECT 直接读进程地址空间),默认 Linux 全是 buffered。云环境 IO 延迟会波动,做 fio benchmark 时避免 bursting(突发模式相当于测两个系统)。

关键词:IO分层,page cache,direct IO,iostat,strace,IO延迟测量 | 来源:202112/20211216_01.md

Q:如何用 EXPLAIN 解读慢 SQL 的 6 个信号?EXPLAIN ANALYZE 有什么必避坑?

EXPLAIN (ANALYZE, VERBOSE, BUFFERS, TIMING, COSTS, SETTINGS, FORMAT TEXT) 读 6 个信号:1)actual time(真耗时,首行/末行,loops 相乘才是真实成本);2)rows vs actual rows(偏差>10× → 统计信息失真,需 ANALYZE);3)Buffers: shared hit/read(read 占比高 → shared_buffers 不够);4)loops(>1 多半 NestLoop 嵌套,cost 数字骗人);5)节点类型(Seq Scan/Index Scan/Bitmap Heap Scan/Hash Join/Sort);6)SETTINGS(打印实际生效的优化器参数,如 random_page_cost)。必避坑:EXPLAIN ANALYZE 真的执行 SQL!对 INSERT/UPDATE/DELETE 必须包 BEGIN; EXPLAIN ANALYZE …; ROLLBACK; 否则会真的改数据。

关键词:EXPLAIN,ANALYZE,BUFFERS,actual rows,loops,执行计划 | 来源:202607/20260709_01.md

Q:如何用 pg_blocking_pids 找出锁阻塞链?锁雪崩的三种典型形态是什么?

PG 9.6+ 提供 pg_blocking_pids(pid) 函数:select pid, pg_blocking_pids(pid) blocked_by, wait_event_type, wait_event, query from pg_stat_activity where wait_event_type=‘Lock’; 可递归找出谁堵谁,沿 blocked_by 一路回溯即得阻塞链(A→B→C…)。锁雪崩三形态:1)大事务持锁,小事务都等,一个慢查询卡 100 个 worker;2)大锁被已有长事务的小锁堵塞——DDL(ACCESS EXCLUSIVE)被普通 SELECT 阻塞,后续所有 DDL/DML 排队;3)高并发小锁等大锁——秒杀场景几百事务抢同一行 FOR UPDATE。第一性原理:没有超时=没有雪崩保护,DDL 必须包事务设 SET LOCAL lock_timeout=‘100ms’。

关键词:pg_blocking_pids,锁阻塞链,锁雪崩,lock_timeout,SKIP LOCKED | 来源:202607/20260709_01.md

Q:如何用 pg_stat_statements 抓 TOP SQL?它有哪些关键字段,分别代表什么含义?

pg_stat_statements 是 PG 内置 SQL 统计插件,需加到 shared_preload_libraries 并 create extension。抓 TOP SQL:select round(total_exec_time::numeric,2) total_ms, calls, round(mean_exec_time::numeric,2) mean_ms, rows, shared_blks_hit+shared_blks_read blks, query from pg_stat_statements order by total_exec_time desc limit 10;。关键字段:queryid 是查询指纹(同版本内规范化后稳定,跨 major 版本可能变化);query 是归一化后的 SQL(参数被替换为 $n);calls 调用次数;total_exec_time/mean_exec_time 总/平均执行时间(PG13+ 字段名);rows 总返回行数;shared_blks_hit/read 共享缓存命中/落盘块数。据此可快速找出耗时最长、消耗 IO 最多的 SQL。

关键词:pg_stat_statements,TOP SQL,queryid,total_exec_time,慢SQL定位 | 来源:202607/20260709_01.md

Q:如何用触发器和 C 扩展跟踪记录是谁写入/更新的,以及被更新了多少次?

跟踪写入者:用 contrib/spi 的 insert_username 扩展或 plpgsql 触发器。insert_username() 是 C 触发器,把 current_user 写入指定 text 列,创建 BEFORE INSERT OR UPDATE 触发器并传列名参数即可(如 create trigger … before insert or update on t for each row execute procedure insert_username(username))。plpgsql 版:create or replace function tg2() returns trigger as $$ begin new.username := current_user; return new; end $$ language plpgsql。跟踪更新次数:plpgsql 触发器 new.updcnt := old.updcnt+1;或用 contrib/spi 的 autoinc 扩展(autoinc() 把 sequence 下一个值写入 int 字段,可覆盖插入值,也支持 UPDATE 时递增,与 serial 列不同,需传列名+sequence 名成对参数)。plpgsql 触发器写法通用、C 触发器性能更高。

关键词:触发器,insert_username,autoinc,current_user,跟踪写入,更新次数 | 来源:201908/20190817_02.md

Q:如何监控表膨胀?B-Tree 索引膨胀的硬伤是什么,如何处理?

找膨胀表:select schemaname||’.’||relname tbl, pg_size_pretty(pg_total_relation_size(oid)) total_size, n_live_tup, n_dead_tup, round(100.0*n_dead_tup/nullif(n_live_tup,0),2) dead_pct from pg_stat_user_tables where n_dead_tup>10000 order by n_dead_tup desc limit 20。找膨胀索引用 pgstattuple(‘idx’) 看 dead_tuple_percent(>30% 值得 REINDEX)。B-Tree 的硬伤:不释放空间,只 REUSE。DELETE 后索引项变 dead tuple,vacuum 标记后加入 FSM,新 INSERT 复用 dead slot;若长期无 INSERT 则永远不释放物理空间,且 nbtree 用双向链表连接 leaf page,一个 page 只剩 1 个有效 item 也不能释放,HEAP 水位能降但索引水位几乎只能 REINDEX。PG12+ 用 REINDEX INDEX CONCURRENTLY 不阻塞写,PG14+ 支持 REINDEX TABLE CONCURRENTLY。

关键词:表膨胀,dead_tuple,pgstattuple,REINDEX CONCURRENTLY,B-Tree | 来源:202607/20260709_01.md

Q:如何诊断 autovacuum 风暴和 checkpoint 风暴?pg_stat_bgwriter 怎么看?

突发 IO/CPU 但 TOP SQL 无变化,答案多在后台进程三件套:autovacuum + checkpoint + bgwriter。autovacuum 风暴:查 pg_stat_progress_vacuum 看 worker 在跑哪些表、进度;查 select datname, age(datfrozenxid) from pg_database order by 2 desc,任一>200000000 触发 anti-wraparound vacuum(这是突然变卡的最大单一原因,autovacuum_freeze_max_age 硬编码防线)。checkpoint 风暴:select * from pg_stat_bgwriter,checkpoints_req 远多于 checkpoints_timed → 雪崩式 checkpoint,应增大 max_wal_size、延长 checkpoint_timeout、checkpoint_completion_target=0.9 摊平 IO。bgwriter:buffers_backend > buffers_clean → backend 写盘太多,bgwriter 不够,调大 bgwriter_lru_maxpages。证伪:临时关 autovacuum 看 IO 是否立刻下降。

关键词:autovacuum,checkpoint,bgwriter,pg_stat_bgwriter,anti-wraparound,IO风暴 | 来源:202607/20260709_01.md

Q:如何诊断流复制延迟?send_lag/flush_lag/replay_lag/xmin 四段各代表什么?

先分清 send 慢还是 replay 慢:主库 select client_addr, state, sent_lsn, replay_lsn, (sent_lsn-replay_lsn) byte_lag from pg_stat_replication; 备库 select pg_last_wal_replay_lsn(), pg_last_wal_receive_lsn()。四段拆解:send_lag(primary→standby 网络,primary 写网卡速率/带宽,通常<1ms);flush_lag(standby 刷 WAL,受备盘 IO,synchronous_commit=on 强制 fsync);replay_lag(standby 应用 WAL,受备机 IO 和并行回放 worker 限制);xmin horizon(logical slot 或 hot_standby_feedback 卡死)。第一性原理:send 是网络问题,replay 是备机执行能力问题,xmin 不前进是全局被事务卡住问题,三件事分开看。证伪:暂时关掉 hot_standby_feedback,延迟立刻消失 → 锁定是 feedback 导致。

关键词:流复制延迟,send_lag,flush_lag,replay_lag,hot_standby_feedback,xmin | 来源:202607/20260709_01.md

Q:如何诊断连接风暴与连接打满?pgbouncer 出问题时怎么查?

PG 是进程模型,连接=进程,连接打满会导致拒连。诊断:select count(*), state from pg_stat_activity group by state; 看 active 是否接近 max_connections;再查最老 idle 连接 select pid, usename, application_name, now()-state_change idle_age from pg_stat_activity where state=‘idle’ order by idle_age desc limit 10。治理:立刻 pg_terminate_backend 最老 idle 连接腾位置(仅 superuser)、排查 APP 连接池泄漏、长期上 pgbouncer、预防设 idle_session_timeout=‘1h’(PG14+)。pgbouncer 故障:psql -p 6432 pgbouncer 后 SHOW POOLS 看 sv_active/pool_size,>0.8 说明后端不够;cl_waiting>0 说明前端在排队;SHOW STATS/SHOW SERVERS 看总量和映射。pool_size 太小时 sv_active=pool_size 全部满载,新客户端排队直到 query_wait_timeout 超时报错。

关键词:连接风暴,max_connections,pgbouncer,SHOW POOLS,idle_session_timeout | 来源:202607/20260709_01.md

Q:故障诊断的三个救命查询和止血三件套分别是什么?

三个救命查询:1)谁在跑 select pid, now()-query_start duration, state, wait_event_type, wait_event, query from pg_stat_activity where now()-query_start > interval ‘5s’ and state=‘active’; 2)谁在等(长事务/空闲事务/2PC)select pid, state, now()-xact_start xact_age, query from pg_stat_activity where state in (‘idle in transaction’,‘idle in transaction (aborted)’) and now()-xact_start > interval ‘30min’; 以及 select * from pg_prepared_xacts where now()-prepared > interval ‘1h’; 3)谁锁了谁 select pid, pg_blocking_pids(pid) blocked_by, wait_event_type, wait_event, query from pg_stat_activity where wait_event_type=‘Lock’。止血三件套:pg_terminate_backend(pid)(杀会话)、pg_cancel_backend(pid)(只杀当前 query)、SET LOCAL lock_timeout(DDL 加超时)。预防参数:statement_timeout=30s、lock_timeout=5s、deadlock_timeout=1s、idle_in_transaction_session_timeout=10min、idle_session_timeout=1h(PG14+)。

关键词:救命查询,止血三件套,pg_terminate_backend,pg_cancel_backend,长事务 | 来源:202607/20260709_01.md

Q:监控 PG 必须先开的 5 个统计开关是什么?为什么每个都必须开?

5 个必开开关:track_activities=on(否则 pg_stat_activity 拿不到会话信息);track_counts=on(否则 pg_stat_*_tables、pg_stat_database 累计计数器为空);track_io_timing=on(否则拿不到 blk_read_time 及 pg_stat_statements 的 IO 时间);track_functions=‘all’(否则 pg_stat_user_functions 无数据);compute_query_id=on(PG13+ 默认,作为 pg_stat_activity.query_id 与 pg_stat_statements 关联的桥梁)。另外半必开日志开关:log_lock_waits=on、log_temp_files=0、log_min_duration_statement=3s。改完 select pg_reload_conf() 生效,任何一个没开对应视图就是空的。

关键词:track_activities,track_counts,track_io_timing,compute_query_id,监控开关 | 来源:202607/20260709_01.md

Q:磁盘满、WAL 堆积、replication slot 卡死如何排查和紧急处理?

磁盘满排查:df -h /pgdata 定位目录,du -sh /pgdata/pg_wal/* 和 du -sh /pgdata/base/* 看 WAL 和哪个库占最多;找最大对象 select n.nspname||’.’||c.relname, pg_size_pretty(pg_total_relation_size(c.oid)) from pg_class c join pg_namespace n on n.oid=c.relnamespace where c.relkind in (‘r’,‘i’) order by pg_total_relation_size(c.oid) desc limit 20。WAL 堆积:查 replication slot 状态 select slot_name, plugin, active, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) lag_bytes from pg_replication_slots。logical slot 卡死:select slot_name, xmin from pg_replication_slots where xmin is not null 找出 xmin 不前进的 slot,重启消费端或 pg_drop_replication_slot。紧急清理:先 pg_switch_wal 归档、调小 wal_keep_size,绝对不要删未归档的 WAL。

关键词:磁盘满,WAL堆积,replication slot,xmin,pg_wal_lsn_diff | 来源:202607/20260709_01.md

Q:阿里云 RDS PostgreSQL 自定义告警应配置哪些指标?各指标的合理阈值是什么?

RDS PG 云盘版需自行添加告警规则,建议配置(连续三次触发):1)active_connections_per_cpu 每 cpu 平均活跃连接数 >=2(与核数无关,8 核设 2 表示 16 活跃连接,负载已高);2)conn_usage 连接数使用率 >=80%;3)cpu_usage CPU 使用率 >=80%;4)local_fs_inode_usage inode 使用率 >=80%;5)local_fs_size_usage 空间使用率 >=80%;6)iops_usage 数据盘 IOPS 使用率 >=80%;7)mem_usage 内存使用率(排除 clean page cache)>=80%。周期和连续次数按业务调整。这是云上 RDS 监控的实操清单,覆盖连接、CPU、磁盘、inode、IOPS、内存六类核心容量指标,避免磁盘满、连接打满、CPU 打满等事故。

关键词:RDS,自定义告警,active_connections_per_cpu,conn_usage,iops_usage,监控指标 | 来源:202002/20200206_01.md

1.11 运维 / 工具 / 部署 / 参数(64 条)

Q:PostgreSQL 14 的 GROUP BY DISTINCT 是什么?

GROUP BY DISTINCT 用于对 grouping sets、cube、rollup 构造出的分组结果去重。当分组集合里不同分组维度组合产生了重复分组(例如 CUBE(a,b) 里某些组合重复),GROUP BY DISTINCT 会消除重复的分组行。它遵循 SQL 标准,让多维度聚合的结果更干净,避免重复分组行导致的统计错误。

关键词:GROUP BY DISTINCT,grouping sets,cube,rollup,PG14 | 来源:202103/20210304_02.md

Q:PostgreSQL 14 的 SQL 标准函数体(SQL-standard function body)是什么?

PG14 支持 SQL 标准函数体,允许用纯 SQL 语法定义函数,例如 CREATE FUNCTION … RETURN expr 或 BEGIN ATOMIC … END,替代传统用 $$ … $$ LANGUAGE sql 包裹字符串的方式。标准函数体在创建时即被解析,语法错误能提前暴露,且函数体更清晰、可被工具更好地分析。这提升了函数定义的可读性和可维护性。

关键词:SQL标准函数体,CREATE FUNCTION,RETURN,PG14 | 来源:202103/20210304_02.md

Q:PostgreSQL 14 的 jsonb 下标语法和原子操作是什么?

PG14 起 jsonb 支持下标语法(jsonb->‘a’-»‘b’ 之外的 jsonb[‘a’] 形式)和 set 原子操作,类似数组下标赋值,例如 UPDATE 里 jsonb[‘key’] = value 直接修改指定 key,或 jsonb[‘key’] = null 删除。这改变了此前更新 jsonb 必须整体重写(jsonb_set)的方式,让 JSON 字段支持更自然的原地更新,也便于配合部分更新优化。

关键词:jsonb下标,原子操作,jsonb_set,PG14 | 来源:202103/20210304_02.md

Q:PostgreSQL 15 的 JSON_TABLE 和 JSON 构造器是什么?

JSON_TABLE 是 SQL/JSON 标准里把 JSON 文档转成关系表(行集)的函数,在 FROM 子句里用 jsonpath 抽取字段映射为列,让 JSON 数据可以直接参与关系查询。JSON 构造器(JSON_OBJECT、JSON_ARRAY、JSON_ARRAYAGG、JSON_OBJECTAGG 等)用于从关系数据生成 JSON。PG15 全面增强了这两类能力,形成「关系→JSON(构造)」和「JSON→关系(JSON_TABLE)」的完整闭环,是 JSON 与关系模型互操作的关键。

关键词:JSON_TABLE,JSON构造器,JSON_OBJECT,JSON_ARRAYAGG,SQL/JSON,PG15 | 来源:202103/20210304_02.md

Q:PostgreSQL 15 的 UNIQUE NULLS NOT DISTINCT 是什么?

PG15 起 UNIQUE 约束支持 NULLS [NOT] DISTINCT 选项。默认(NULLS DISTINCT)下多个 NULL 互不相等,可同时存在多行 NULL;UNIQUE NULLS NOT DISTINCT 则把 NULL 视作相等的值,只允许一行 NULL。这解决了历史上唯一约束无法阻止重复 NULL 的问题,适合“业务上 NULL 也应有唯一性”的场景。

关键词:UNIQUE,NULLS NOT DISTINCT,唯一约束,PG15 | 来源:202103/20210304_02.md

Q:PostgreSQL 15 的 security invoker views 是什么,解决什么问题?

普通视图默认以 security definer 语义运行还是以 owner 权限运行易混淆,security invoker view(PG15)让视图按调用者(invoker)的权限访问基表,而不是视图定义者的权限。这更符合最小权限原则:用户通过视图查询时,只受自己拥有的基表权限约束,视图不会成为绕过权限检查的后门。适合多租户、需要精细控制基表访问权限的场景。

关键词:security invoker view,视图,权限,PG15,definer | 来源:202103/20210304_02.md

Q:PostgreSQL 内置连接池(PRO build-in pool)和 pgbouncer 有何区别?

PostgreSQL PRO 版内置连接池(build-in pool),把池化能力做进数据库内部,客户端连接后由 PG 内部复用后端进程,省去独立中间件。pgbouncer 是外部连接池,需单独部署。内置池的优点是架构简单、少一跳网络,但功能可能不如 pgbouncer 丰富;pgbouncer 独立部署、可横向扩展、生态成熟。选型看是否需要中间件和功能深度。

关键词:内置连接池,build-in pool,pgbouncer,连接池 | 来源:201909/20190922_02.md

Q:PostgreSQL 在 ZFS 上的调优要点是什么?

ZFS 是 COW 文件系统,用于 PG 时注意:ZFS 的 recordsize 设置(对齐 PG 8KB 页)、关闭或调整 ZFS 的冗余 checksum(与 PG checksum 二选一避免重复)、配置 ARC 缓存大小、以及 WAL 和数据的 dataset 分离。PG12 的 wal_recycle、wal_init_zero 参数可适配 COW 文件系统减少写放大。核心是让 ZFS 特性(快照、压缩、校验)与 PG 的 WAL/checksum 机制协调。

关键词:ZFS,COW,recordsize,ARC,调优 | 来源:202009/20200910_01.md

Q:PostgreSQL 的 CLOSE_WAIT 套接字如何快速关闭?

CLOSE_WAIT 是 TCP 状态,表示对端已关闭、本端应用未调用 close 导致连接悬挂。快速关闭需找到持有该套接字的进程并让它 close(重启进程或强制关闭 socket)。排查用 ss/netstat 找 CLOSE_WAIT 连接,定位进程,处理应用层未正确关闭连接的问题(连接泄漏)。数据库连接池若应用未归还连接也会产生大量 CLOSE_WAIT。

关键词:CLOSE_WAIT,TCP,连接泄漏,套接字 | 来源:202311/20231124_01.md

Q:PostgreSQL 的 Ceph 存算分离共享存储配置是什么?

PolarDB 存算分离共享存储可用 Ceph 构建,配置 Ceph cache tier(SSD 读写缓存)+ 机械盘两层存储,SSD 做热数据缓存、机械盘做容量层。Ceph 提供分布式块存储(RBD),多节点共享访问。这实现了一写多读集群的共享存储层,用 SSD 缓存保证性能、机械盘降低成本。

关键词:Ceph,存算分离,共享存储,cache tier,SSD | 来源:202508/20250812_03.md

Q:PostgreSQL 的 DBA 最常用 SQL 有哪些?

DBA 常用 SQL 包括:查活动会话(pg_stat_activity)、查锁等待(pg_locks + pg_blocking_pids)、查表大小(pg_relation_size/pg_total_relation_size)、查膨胀(pg_stat_user_tables)、查索引使用(pg_stat_user_indexes)、查慢查询(pg_stat_statements)、杀会话(pg_terminate_backend)。这些是日常运维排障的核心查询,应熟记。

关键词:DBA常用SQL,pg_stat_activity,pg_locks,pg_terminate_backend | 来源:202005/20200509_02.md

Q:PostgreSQL 的 Docker 容器内 zfs / DirectIO 问题是什么?

macOS 的 Docker 容器内核是 linuxkit,不支持 zfs 等需要特定内核模块的文件系统;容器内 DirectIO 的生效取决于宿主机目录挂载方式(未用 DirectIO 挂载时,容器内用 DirectIO flag 写数据不保证真正 DIO)。多容器共享宿主机文件系统的一致性需通过 DirectIO 或共享存储保证。这些是容器化部署 PG 时文件系统层面的常见坑。

关键词:Docker,zfs,DirectIO,linuxkit,文件系统 | 来源:202508/20250815_03.md

Q:PostgreSQL 的 MERGE INTO 语法是什么,支持哪些子句?

MERGE 是 SQL 标准的 upsert 语法,PG15 引入,用 WHEN MATCHED THEN UPDATE / WHEN NOT MATCHED THEN INSERT 分支处理目标行。PG17 增强支持 RETURNING 子句和 WHEN NOT MATCHED BY SOURCE(处理源中不存在的目标行,通常 DELETE)。MERGE 相比 INSERT … ON CONFLICT 更通用,能一次表达匹配更新、不匹配插入、源缺失删除等多种动作,适合数据同步和 ETL 的增量合并场景。

关键词:MERGE,upsert,WHEN MATCHED,WHEN NOT MATCHED,RETURNING,PG15 | 来源:202103/20210304_02.md

Q:PostgreSQL 的 Patroni 高可用框架是什么?

Patroni 是 PG 的高可用模板,用 DCS(etcd/consul/zookeeper)做分布式协调,通过 leader lock 决定谁是 primary,自动处理 failover、switchover、复制管理。它把 PG 与 DCS 结合,实现自动主从切换和集群管理,是 PG 高可用的主流方案(Pigsty、云 PG 都基于它)。核心是 DCS 里的 leader 租约保证任意时刻只有一个 primary。

关键词:Patroni,高可用,DCS,leader lock,failover | 来源:202103/20210304_02.md

Q:PostgreSQL 的 Pigsty 是什么?

Pigsty 是开源的 PG 发行版和高可用部署方案,基于 Ansible 一键部署生产级 PG 集群(高可用、监控、连接池、备份集成),类似“PG 的 Kubernetes”。它整合了 Patroni(HA)、pgbouncer(连接池)、Prometheus/Grafana(监控)、pgbackrest(备份)等,是 PG 生产部署的完整方案,适合快速搭建高可用 PG。

关键词:Pigsty,部署,高可用,Ansible,Patroni | 来源:202206/20220628_01.md

Q:PostgreSQL 的 PolarDB 三节点开源版部署架构是什么?

PolarDB 三节点开源版是共享存储的一写多读集群,一个主节点 + 两个只读节点共享同一存储(PolarFS/共享块设备)。主节点写,只读节点共享数据、就近读,实现存算分离和高可用。部署需配置共享存储、节点间通信、HA 组件。相比传统主从复制,共享存储的只读节点无复制延迟,读扩展更平滑。

关键词:PolarDB,三节点,共享存储,一写多读,存算分离 | 来源:202108/20210816_01.md

Q:PostgreSQL 的 SSH 长连接防断连配置是什么?

SSH 长连接防断连用 TCPKeepAlive(TCP 层心跳)、ServerAliveInterval(客户端周期发心跳)、ServerAliveCountMax(多少次无响应才断开)配置。这些参数让 SSH 连接在中间 NAT/防火墙空闲超时的情况下保持活跃,避免长时间无操作被断开。数据库远程连接(如 ssh 隧道访问 PG)也需要这些防断连配置。

关键词:SSH,防断连,TCPKeepAlive,ServerAliveInterval | 来源:202101/20210130_06.md

Q:PostgreSQL 的 SaaS DBaaS 设计中 schema 和 database 的优劣?

多租户隔离可用 database 或 schema 两种方式。database 隔离彻底(不同库独立 catalog、权限、连接),但资源开销大、跨库查询难、连接管理复杂;schema 共享 catalog,资源省、跨 schema 查询方便,但隔离弱(共享 catalog、易串扰)。PG 的 schema 本质是命名空间,database 才是真正隔离边界。选型:强隔离、独立计费用 database;资源共享、统一运维用 schema + 严格权限。

关键词:SaaS,多租户,schema,database,隔离 | 来源:202411/20241115_03.md

Q:PostgreSQL 的 Xata DBA 智能体是什么?

Xata 是 DBA 智能体,用 AI 自动化数据库运维(诊断、优化、回答问题)。它把 DBA 的排障经验和最佳实践封装成 AI agent,让用户用自然语言解决数据库问题。这是 AI 与数据库运维融合的方向,从“人工排障”转向“智能体辅助运维”。

关键词:Xata,DBA智能体,AI运维 | 来源:202503/20250321_02.md

Q:PostgreSQL 的 backtrace_functions 参数是什么?

backtrace_functions 是 PG13 的开发者 GUC,配置需要跟踪的 C 函数列表,当这些函数被调用时打印 backtrace。它用于源码开发调试,追踪特定函数的调用路径。配合 gdb、backtrace_on_internal_error 等工具定位内核问题。

关键词:backtrace_functions,调试,GUC,PG13 | 来源:202012/20201216_02.md

Q:PostgreSQL 的 bad plan 记录器是什么?

bad plan 记录器是评估优化器执行计划准确性的工具,当评估 rows 与实际 rows 相差超过配置比例时记录该查询。它帮助发现“优化器估错”的 SQL(统计信息不足、数据倾斜导致计划偏差),是性能调优的重要辅助——识别需要 ANALYZE 或调参的查询。

关键词:bad plan,执行计划,rows估计,优化器 | 来源:202003/20200324_32.md

Q:PostgreSQL 的 bytebase SQL 审核是什么?

bytebase 是数据库变更管理和 SQL 审核平台,把 SQL 变更纳入流程(工单、审批、执行、回滚、审计),类似“数据库的 GitOps”。它解决手工执行 SQL 缺乏审查、无回滚、无审计的问题,是 DBA 团队的 SQL 治理工具。配合 PolarDB/PG,实现 SQL 审核最佳实践。

关键词:bytebase,SQL审核,变更管理,GitOps | 来源:202206/20220628_01.md

Q:PostgreSQL 的 catalog corruption(元数据损坏)如何检测?

catalog corruption 检测通过检查系统表(pg_class、pg_attribute 等)的一致性,发现元数据损坏。工具包括 amcheck(检查索引/页)、pg_catcheck(专门检查 catalog 一致性)、以及查询系统表交叉验证(如 pg_class 与 pg_attribute 的 OID 对应)。元数据损坏危害大(影响所有操作),需定期体检,发现后从备份恢复。

关键词:catalog corruption,元数据损坏,pg_catcheck,amcheck | 来源:202008/20200814_04.md

Q:PostgreSQL 的 catalog 全局可见问题是什么(DB 吐槽大会 34 期)?

PG 的 catalog(系统表)全局可见,所有 database 共享同一个实例的 catalog(pg_database、pg_roles 等),而表数据是各库独立的。这意味着用户能看到实例级别的全局信息(所有库、所有角色),在多租户场景下信息暴露更多,隔离性不如 database 独立。这是 PG 架构特性,也是多租户设计需考虑的点。

关键词:catalog,全局可见,多租户,pg_database | 来源:202109/20210903_10.md

Q:PostgreSQL 的 debug_invalidate_system_caches_always 参数是什么?

debug_invalidate_system_caches_always 是 PG14 的调试参数,强制不使用 system catalog cache,每次都重新读系统表。它用于调试 catalog cache 相关 bug,验证代码是否依赖了错误的缓存状态。生产环境不能开启(性能极差),仅开发调试用。

关键词:debug_invalidate_system_caches_always,catalog cache,调试,PG14 | 来源:202101/20210107_04.md

Q:PostgreSQL 的 interval 类型内部是如何存储的?

interval 内部用三个独立字段存储:月(month)、日(day)、微秒(microsecond),而非统一的秒数。这样 1 month 和 30 days 在存储上可区分,加减运算能正确处理日历语义(如 1 month + 2023-01-31 应得 2023-02-28)。但代价是不同单位的 interval 之间比较、聚合时语义复杂。interval 可转成数值用于计算,例如 EXTRACT(EPOCH FROM interval) 得到总秒数,便于做时间差计算。

关键词:interval,内部存储,月,日,微秒,EXTRACT EPOCH | 来源:202103/20210304_02.md

Q:PostgreSQL 的 libpq tcp_user_timeout 参数是什么?

tcp_user_timeout 是 PG12 起 libpq 的连接参数(对应 TCP_USER_TIMEOUT),控制连接异常关闭时的超时时间。当网络异常(对端不可达、链路中断)时,TCP 默认可能长时间不感知,会话一直占用。设置 tcp_user_timeout 让连接在指定时间内未收到 ACK 就关闭,会话占用时间可控,避免僵尸连接堆积。

关键词:tcp_user_timeout,TCP_USER_TIMEOUT,连接超时,PG12 | 来源:201904/20190409_02.md

Q:PostgreSQL 的 long query 客户端异常断开会怎么样?

客户端执行 long query 时异常断开,服务端默认仍会继续执行完该查询(因为 PG 不实时检测客户端断开),可能浪费资源。PG14 起 check_client_connection_interval 可配置周期性检测客户端存活,检测到断开就中断查询。此外 tcp_user_timeout、keepalive 参数也能加速感知。核心是默认“查询跑完才知道断开”,需配置心跳类参数及时回收。

关键词:long query,客户端断开,check_client_connection_interval | 来源:202501/20250111_01.md

Q:PostgreSQL 的 neon 存算分离 serverless 是什么?

neon 是开源 AWS Aurora 风格的 PG,存算分离、serverless、Rust 编写。它把存储层(WAL 分离、页服务)与计算层解耦,计算节点可动态启停、按需计费,存储用对象存储。这让 PG 具备 serverless 的弹性(空闲缩到零、按需扩展),是 PG 云原生方向的代表。

关键词:neon,存算分离,serverless,对象存储 | 来源:202306/20230606_01.md

Q:PostgreSQL 的 odyssey 连接池是什么?

odyssey 是 Yandex 开源的多线程连接池(Scalable PostgreSQL connection pooler),用多线程模型处理连接,性能高于单线程的 pgbouncer。它支持多种认证、TLS、多后端路由,适合大规模高并发场景。相比 pgbouncer 的单线程事件循环,odyssey 多线程能利用多核,吞吐更高。

关键词:odyssey,连接池,多线程,pgbouncer | 来源:201906/20190624_01.md

Q:PostgreSQL 的 peerdb ETL 工具是什么?

peerdb 是 PG 的 ETL 工具,支持逻辑订阅、时间 base、xmin base 的增量提取,号称比现有产品快 10 倍。它做 PG 到数据仓库/数据湖的 CDC 同步,用逻辑复制技术高效增量提取。适合 PG 作为源的数据同步、ELT 场景。

关键词:peerdb,ETL,CDC,逻辑订阅,增量提取 | 来源:202403/20240314_03.md

Q:PostgreSQL 的 pg_activity 命令行 top 工具是什么?

pg_activity 是终端里的 PG 实时监控工具(类似 top/htop),实时展示当前活动查询、等待事件、锁、连接等,比静态查询 pg_stat_activity 更直观。它让 DBA 在命令行快速观察数据库负载,是排障的常用工具。

关键词:pg_activity,top,实时监控,命令行 | 来源:202101/20210130_05.md

Q:PostgreSQL 的 pg_basebackup 异地从库和增量备份怎么做?

pg_basebackup 做全量备份和建 standby(-X stream 流式 WAL、–write-recovery-conf 生成 standby 配置)。增量备份用 pg_basebackup –incremental=PATH_TO_MANIFEST 基于上次备份的 manifest 只备份变化块,再用 pg_combinebackup 合并全量+增量为新全量。这是 PG17 起的原生增量备份能力。异地从库则用 pg_basebackup + primary_conninfo 建立流复制。

关键词:pg_basebackup,增量备份,pg_combinebackup,异地从库 | 来源:202203/20220309_01.md

Q:PostgreSQL 的 pg_datasentinel 库内可观测是什么?

pg_datasentinel 是库内可观测性扩展,把运维从“翻日志”推进到“库内可观测”,在数据库内收集和展示运维指标(活动会话、等待、资源),让 DBA 用 SQL 直接查询运行状态,类似内置的 ASH。它减少了外部监控的依赖,是 PG 可观测性增强方向。

关键词:pg_datasentinel,可观测性,库内监控,ASH | 来源:202604/20260416_04.md

Q:PostgreSQL 的 pg_hba.conf 配置和 SSL 吊销证书列表(CRL)是什么?

pg_hba.conf 控制客户端认证规则(谁、从哪、用什么方法连接)。PG14 支持配置 SSL 吊销证书列表目录(ssl_crl_dir 和 libpq 的 sslcrldir),把已吊销的证书 CRL 放在指定目录用于校验,拒绝被吊销证书的客户端。这是证书管理安全增强,配合 clientcert 实现完整的证书认证链。

关键词:pg_hba.conf,SSL,CRL,ssl_crl_dir,证书吊销 | 来源:202102/20210219_01.md

Q:PostgreSQL 的 pg_hexedit 数据文件编辑工具是什么?

pg_hexedit 是数据文件编辑/修复/读数工具(类似 pg_filedump),直接查看和修改 PG 数据文件的二进制内容。用于数据块级修复、页结构分析、抢救损坏数据。它提供比 pg_filedump 更交互的编辑能力,是极端情况下数据修复的底层工具。

关键词:pg_hexedit,数据文件,修复,pg_filedump | 来源:202307/20230704_03.md

Q:PostgreSQL 的 pg_lightool 轻量级工具是什么?

pg_lightool 是 PG 的轻量级周边工具,提供一些便捷的运维小功能(如查看锁、阻塞、连接等),类似 pg_activity 的辅助工具集。它定位轻量、易用,适合快速排障,不必部署重型监控。这类工具补充了 psql 命令行在可视化观察上的不足。

关键词:pg_lightool,轻量工具,运维 | 来源:202103/20210324_41.md

Q:PostgreSQL 的 pg_osc 在线 DDL 工具是什么?

pg_osc 是 online DDL 工具,用“影子表+触发器”方式在线执行表结构变更(加列、改类型等需要重写表的 DDL),避免长时间锁表。它创建新表、同步数据、切换表名,业务基本无感知。类似 gh-ost 之于 MySQL,pg_osc 解决 PG 大表 DDL 锁表重写的问题。

关键词:pg_osc,online DDL,影子表,触发器 | 来源:202210/20221008_01.md

Q:PostgreSQL 的 pg_rewind 和时间线分叉是什么?

pg_rewind 用于主从切换后把旧主回退到新主的时间线,使其能作为新 standby 加入。当旧主在切换时产生了新时间线分叉(两边都写),pg_rewind 比对数据块差异,把旧主的分叉数据回退,只同步差异块。它是主从切换(failover 后旧主重新加入)的标准工具,配合时间线概念使用。

关键词:pg_rewind,时间线,主从切换,failover | 来源:202103/20210304_02.md

Q:PostgreSQL 的 pg_track_settings 配置变更跟踪是什么?

pg_track_settings 插件跟踪 postgresql.conf 配置变更历史,记录参数何时被谁改过、改前改后的值。它解决“配置变更无审计”的问题,便于排障(性能突变是否是调参引起)和合规审计。类似功能有 powa 的配置变更跟踪。

关键词:pg_track_settings,配置变更,审计,postgresql.conf | 来源:202010/20201006_01.md

Q:PostgreSQL 的 pgbouncer 连接池是什么,为什么需要连接池?

pgbouncer 是轻量级连接池中间件,介于客户端和 PG 之间,复用数据库后端连接。PG 每个后端连接是独立进程,内存开销大(数 MB 起),大量连接会拖垮性能,且 max_connections 有限。连接池把大量客户端连接复用到少量后端连接,支持 session、transaction、statement 三种池化模式。transaction 模式最常用(事务结束即释放连接),适合高并发短事务的 Web 应用。

关键词:pgbouncer,连接池,transaction mode,max_connections | 来源:202112/20211220_04.md

Q:PostgreSQL 的 pgcat 读写分离连接池是什么?

pgcat 是新一代 PG 连接池和读写分离中间件(Rust 编写),支持分片、读写分离、事务路由、多租户等。它比 pgbouncer 功能更强(支持 sharding 级别的路由),比 pgpool-II 更现代、性能更好。pgcat 适合需要“连接池+读写分离+分片路由”一体化的场景。

关键词:pgcat,读写分离,连接池,分片,Rust | 来源:202212/20221202_02.md

Q:PostgreSQL 的 pgmodeler 图形化建模工具是什么?

pgmodeler 是 PG 的图形化建模工具,可视化设计数据库(ER 图、表、关系),生成 DDL 或反向工程现有库生成模型图。适合数据库设计阶段,比手写 DDL 直观,支持正向/反向工程。是 DBA/架构师设计 schema 的可视化工具。

关键词:pgmodeler,建模工具,ER图,数据库设计 | 来源:202012/20201217_03.md

Q:PostgreSQL 的 pgpointcloud 激光点云插件是什么?

pgpointcloud 是存储激光点云(LiDAR)数据的扩展,把海量三维点数据高效存储、压缩、精确提取。点云是自动驾驶、测绘、BIM 的数据形式,pgpointcloud 用压缩块组织点数据,支持快速范围查询。这是 PG 在专业空间数据(点云)领域的扩展。

关键词:pgpointcloud,点云,LiDAR,压缩 | 来源:202212/20221224_02.md

Q:PostgreSQL 的 pgpool-II 读写分离中间件是什么?

pgpool-II 是功能丰富的中间件,支持连接池、读写分离、负载均衡、复制管理、在线恢复、并行查询等。读写分离通过识别 SQL 类型(SELECT 路由到 standby,写路由到 primary)实现。pgpool-II 4.x 支持 enable_shared_relcache(共享关系缓存)、scram 认证等。相比 pgbouncer(纯连接池),pgpool-II 是完整的高可用+负载均衡中间件,但配置更复杂。

关键词:pgpool-II,读写分离,负载均衡,中间件,enable_shared_relcache | 来源:202109/20210924_01.md

Q:PostgreSQL 的 pgquarrel DDL 比对工具是什么?

pgquarrel 是数据结构(DDL/schema)比对工具,比较两个数据库(或数据库与 DDL 脚本)的结构差异,生成差异 DDL。用于 schema 版本管理、环境一致性检查(开发 vs 生产)、变更审计。类似 diff 之于文本,pgquarrel 是 schema 的 diff 工具,配合迁移脚本管理 schema 变更。

关键词:pgquarrel,DDL比对,schema diff | 来源:202003/20200324_18.md

Q:PostgreSQL 的 pgrouting 路径规划插件是什么?

pgrouting 是路径规划扩展,基于 PostGIS 提供路由算法(最短路径 Dijkstra、A*、旅行商 TSP、VRP 等),用于出行、快递、配送的路径规划。它把图算法叠加到路网数据上,配合 PostGIS 的空间索引和路网拓扑,构建完整的导航/物流系统。

关键词:pgrouting,路径规划,Dijkstra,TSP,PostGIS | 来源:202212/20221224_01.md

Q:PostgreSQL 的 postmaster 从启动到关闭的逻辑是什么?

postmaster 是 PG 的主进程,启动时读配置、初始化共享内存、启动辅助进程(bgwriter、checkpointer、walwriter、autovacuum 等)、监听客户端连接;每个客户端连接 fork 一个 backend 进程;关闭时发信号让各进程优雅退出、做 checkpoint、回收资源。它是 PG 进程模型的核心,管理所有子进程的生命周期。

关键词:postmaster,进程模型,启动,关闭,辅助进程 | 来源:202509/20250912_07.md

Q:PostgreSQL 的 psql \dX 和 df/do 快捷命令是什么?

\dX(PG14)查看自定义统计信息(extended statistics),\df 列出函数、\do 列出操作符,PG14 起 df/do 支持按参数类型筛选。这些快捷命令让 DBA 快速查看数据库对象定义,替代查询 pg_catalog。\d 系列(\dt 表、\dv 视图、\di 索引)是 psql 最常用的元命令。

关键词:psql,dX,df,do,快捷命令 | 来源:202101/20210117_01.md

Q:PostgreSQL 的 psql 客户端 gexec 妙用是什么?

psql 的 \gexec 元命令把上一条查询的每一行结果当作一条 SQL 执行,例如 SELECT ‘DROP TABLE ‘||tablename FROM … 后用 \gexec 批量执行生成的多条 DROP。这让 psql 能“用查询结果驱动命令”,实现批量 DDL、批量授权等,省去写脚本循环。是 DBA 批量操作的利器。

关键词:psql,gexec,批量DDL,元命令 | 来源:202101/20210121_02.md

Q:PostgreSQL 的 restore_command 参数修改支持 reload 生效(PG14)是什么?

PG14 起 restore_command 等恢复参数支持 reload 生效(SIGHUP 重载配置),无需重启实例。此前这些参数需重启才能修改,调整恢复命令很不方便。reload 生效让备份恢复相关的运维调整更灵活,减少停机。

关键词:restore_command,reload,恢复参数,PG14 | 来源:202012/20201202_03.md

Q:PostgreSQL 的 supavisor 云原生连接池是什么?

supavisor 是云原生多租户连接池,为 serverless 和 SaaS 场景设计,支持大规模连接复用、租户隔离、动态伸缩。它解决云数据库海量短连接的管理问题,比 pgbouncer 更适合多租户和 serverless 架构。supavisor 是新一代连接池的代表,配合云数据库的弹性能力。

关键词:supavisor,云原生,连接池,多租户,serverless | 来源:202312/20231214_02.md

Q:PostgreSQL 的 target_session_attrs 和 GUC_REPORT 实现客户端决策链路是什么?

target_session_attrs(read-write/read-only/any 等)配合 multi host 让 libpq 在连接时选择符合要求的节点(读写分离)。GUC_REPORT 机制让客户端在连接建立时立即获取数据库当前状态(如 in_hot_standby、事务状态),用于驱动级 failover 和负载均衡决策。两者结合实现协议级的读写分离和故障转移,客户端无需应用层判断。

关键词:target_session_attrs,GUC_REPORT,读写分离,failover,libpq | 来源:202103/20210304_02.md

Q:PostgreSQL 的 timezone 如何修改?

timezone 是会话级参数,可用 SET timezone=‘Asia/Shanghai’ 修改会话时区,或 ALTER DATABASE/SYSTEM SET timezone 持久化。timestamptz 类型存 UTC,显示时按 timezone 转换,改 timezone 只影响显示不影响存储。云数据库(RDS)修改时区可能受参数组限制,需在控制台或参数组里设置。

关键词:timezone,时区,timestamptz,ALTER SYSTEM | 来源:202001/20200131_01.md

Q:PostgreSQL 的 trace_connection_negotiation 参数是什么?

trace_connection_negotiation 是 PG17 的 GUC,跟踪客户端的 SSLRequest 或 GSSENCRequest 包,即连接协商阶段的加密请求。用于调试 SSL/GSS 连接建立问题,判断客户端是否请求了加密、协商卡在哪一步。

关键词:trace_connection_negotiation,SSL,GSS,连接协商,PG17 | 来源:202404/20240409_03.md

Q:PostgreSQL 的 tuned Linux 参数配置方法是什么?

tuned 是 Linux 的动态系统参数配置工具,用 profile 一键优化 OS 参数(内核、IO 调度、CPU 调频、内存等),适配数据库负载。对 PG 部署,用 tuned 的专用 profile 优化 OS 层(如 noop/deadline IO 调度、大页、swappiness),配合 PG 自身参数调优,提升整体性能。比手工改 sysctl 更规范、可回退。

关键词:tuned,Linux参数,IO调度,调优 | 来源:202006/20200625_04.md

Q:PostgreSQL 的 unistr 函数是什么?

unistr 函数(PG14)用于把包含 Unicode 转义的字符串还原为实际字符,例如 unistr(’d\0061t’) 返回 ‘dat’,支持 \XXXX 形式的 Unicode 转义序列。它解决了在 SQL 文本里难以直接书写某些特殊字符(控制字符、非常规字符)的问题,是字符串处理的补充工具,常用于处理含转义的国际文本。

关键词:unistr,Unicode转义,PG14 | 来源:202103/20210304_02.md

Q:PostgreSQL 的 whoDB 数据探索工具是什么?

whoDB 是数据探索工具,让用户探索、理解数据库里的数据(类似“数据的搜索引擎”),解决“数据积灰、不知道有什么数据”的问题。它自动索引和描述数据,支持自然语言查询数据,是数据资产管理和数据发现的工具。

关键词:whoDB,数据探索,数据发现,自然语言 | 来源:202512/20251213_10.md

Q:PostgreSQL 的最佳实践规约有哪些核心要点?

持续稳定使用 PG 的最佳实践:连接用连接池控制并发、避免长事务和 idle in transaction、合理建索引(不过度)、定期 vacuum 和 analyze、监控慢查询和膨胀、参数按硬件调优(shared_buffers、work_mem、effective_cache_size)、备份和 PITR 演练、版本升级规划。核心是“防膨胀、控连接、优索引、勤监控、有备份”,让数据库长期稳定。

关键词:最佳实践,连接池,索引,vacuum,监控,备份 | 来源:201902/20190219_02.md

Q:PostgreSQL 的自定义 GUC 规范化(PG14)是什么?

PG14 规范化自定义 GUC 参数,统一扩展自定义参数的命名和注册方式,避免扩展参数命名混乱。自定义 GUC 让扩展能定义自己的配置参数,纳入 postgresql.conf 管理。规范化后参数命名更一致、文档更清晰。PG17 又支持 ALTER SYSTEM 设置未识别自定义 GUC。

关键词:自定义GUC,参数规范化,PG14 | 来源:202104/20210408_05.md

Q:PostgreSQL 的进程模型与高并发和连接池关系是什么?

PG 是进程模型(每连接一个 backend 进程),相比线程模型内存开销大、连接数受限,因此高并发场景必须配合连接池(pgbouncer 等)复用后端连接。进程模型优点是隔离性好(一个进程崩溃不影响他人)、调试简单;缺点是连接多时内存和调度开销大。所以 PG 的架构天然需要连接池来支撑高并发。

关键词:进程模型,连接池,高并发,backend进程 | 来源:202606/20260601_06.md

Q:PostgreSQL 通过 SQL 接口关闭、重启数据库怎么实现?

PG 没有直接的 SQL 关库命令,需通过函数/信号实现:pg_ctl 命令行执行 stop/restart,或调用 pg_terminate_backend 杀会话、pg_ctl 工具,或扩展提供关闭函数。实际上标准做法是用 pg_ctl stop/restart(需 OS 层面执行),库内无法用纯 SQL 直接 shutdown。文章讨论的是通过 SQL 触发关闭的变通方案(如 UDF 调用 system)。

关键词:关闭数据库,重启,pg_ctl,shutdown | 来源:201902/20190201_01.md

Q:不懂 jsonpath 就相当于 JSON 没入门,jsonpath 的核心语法是什么?

jsonpath 是 SQL/JSON 的路径语言,核心语法:$ 表示根,.key 取对象成员,[*] 遍历数组,.?(@.x > 1) 做过滤,.type() 取类型,.size() 取大小,双引号内可写复杂 key。PG 的 jsonb_path_query、jsonb_path_exists 等函数都基于 jsonpath 执行。掌握 jsonpath 后,JSON 查询从“多级 -» 和 -> 嵌套”变成一条可读的路径表达式,开发效率提升一个量级,是 JSON 进阶的必修课。

关键词:jsonpath,$,过滤器,.type(),.size(),jsonb_path_query | 来源:202103/20210304_02.md

Q:为什么增加连接不能无限提高 TPS/QPS?配置多少个连接合适?

连接数增加会带来进程调度、内存、锁、缓存争用等开销,超过 CPU 核数的连接会导致上下文切换加剧、性能反而下降。合适连接数约为 CPU 核数(活跃连接),用连接池控制活跃连接在核数附近。配置过少并发不足,过多则争用和调度开销抵消收益。核心是让活跃并发连接数匹配 CPU 处理能力,而非堆连接总数。

关键词:连接数,TPS,QPS,CPU核数,连接池 | 来源:202112/20211220_04.md

1.12 扩展 / 插件(64 条)

Q:PostGIS 的 ST_AsMVT 地图矢量瓦片是什么?

ST_AsMVT 是 PostGIS 3 的函数,把查询结果生成 Mapbox Vector Tile(MVT)格式的矢量瓦片,配合 ST_AsMVTGeom 裁剪几何到瓦片范围。PG 直接输出矢量瓦片,配合 pg_tileserv(Go)或 Martin(Rust)等瓦片服务,即可构建轻量地图服务,无需 GeoServer 等重型 GIS 中间件。这是“数据库直出瓦片”的现代 GIS 架构。

关键词:ST_AsMVT,矢量瓦片,Mapbox Vector Tile,pg_tileserv,Martin | 来源:202103/20210313_18.md

Q:PostgreSQL 14 的 postgres_fdw 异步 append 是什么,提升什么性能?

PG14 为 FDW 引入异步执行接口,postgres_fdw 实现异步 append,即在 sharding 场景下对多个远端分片的查询可以异步并发发起,而不是串行逐个执行再合并。异步 append 让多个外部表的扫描并行进行,减少总响应时间,提升 sharding 查询吞吐。这是 FDW 从“串行拉取”走向“异步并行”的关键一步,未来将支持更多异步操作。

关键词:postgres_fdw,异步append,FDW,sharding,PG14 | 来源:202103/20210331_02.md

Q:PostgreSQL 18 的 EXPLAIN 扩展信息钩子是什么?

PG18 新增 EXPLAIN 扩展信息钩子,允许扩展在 EXPLAIN 输出里附加自定义信息(如插件的执行细节、成本估算)。此前 EXPLAIN 输出由内核固定,扩展难以注入信息。该钩子让扩展(如 FDW、自定义扫描)能把内部信息暴露给 EXPLAIN,提升可观测性和调优能力。

关键词:EXPLAIN,钩子,扩展信息,PG18 | 来源:202503/20250319_04.md

Q:PostgreSQL 18 的 extension_control_path 是什么?

extension_control_path 是 PG18 新增 GUC,指定插件的 .control 文件搜索路径,控制插件安装位置。这解决了插件散落在不同目录时无法被发现的问题,让插件管理更灵活(如自定义插件目录、多版本插件并存)。配合 PGXN/打包工具,改善插件部署体验。

关键词:extension_control_path,插件路径,PG18 | 来源:202503/20250319_08.md

Q:PostgreSQL 向插件开放执行路径生成策略是什么意思?

PG 逐渐向插件开放执行路径(path)生成策略,允许扩展参与优化器的执行计划生成(如自定义扫描路径、成本模型)。这是 PG 可扩展性向优化器深水区的延伸,让扩展(如列存、向量、图引擎)能生成自己的执行路径参与优化选择,而非只作为黑盒扫描节点。这使插件能更深地融入查询优化。

关键词:执行路径,优化器,插件,扩展,PG | 来源:202602/20260224_02.md

Q:PostgreSQL 多模扩展中图数据模型如何设计?

图数据模型用节点表(vertices)+ 边表(edges)存储,边表存起点、终点、权重、类型。查询用递归 CTE(PG 原生)或 AGE(openCypher)/SQL/PGQ 做图遍历(最短路径、N 度关系、模式匹配)。设计要点:节点和边建索引(边表对起终点建 B-tree 或 GiST)、大图分区、选择合适的图查询接口。图模型适合社交、风控、推荐、知识图谱。

关键词:图数据模型,节点,边,递归CTE,AGE,SQL/PGQ | 来源:202603/20260313_04.md

Q:PostgreSQL 多模扩展中时序数据模型如何设计?

时序数据模型设计:用 hypertable(timescaledb)按时间分 chunk,维度列(设备 ID)+ 时间戳 + 指标值,配合时间索引。设计要点:按查询模式选择分区粒度(小时/天)、合理设置数据保留和压缩策略、用连续聚合预计算常用聚合。时序模型要兼顾高速写入(批量、append-only)和区间查询,避免高基数维度导致的索引膨胀。

关键词:时序数据模型,hypertable,chunk,连续聚合 | 来源:202603/20260313_08.md

Q:PostgreSQL 多模扩展中空间数据模型如何设计?

空间数据模型用 geometry/geography 类型存点线面,配 GiST 空间索引,按业务用点(POI)、线(路网)、面(行政区)组织。设计要点:选择合适 SRID(投影 vs 球面)、建空间索引、用空间函数(ST_Intersects、ST_Distance)查询、大数据量分区(按地理范围)。配合 pgrouting 做路径规划、pgpointcloud 存点云。

关键词:空间数据模型,geometry,GiST,SRID,PostGIS | 来源:202603/20260313_16.md

Q:PostgreSQL 多模扩展(多模型数据库)架构是什么?

PG 的多模扩展架构让一个数据库同时支持关系、JSON、时序(timescaledb)、空间(PostGIS)、图(AGE)、向量(pgvector)等多种数据模型。底层靠扩展机制(类型、索引、操作符、函数)接入新模型,共享 PG 的事务、MVCC、存储和 SQL 引擎。多模融合的价值是避免为每种数据模型部署独立数据库,简化架构、统一运维。

关键词:多模扩展,多模型,JSON,时序,空间,图,向量 | 来源:202603/20260313_01.md

Q:PostgreSQL 时序冷热分离的三个扩展方案是什么?

时序冷热分离三个扩展组合可让存储成本降 50%、查询性能翻倍:用 TimescaleDB 压缩热数据(列式压缩)+ 数据保留策略自动老化 + pg_tier/parquet_s3_fdw 把冷数据转储到对象存储。核心思路是热数据用高性能本地存储+压缩,冷数据下沉到廉价对象存储,查询时按需访问。这是时序数据存储成本优化的典型架构。

关键词:冷热分离,TimescaleDB,pg_tier,压缩,时序 | 来源:201910/20191027_04.md

Q:PostgreSQL 的 Docker 镜像制作(集成插件)怎么做?

制作集成大量插件的 PG Docker 镜像:用 Dockerfile 基于官方 PG 镜像,apt/yum 安装插件或源码编译(PGXS make install),推送到镜像仓库。需注意插件版本与 PG 大版本匹配、依赖库安装、多架构(amd64/arm64)分别构建。镜像集成插件方便学习和快速部署,是“开箱即用”的环境方案。

关键词:Docker镜像,Dockerfile,插件集成,多架构 | 来源:202307/20230710_02.md

Q:PostgreSQL 的 FDW 全局事务 postgres_fdw_plus 是什么?

postgres_fdw_plus 是支持全局事务的 FDW 增强,让跨多个外部服务器的操作能纳入分布式事务(类似 XA/2PC),保证跨节点一致性。原生 postgres_fdw 的每个远端连接是独立事务,跨节点提交非原子。postgres_fdw_plus 用全局事务协议协调,适合需要跨分片强一致性的 sharding 场景。

关键词:postgres_fdw_plus,全局事务,分布式事务,FDW | 来源:202104/20210416_03.md

Q:PostgreSQL 的 FDW 异步流式传输是什么,解决什么瓶颈?

传统 FDW 从远端拉数据是同步、批量的,可能产生大缓冲区、串行等待,成为瓶颈。异步流式传输让 FDW 以流的方式边取边处理,远端和本地并行工作,减少内存峰值和等待,提升大数据量联邦查询的吞吐。这是 FDW 性能演进的方向,配合异步 append 和 pushdown,让 PG 联邦查询更接近原生分布式性能。

关键词:FDW,异步流式,联邦查询,性能 | 来源:202512/20251213_07.md

Q:PostgreSQL 的 FDW(Foreign Data Wrapper)是什么,工作流程如何?

FDW 是外部表访问接口,让 PG 通过 SQL 访问外部数据源(其他 PG、MySQL、SQL Server、文件、Hadoop 等)。工作流程:定义 server(连接信息)、user mapping(认证)、foreign table(映射外部对象),查询时 PG 生成外部扫描计划,FDW 把可下推的操作(WHERE、JOIN、聚合)下推到远端,拉回结果。postgres_fdw 是内置的 PG 到 PG 的 FDW,支持 pushdown、异步 append、批量插入等。FDW 是 PG 联邦查询和多源集成的基础。

关键词:FDW,外部表,foreign table,server,user mapping | 来源:202606/20260608_62.md

Q:PostgreSQL 的 MADlib 机器学习插件是什么?

MADlib 是 Apache 开源的机器学习扩展,在数据库内实现大量 ML 算法(回归、分类、聚类、深度学习、图算法等),数据不离开数据库即可训练和预测。它利用 PG 的 SQL 和并行能力做 in-database machine learning,避免数据搬运,适合大规模数据集的建模。可结合 Tensorflow 等做时序分析等高级场景。

关键词:MADlib,机器学习,in-database ML,深度学习 | 来源:202104/20210415_02.md

Q:PostgreSQL 的 PGSpider 联邦查询插件是什么?

PGSpider 是基于 FDW 的并行联邦查询插件,整合 sqlite_fdw、influxdb_fdw、griddb_fdw、mysql_fdw、parquet_s3_fdw 等多种 FDW,提供统一的并行查询入口。它让 PG 能并行查询多个异构数据源,是“数据虚拟化/联邦查询”的集成方案,适合需要跨库统一查询又不想做 ETL 的场景。

关键词:PGSpider,联邦查询,并行,FDW,数据虚拟化 | 来源:202105/20210527_02.md

Q:PostgreSQL 的 PGXN 插件市场是什么?

PGXN(PostgreSQL Extension Network)是 PG 的插件发布/分发平台,类似 CPAN/PyPI,用 pgxn 客户端(pgxn install)安装插件。它解决了“PG 没有官方插件市场”的痛点,集中了社区插件。但 PG 内核没有官方的插件市场机制(DB 吐槽大会第 36 期),PGXN 是社区方案,DuckDB 官方已推出“社区扩展插件市场”可作参照。

关键词:PGXN,插件市场,pgxn,扩展分发 | 来源:202308/20230829_01.md

Q:PostgreSQL 的 QuestDB 兼容 PG 协议时序数据库是什么?

QuestDB 是一款兼容 PG 协议的时序数据库,用类似 PG 的 SQL 接口,但存储引擎专为时序优化(列式、时间索引、高吞吐写入)。它说明“兼容 PG 协议”成为时序/新数据库吸引 PG 用户的策略。相比 timescaledb(PG 扩展),QuestDB 是独立数据库,性能更高但生态和兼容性不如原生 PG。

关键词:QuestDB,时序数据库,PG协议,列式 | 来源:202004/20200412_03.md

Q:PostgreSQL 的 Spock 多主复制插件是什么?

Spock 是 PG 的多主复制插件,实现多个节点双向写入并同步,类似 pglogical 的增强。多主复制解决 PG 内置逻辑复制“同表只能单向、双向打环”的限制,提供冲突处理机制。但多主复制本质复杂(冲突、全局序列、延迟),适合对一致性要求可放松、需要多地域就近写入的场景。

关键词:Spock,多主复制,双向复制,pglogical | 来源:202511/20251121_11.md

Q:PostgreSQL 的 TDE(透明数据加密)插件有哪些?

PG 原生长期不支持透明数据加密(TDE),需插件实现。Percona 开源了 PG 16+ 的 TDE 插件,提供整库加密,文件落盘前加密。TDE 保护静态数据(磁盘文件被窃取时不可读),是安全合规(等保、GDPR)的常见要求。此外还有 pgcrypto(字段级加解密)、pg_tde 等方案。选择 TDE 需权衡性能损耗(加密开销)和密钥管理复杂度。

关键词:TDE,透明数据加密,Percona,静态数据加密 | 来源:202404/20240416_02.md

Q:PostgreSQL 的 amcheck 插件是什么,PG14 增强了什么?

amcheck 是索引和数据页完整性校验插件,检查 B-tree 等索引结构是否损坏、页格式是否正确。PG14 增强 heap 表数据页格式错误、逻辑错误检测(如 tuple 损坏、页 header 错误)。它用于定期体检、故障后验证数据完整性,是数据可靠性检查的重要工具。

关键词:amcheck,完整性校验,数据页,索引,PG14 | 来源:202010/20201024_02.md

Q:PostgreSQL 的 citus 分库分表插件与基于 postgres_fdw 的 sharding 有什么区别?

citus 是分布式扩展,把表按分布列哈希/范围分布到多个 worker 节点,coordinator 负责路由和并行聚合,支持分布式事务、rebalancing、列存(columnar)等,是原生分布式的 sharding 方案。基于 postgres_fdw 的 sharding 则是用外部表把远端分片引入本地,靠 FDW 下推和 append 并行查询模拟 sharding,本质是联邦查询,分布式事务、扩容、负载均衡能力弱于 citus。citus 11 起企业版功能全开源,是 PG 生态最成熟的 sharding 方案。

关键词:citus,sharding,postgres_fdw,分库分表,分布式 | 来源:202103/20210325_02.md

Q:PostgreSQL 的 delay standby + dblink 模拟时间旅行表是什么?

用延迟备库(delay standby)配合 dblink/postgres_fdw 访问延迟时间点的数据,模拟时间旅行表(查询过去某时刻的数据状态)。因为备库延迟应用 WAL,其数据停留在过去,查询它即得到历史快照。这是 PG 无原生时态表时的一种近似方案,适合偶尔需要查历史状态的场景。

关键词:delay standby,时间旅行,时态表,dblink | 来源:202107/20210708_01.md

Q:PostgreSQL 的 duckdb_fdw 加速分析计算是什么原理?

duckdb_fdw 把 DuckDB 作为 PG 的外部分析引擎,通过 FDW 把查询下推到 DuckDB 执行。DuckDB 是列式、向量化、内存优化的分析型引擎,对聚合、扫描类 OLAP 查询比 PG 快得多(文章称提速 40 倍)。适合在 PG 里跑重分析查询时,把计算交给 DuckDB,PG 负责数据管理和事务。类似方案还有 pg_duckdb、pg_analytics。

关键词:duckdb_fdw,DuckDB,分析加速,列式,OLAP | 来源:202209/20220924_01.md

Q:PostgreSQL 的 hdfs_fdw 访问 hive/spark 是什么?

hdfs_fdw 让 PG 通过外部表访问 HDFS 上的数据(hive/spark 表),把大数据平台的数据直接引入 PG 查询。这实现了 PG 与 Hadoop 生态的对接,适合在 PG 里查询数据湖/数仓的离线数据。配合 parquet 格式和列存,可作为大数据查询入口。

关键词:hdfs_fdw,hive,spark,HDFS,数据湖 | 来源:202307/20230705_01.md

Q:PostgreSQL 的 hook(钩子)机制是什么,有哪些常见应用?

hook 是 PG 的扩展机制,在核心流程的特定点(executor、planner、utility、连接、认证等)预留回调,扩展通过注册 hook 函数插入自定义逻辑。常见应用:pg_stat_statements(executor hook 收集 SQL 统计)、登录 hook(login trigger,在连接时执行)、ALTER TABLE hook(审计)、EXPLAIN hook(PG18)。hook 让扩展无需改内核即可介入核心流程,是 PG 可扩展性的基石,但 hook 点有限且需谨慎使用。

关键词:hook,钩子,回调,扩展机制,executor hook | 来源:202107/20210708_04.md

Q:PostgreSQL 的 lantern 向量插件是什么?

lantern(及 lantern_extras)是 PolarDB/PG 的 AI 向量插件,提供向量检索、AI 功能集成,类似 pgvector 但针对 AI 场景优化。它支持向量索引和相似搜索,配合 PG 的 JSON、数组等实现多模检索。lantern 是 PG 在 AI 应用(图像搜索、推荐、NLP)上的插件选择之一。

关键词:lantern,向量,AI,相似搜索 | 来源:202309/20230922_01.md

Q:PostgreSQL 的 pgSCV 和 pgnodemx 指标导出器是什么?

pgSCV 是 PG 的 metrics exporter,聚合 pg_stat_* 指标导出给 Prometheus,并提供查询建议;pgnodemx 是 crunchy 开源的 OS metrics SQL 接口插件,把 Linux cgroup、/proc 等系统指标用 SQL 访问。两者都服务于监控体系:pgSCV 导出 PG 指标,pgnodemx 导出 OS 指标,配合 Prometheus+Grafana 构建完整监控。

关键词:pgSCV,pgnodemx,Prometheus,指标导出,监控 | 来源:202009/20200911_03.md

Q:PostgreSQL 的 pg_bulkload 是什么,编译报错常见原因?

pg_bulkload 是高速批量导入插件,绕开 SQL 层直接写数据文件,比 COPY 更快,适合海量数据初始加载。在 PolarDB 11 编译/使用报错常见原因是版本不兼容、依赖缺失或 API 变化(PolarDB 基于 PG 11,插件需匹配版本)。解决需核对插件版本与 PG 大版本对应关系、安装依赖库后重新编译。

关键词:pg_bulkload,批量导入,编译报错,PolarDB | 来源:202412/20241210_01.md

Q:PostgreSQL 的 pg_curl 插件是什么?

pg_curl 插件让数据库内发起 HTTP 请求(GET/POST),把外部 API 调用封装为 SQL 函数。适合在存储过程里调用外部服务(如通知、webhook、AI 接口)。但库内发 HTTP 有安全风险(SSRF、外联),需严格限制权限和出口。类似 openai+http 插件让 PG 快捷调用 openai 服务。

关键词:pg_curl,HTTP,外部API,openai | 来源:202108/20210813_02.md

Q:PostgreSQL 的 pg_duckdb 和 pg_analytics 是什么?

pg_duckdb 是把 DuckDB 集成进 PG 的插件,让 PG 能调用 DuckDB 引擎做分析加速;pg_analytics 是 zero-ETL 超融合插件,让 PG 直接查询 Apache Iceberg、Parquet 等数据湖格式。两者都让 PG 具备现代分析能力:pg_duckdb 偏重向量化分析引擎,pg_analytics 偏重数据湖格式访问,实现冷热分离和分析加速。

关键词:pg_duckdb,pg_analytics,DuckDB,Iceberg,Parquet | 来源:202409/20240918_03.md

Q:PostgreSQL 的 pg_lake / pg_lakehouse 数据湖插件是什么?

pg_lake 系列是 snowflake 收购后开源的 PG 集成数据湖插件,pg_lakehouse(paradedb)让 PG 直接访问本地/远端对象存储的 Parquet、CSV、JSON、Avro、ORC 等文件,实现 PG 与数据湖的融合。这类插件让 PG 无需 ETL 即可查询数据湖数据,是“数据库+数据湖”超融合(zero-ETL)的代表。

关键词:pg_lake,pg_lakehouse,数据湖,Parquet,对象存储 | 来源:202511/20251107_11.md

Q:PostgreSQL 的 pg_parquet 和 parquet_s3_fdw 有什么区别?

pg_parquet 是 Rust(pgrx)写的插件,在 PG 内读写 Parquet 文件(本地/对象存储),支持把表导出为 Parquet 或把 Parquet 读入表;parquet_s3_fdw 是 FDW,把 S3 上的 Parquet 作为外部表查询。前者偏重双向读写和导出,后者偏重外部表只读查询。两者都让 PG 与 Parquet 数据湖生态互通。

关键词:pg_parquet,parquet_s3_fdw,Parquet,数据湖 | 来源:202411/20241106_01.md

Q:PostgreSQL 的 pg_start_sql 与 login hook 区别是什么?

pg_start_sql 是实例启动时执行的 hook(初始化、预热),login hook 是每次会话登录时执行的触发器(审计、限制)。前者面向数据库启动生命周期,后者面向每个连接建立。两者都是 hook 机制的应用,但触发时机和用途不同。

关键词:pg_start_sql,login hook,启动,登录 | 来源:202105/20210525_02.md

Q:PostgreSQL 的 pg_start_sql 插件(启动时自动加载 SQL)是什么?

pg_start_sql 是实例启动时的 HOOK 插件,在数据库启动时自动执行预定义的 SQL 或文件(如建表、建函数、设置参数、预热缓存)。它利用启动 hook 在 postmaster 启动阶段插入逻辑,适合自动初始化、预热、部署脚本化场景,减少手工操作。

关键词:pg_start_sql,启动hook,自动加载SQL | 来源:202105/20210525_02.md

Q:PostgreSQL 的 pg_tier + parquet_s3_fdw 冷数据转储是什么?

pg_tier 配合 parquet_s3_fdw 实现冷数据分层:把不常访问的表数据导出为 Parquet 文件存到对象存储(OSS/S3),在 PG 里通过 parquet_s3_fdw 作为外部表访问。这样热数据在本地、冷数据在对象存储,降低存储成本(对象存储比本地 SSD 便宜),查询冷数据时按需读取。这是存储成本优化的冷热分离方案,类似 PG 生态的“数据湖”能力。

关键词:pg_tier,parquet_s3_fdw,冷热分离,对象存储,OSS | 来源:202405/20240506_01.md

Q:PostgreSQL 的 pg_tier 冷热分离和 TimescaleDB 数据保留有何异同?

两者都做时序/冷数据的分层管理:TimescaleDB 数据保留策略(retention policy)自动删除/归档过期的 chunk,配合压缩降低存储;pg_tier 把冷数据转储到对象存储(OSS/S3),用外部表按需访问。TimescaleDB 侧重时序数据的自动老化和压缩,pg_tier 侧重通用表的冷数据下沉到廉价存储。都是降存储成本的方案,TimescaleDB 更内聚于时序场景。

关键词:pg_tier,TimescaleDB,冷热分离,数据保留,压缩 | 来源:202405/20240506_01.md

Q:PostgreSQL 的 pg_timetable 和 pg_task 任务调度插件是什么?

pg_timetable 和 pg_task 是 PG 的任务调度(JOB)插件,在数据库内定时执行 SQL 任务(类似 cron 但数据库内)。pg_timetable 支持链式任务、依赖、错误处理;pg_task 更轻量。相比外部 cron,库内调度与数据更近、便于管理和监控,适合数据刷新、定期清理、报表生成等定时任务。PG 原生也有 pg_cron 做类似的事。

关键词:pg_timetable,pg_task,任务调度,pg_cron,JOB | 来源:202108/20210813_01.md

Q:PostgreSQL 的 pg_tokenizer 和 pg_ai_query 是什么?

pg_tokenizer 是 PG 的 AI 分词/token 化插件,把文本切分为 token 供 AI 模型或全文检索使用;pg_ai_query 是 AI 原生插件,让 PG 内直接调用 AI 能力(如用自然语言查询生成 SQL、语义分析)。它们代表 PG 向 AI 融合的方向:数据层直接提供 AI 能力,减少应用层搬运。

关键词:pg_tokenizer,pg_ai_query,AI,分词,自然语言 | 来源:202511/20251128_07.md

Q:PostgreSQL 的 pg_upgrade 与插件的兼容性要注意什么?

pg_upgrade 跨大版本升级时,插件需在新版本上重新编译/安装,因为插件编译绑定 PG 大版本(ABI 变化)。升级文档会说明插件、字典、同义词等文件的处理。升级前需确认所有插件有目标版本对应的安装包,否则升级后插件不可用。此外 pg_upgrade 会销毁 replication slot,需记录并重建。

关键词:pg_upgrade,插件兼容,大版本升级,replication slot | 来源:202108/20210805_01.md

Q:PostgreSQL 的 pg_upgrade 大版本升级要点是什么?

pg_upgrade 用于跨大版本升级(原地升级数据目录),比 pg_dump/restore 快。要点:升级前备份、检查插件兼容性(插件需重装)、记录 replication slot(升级会销毁)、处理自定义类型和扩展、用 –link 或 –copy-file-range 加速、升级后 ANALYZE。核心风险是插件和 slot 丢失,需提前规划。

关键词:pg_upgrade,大版本升级,–link,插件,slot | 来源:202108/20210805_01.md

Q:PostgreSQL 的 pgcrypto 加解密和大对象(large object)是什么?

pgcrypto 提供数据库内的加解密、哈希、随机函数(pgp_sym_encrypt、gen_random_uuid、digest 等),用于字段级加密、密码哈希、数据校验。大对象(large object)是 PG 存储大二进制数据(如文件)的机制,配合 pgcrypto 可加密存储文件。相比文件系统存文件,库内大对象可纳入备份和事务管理,但性能和管理成本更高。

关键词:pgcrypto,大对象,加解密,large object | 来源:202212/20221215_01.md

Q:PostgreSQL 的 pglog 日志分析插件是什么?

pglog 插件分析 PG 的 csvlog 日志,生成各种报告(慢查询、错误、连接统计等)。它把日志从纯文本变成结构化分析,帮助 DBA 了解数据库运行状况、发现异常。类似 log_fdw 但侧重报告生成,而非实时查询。

关键词:pglog,csvlog,日志分析,报告 | 来源:202109/20210918_03.md

Q:PostgreSQL 的 pgvector / vector 向量检索插件是什么?

pgvector(或 PolarDB 的 vector 插件)提供向量类型和相似度检索(L2 距离、内积、余弦相似度),支持 HNSW、IVFFlat 索引加速近似最近邻(ANN)搜索。它是 PG 实现 AI 语义检索、图像相似、推荐系统的基础,配合多模查询实现“向量+文本+空间”融合检索。向量检索让 PG 成为 RAG(检索增强生成)的知识库底座。

关键词:pgvector,向量检索,HNSW,IVFFlat,ANN,RAG | 来源:202203/20220302_01.md

Q:PostgreSQL 的 pgvectorscale 是什么?

pgvectorscale 是 pgvector 的增强扩展,用 StreamingDiskANN 等技术提升大规模向量检索的性能和规模,支持更大的向量集和更快的 ANN 查询,扩展机制类似 pgvector。它面向超大规模向量库场景(亿级向量),是 pgvector 生态的性能增强方案。

关键词:pgvectorscale,StreamingDiskANN,向量检索,pgvector | 来源:202511/20251109_05.md

Q:PostgreSQL 的 plrust 和 rust 插件开发是什么?

plrust 是 Rust 编写 PL 函数(存储过程语言)的插件,用 Rust 的安全性(内存安全、无 GC)写高性能数据库函数;pg_parquet 等插件也采用 pgrx 框架用 Rust 开发。Rust 相比 C 更安全(避免内存漏洞)、开发体验更好,是 PG 插件开发的新趋势。pgrx 是 Rust 开发 PG 扩展的主流框架。

关键词:plrust,pgrx,Rust,插件开发 | 来源:202402/20240201_04.md

Q:PostgreSQL 的 postgres_protobuf 插件是什么?

postgres_protobuf 插件让 PG 存取 Protobuf 二进制数据,把 Protobuf 消息序列化/反序列化到数据库。Protobuf 是高效二进制序列化格式(gRPC、微服务常用),该插件让 PG 能直接处理 Protobuf 数据,实现微服务与数据库的数据格式统一,避免应用层反复转换。

关键词:postgres_protobuf,Protobuf,序列化,微服务 | 来源:202412/20241213_01.md

Q:PostgreSQL 的 postgresml 是什么?

PostgresML 是“模型集市+向量数据库+自定义模型”的 PG 扩展,在数据库内做机器学习训练和推理,支持多种模型(如 HuggingFace、XGBoost),并提供向量检索。它让 PG 成为一站式 AI 平台:数据存储、模型训练、向量检索都在库内完成,适合 AI 应用(图像搜索、推荐、NLP)快速落地。

关键词:PostgresML,机器学习,模型,向量检索 | 来源:202309/20230911_01.md

Q:PostgreSQL 的 quantile 分位数聚合插件是什么?

quantile 插件提供分位数聚合函数(如中位数、p50、p95、p99),弥补 pg_stat_statements 等无法直接算分位数的短板。分位数对延迟分析、性能 SLA 很重要(识别长尾慢请求)。PG 原生可用 percentile_cont/percentile_disc 聚合,quantile 插件提供更丰富的分位数计算。

关键词:quantile,分位数,p99,percentile | 来源:202109/20210914_01.md

Q:PostgreSQL 的 time_bucket / date_bin 函数是做什么的?

time_bucket 是 timescaledb 提供的时序分桶函数,PG14 起内置等价的 date_bin。date_bin(stride, source, origin) 把时间戳对齐到任意起点(origin)和任意步长(stride)的桶,例如 date_bin(‘5 minutes’, ts, TIMESTAMPTZ ‘2000-01-01’) 把时间归到每 5 分钟一桶。相比 date_trunc 只能按固定日历单位(小时/天)对齐,date_bin 支持任意 bucket 和任意 origin 偏移,适合 IoT、金融等时序场景的窗口聚合。

关键词:date_bin,time_bucket,时序,分桶,origin,PG14,timescaledb | 来源:202103/20210325_01.md

Q:PostgreSQL 的 timescaledb Hyperfunctions 是什么?

Hyperfunctions 是 timescaledb 的时序数据分析函数库,提供统计近似、时间加权、速率、下采样等高级时序分析函数(如 approximate percentile、time_weight、counter_agg)。它让时序分析(监控聚合、金融指标)直接在 SQL 里完成,无需外部计算,是 timescaledb 的分析能力扩展。

关键词:timescaledb,Hyperfunctions,时序分析,下采样 | 来源:202107/20210715_04.md

Q:PostgreSQL 的 vops(向量化)插件是什么?

vops(vectorized operations)是向量化执行插件,把数据按列向量组织、用 SIMD 批量处理,加速分析型查询(聚合、扫描)。它是对 PG 行式执行的向量化补充,类似列存引擎。在 PolarDB 编译报错通常也是版本/依赖问题。向量化是 OLAP 加速的重要技术方向。

关键词:vops,向量化,SIMD,OLAP | 来源:202412/20241209_01.md

Q:PostgreSQL 的 wasm extension(UDF 安全沙箱)是什么?

wasm extension 用 WebAssembly 作为 UDF 的安全沙箱,让用户自定义函数在受限的 WASM 运行时里执行,隔离文件系统、网络等系统访问,防止恶意/有 bug 的 UDF 危害数据库。相比原生 C UDF(可访问整个进程),wasm 沙箱提供内存安全和权限隔离。这是数据库 UDF 安全的重要方向,适合多租户、云数据库让用户安全自定义逻辑。

关键词:wasm,WebAssembly,UDF,安全沙箱 | 来源:202308/20230819_01.md

Q:PostgreSQL 的 zig 开发插件和 C 插件开发有什么区别?

传统 PG 插件用 C 开发(配合 PGXS 构建),zig 是新语言,可编译出无依赖、兼容 C ABI 的库,开发体验现代、更安全。文章展示了用 zig 开发 PG 插件,说明插件开发语言多元化。核心是插件需导出 PG 规定的 C 接口(_PG_init、函数符号),任何能编译成共享库的语言都可实现。C 插件开发需理解 PGXS、fmgr、内存上下文等。

关键词:zig,插件开发,C,PGXS,fmgr | 来源:202403/20240330_05.md

Q:PostgreSQL 的列存/列式存储扩展有哪些?

列式存储扩展用于分析场景,按列而非行存储数据,压缩比高、扫描快。代表:cstore_fdw(早期列存 FDW)、citus 的 columnar(citus 11 内置列存)、TimescaleDB 的列式压缩、pg_analytics(zero-ETL 超融合)、以及 duckdb_fdw/parquet 相关方案。列存适合 OLAP 大量扫描少数字段,不适合频繁单行更新。选择取决于是 PG 原生列存(citus columnar)还是外部引擎(duckdb)加速。

关键词:列存,columnar,cstore_fdw,citus,OLAP | 来源:202104/20210428_03.md

Q:PostgreSQL 的图计算插件 AGE 是什么?

AGE(A Graph Extension)是 Apache 开源的图数据库扩展,在 PG 内实现 openCypher 图查询语言,提供图数据存储和遍历(如 shortest path、模式匹配)。它基于 PG 的存储和事务,让关系库具备图计算能力,适合社交网络、风控、推荐等图谱场景。AGE 用 cypher 语法,PG19 又引入 SQL/PGQ 原生图查询,图能力正从插件走向标准。

关键词:AGE,图数据库,openCypher,图查询 | 来源:202104/20210417_02.md

Q:PostgreSQL 的数据库选型通用原则是什么?

数据库选型通用原则:先明确业务需求(数据模型、一致性要求、读写比例、扩展性、运维成本),再匹配数据库能力。要点包括:数据模型匹配(关系/文档/时序/图)、事务与一致性需求、性能与扩展性、生态与人才、成本(license+运维)。避免“追新”和“过度设计”,用成熟方案解决明确问题。PG 因多模、开源、生态好,是多数场景的稳妥选择。

关键词:数据库选型,选型原则,一致性,成本 | 来源:202205/20220512_01.md

Q:PostgreSQL 的监控告警体系怎么搭建?

PG 监控告警体系通常分层:指标采集(Prometheus + pg_exporter/pgSCV/node_exporter)、可视化(Grafana 仪表盘)、日志分析(pgbadger)、慢查询(pg_stat_statements)、告警(Alertmanager 规则)。采集 PG 的 pg_stat_* 视图和系统指标,设置阈值告警(连接数、锁等待、慢查询、复制延迟、磁盘)。完整的监控体系让 DBA 从被动救火转向主动预防。

关键词:监控,Prometheus,Grafana,告警,pg_exporter | 来源:201910/20191027_04.md

Q:PostgreSQL 的相似搜索(文本、向量、空间、标签)多模融合查询怎么设计?

多模融合查询把多种相似度组合排序:文本用分词/模糊匹配(tsvector、pg_trgm)+ rank,AI 语义用向量相似(pgvector、vector 插件),空间用距离/范围(PostGIS),标签用数组包含/相交,标量用等值/范围过滤。设计上用各维度的索引(GIN、向量索引、GiST、B-tree)分别加速,再按业务权重合并打分排序。核心是每种相似度建对应索引,最终在应用层或 SQL 里加权融合。

关键词:多模融合,相似搜索,向量,PostGIS,tsvector,rank | 来源:201903/20190310_01.md

Q:postgres_fdw 支持哪些下推(pushdown)操作?

postgres_fdw 支持把 WHERE 条件、JOIN、聚合、排序、LIMIT、CASE 语句等操作下推到远端执行,减少数据传输量。PG15 起支持 case 语句 pushdown,PG17 支持 semi-join(EXISTS)pushdown。下推的前提是操作只涉及外部表的列和远端支持的能力。核心原则是“尽量在数据所在地计算,只回传结果”,是 FDW 性能的关键。

关键词:postgres_fdw,pushdown,下推,semi-join,CASE | 来源:202108/20210801_03.md

Q:postgres_fdw 的 batch_size 对 insert 性能影响多大?

PG14 的 postgres_fdw insert 支持批量插入,batch_size 控制每个批次的行数。合理设置 batch_size 能显著提升 insert 到外部表的吞吐,因为它减少了与远端的网络往返和逐行 insert 的开销。batch_size 过小则往返多、过大则单次内存占用高,需根据网络延迟和行大小调优。这是 FDW 写入性能的关键参数。

关键词:postgres_fdw,batch_size,insert,批量插入 | 来源:202106/20210609_02.md

Q:postgres_fdw 的 keep_connections 选项是什么?

PG14 的 postgres_fdw 支持 hold foreign server 长连接选项(keep_connections),控制是否保持到外部服务器的连接不关闭。保持长连接可避免每次查询都重建连接的开销(TCP 握手、认证),提升频繁访问远端表的性能;代价是占用连接数。这是 FDW sharding 场景下减少连接建立开销、提升性能的重要优化。

关键词:postgres_fdw,keep_connections,长连接,PG14 | 来源:202104/20210403_02.md

Q:timescaledb 时序数据库的核心能力和压缩机制是什么?

timescaledb 是 PG 的时序扩展,核心能力:hypertable(超表)自动按时间分区、连续聚合(continuous aggregate)、数据保留策略(自动老化)、压缩(列式压缩)、以及 time_bucket 等时序分析函数。压缩通过把多个 chunk 的数据转成列式存储并压缩,大幅节省空间、加速扫描。timescaledb 2.2 还通过 custom plan provider 实现 index skip scan,加速 distinct、first_value、last_value 等稀疏值查询,最快上万倍提升。

关键词:timescaledb,hypertable,连续聚合,压缩,index skip scan | 来源:202105/20210514_01.md

Q:timescaledb 的连续聚合(continuous aggregate)和普通物化视图有何区别?

连续聚合是 timescaledb 针对时序的实时聚合物化视图,自动在后台增量刷新(只刷新新增/变化的 chunk),并支持“实时聚合”把最新未物化的数据实时合并进结果,查询永远是最新的。普通物化视图需手动全量 REFRESH,无法实时。连续聚合解决时序场景“既要实时又要快”的聚合查询需求,是 timescaledb 的核心杀手锏。

关键词:timescaledb,continuous aggregate,连续聚合,实时聚合 | 来源:202108/20210813_04.md

1.13 安全(38 条)

Q:DuckLake 本身没有细粒度权限,如何组合实现数据访问控制?

DuckLake 无内置 GRANT/RLS/列级权限,需多层叠加:1) READ_ONLY 模式阻止写;2) 数据文件加密防止绕过 DuckLake 直读 Parquet;3) DuckDB 引擎层用 enable_external_access=false + allowed_directories/allowed_paths 限制可访问的 S3 前缀;4) 对象存储 IAM 做 bucket/prefix 级隔离(最强);5) metadata DB 层用 PostgreSQL GRANT 或文件系统权限保护 catalog;6) 用 VIEW 在应用层做行/列过滤。核心结论是最可靠的是基础设施层 IAM + 引擎层路径限制。

关键词:DuckLake,访问控制,READ_ONLY,enable_external_access,IAM,allowed_directories | 来源:202604/20260415_04.md

Q:PG13 之前对 TDE 透明加密的期待是什么?为什么 TDE 一直难产?

TDE(透明数据加密)指对数据文件、WAL、临时文件等在存储层透明加密,使拿到磁盘/备份副本的人无法直接读取明文。社区长期期待 cluster-level TDE,但实现复杂:需要在 buffer 读写路径、WAL 加解密、密钥管理(KEK/DEK 分层、轮换)、备份恢复、复制链路等多个层面打通,且要与 pgcrypto 等既有加密能力协调。PG13 时仍处于 patch 讨论阶段,后续版本也多次被打回,直到较新版本才逐步推进。

关键词:TDE,透明加密,KEK,DEK,cluster-level,WAL加密 | 来源:201909/20190928_01.md

Q:PL/pgSQL 动态 SQL 中标识符、值、语法片段分别该如何安全处理?

三类输入要用不同方式:数据值走参数绑定(EXECUTE … USING $1);标识符(表名/列名)先做白名单校验再用 %I/quote_ident 引用;受限语法片段(ASC/DESC、排序字段)用枚举映射,不接受自由文本。错误示范是把用户输入直接拼进 SQL 文本(如 ‘… WHERE ‘||colname||’=…’),既无白名单又把值拼进语法,攻击者可控制 colname 或 keyvalue 改变语法结构。

关键词:动态SQL,EXECUTE USING,quote_ident,%I,白名单,枚举 | 来源:202606/20260601_17.md

Q:PolarDB/PostgreSQL 里密码明明正确却报「密码错误」通常是什么原因?

常见原因不是密码本身错,而是认证链路或环境问题:pg_hba.conf 命中了错误规则导致用了不同认证方式、密码编码问题、SCRAM 与 md5 不一致(改过 password_encryption 但没轮换)、客户端连错实例、角色不存在或 login 权限缺失、以及大小写/特殊字符被 shell 或连接串转义等。排查应从 HBA 规则命中顺序、认证方法、rolpassword 存储形态和连接串参数逐项定位。

关键词:密码错误,PolarDB,pg_hba.conf,SCRAM,认证排查 | 来源:202412/20241226_01.md

Q:PostgreSQL 14 对 TDE 的支持有哪些变化?

PG14 引入了 TDE 相关 patch,目标是支持加密数据文件和加密 WAL 日志文件,属于 cluster 级透明加密的早期落地。核心思路是在存储层对 page 和 WAL 做加解密,密钥由外部 KMS 或专用密钥文件提供。需要强调的是这类改动属于预览/讨论阶段,早期版本中 TDE 多次被打回,最终是否进入 GA 需以 release notes 为准。

关键词:TDE,PG14,加密数据文件,加密WAL,cluster-level | 来源:202012/20201228_01.md

Q:PostgreSQL 14 新增的 pg_read_all_data / pg_write_all_data 角色有什么用?

PG14 引入两个预制角色:pg_read_all_data 拥有对数据库中所有表和序列的默认读权限,pg_write_all_data 拥有默认写权限。它们主要用于兼容 MySQL 式的「只读影子用户/读写用户」管理习惯,让 DBA 可以一键授予某个账号全库只读或全库读写能力,而不必逐对象 GRANT。这两个角色只授予数据读写,不授予 DDL 或管理权限,安全性好于直接给 superuser。

关键词:pg_read_all_data,pg_write_all_data,预制角色,只读影子用户,PG14 | 来源:202104/20210406_03.md

Q:PostgreSQL 15 如何把 SET / ALTER SYSTEM 修改 GUC 参数的权限授予普通角色?

PG15 增加了对 GUC 参数的授权机制,允许通过 GRANT 将特定参数的 SET(会话级设置)或 ALTER SYSTEM(全局持久化设置)权限授予指定角色。这样可以把「谁能调整某个参数」做成细粒度权限,而不是只有 superuser 才能改。授权后普通角色即可在授权范围内设置对应 GUC。

关键词:PG15,GUC,SET,ALTER SYSTEM,GRANT,参数授权 | 来源:202204/20220408_05.md

Q:PostgreSQL 15 对 database 的 public schema 收回了什么权限?为什么重要?

PG15 之前,每个新建 database 的 public schema 默认对 PUBLIC(所有角色)授予 CREATE 和 USAGE 权限,任何能登录的用户都可在 public schema 建对象,带来安全隐患(如 search_path 劫持)。PG15 起收回 public schema 对 PUBLIC 的 CREATE 权限,只保留 USAGE,模板库相应调整。这堵住了默认状态下任意用户往 public schema 建对象的漏洞。

关键词:PG15,public schema,PUBLIC,CREATE,search_path,收权 | 来源:202109/20210913_01.md

Q:PostgreSQL 16 新增的 pg_create_subscription 内置角色解决了什么问题?

PG16 新增 pg_create_subscription 预制角色,只有拥有该角色(或 superuser)的用户才能创建逻辑订阅。同时细化了 subscription apply 时的角色选择:应用变更时可按 subscription owner 或 table owner 的身份执行。这避免了必须给普通用户授予过大的复制/写入权限才能建订阅,实现逻辑复制的最小授权。

关键词:pg_create_subscription,逻辑订阅,预制角色,subscription owner,PG16 | 来源:202304/20230406_02.md

Q:PostgreSQL 16 的 createrole_self_grant 参数解决什么问题?

PG16 新增 GUC createrole_self_grant。非 superuser 用户在拥有 CREATEROLE 权限并创建新角色后,默认并不会自动获得新角色的成员资格,导致「创建了却无法 SET ROLE 或继承其权限」的尴尬。createrole_self_grant 可配置为 set/inherit,让创建者在建角色时自动反向获得对新角色的 SET ROLE / INHERIT 权限,避免再手工 GRANT。

关键词:createrole_self_grant,CREATEROLE,SET ROLE,INHERIT,PG16 | 来源:202301/20230111_01.md

Q:PostgreSQL 17 引入的 MAINTAIN 权限和 pg_maintain 角色解决什么问题?

PG17 引入 MAINTAIN 权限及配套的 pg_maintain 预制角色,专门覆盖 VACUUM、ANALYZE、REINDEX、CLUSTER 等维护性操作。此前这些操作常需要表 owner 或 superuser,现在可以把「维护权」从「所有权/管理权」中剥离,单独授予,实现最小权限的运维授权——比如让某个账号只能做 vacuum/analyze,不能改数据或结构。

关键词:MAINTAIN,pg_maintain,VACUUM,ANALYZE,维护权限,PG17 | 来源:202403/20240314_01.md

Q:PostgreSQL 18 给 pgcrypto 新增了哪两个更安全的密码哈希算法?

PG18 为 pgcrypto 新增了两个更安全的密码哈希算法(如 bcrypt 和 argon2 方向的增强),用于替代较弱的 md5 口令哈希。相比传统 crypt/md5,这些算法带 cost 因子和抗 GPU/抗字典特性,能显著提高口令库泄露后的离线猜测成本。具体算法名以 GA release notes 为准,但方向是补强 pgcrypto 的口令哈希能力。

关键词:pgcrypto,密码哈希,argon2,bcrypt,PG18 | 来源:202504/20250406_05.md

Q:PostgreSQL 中 scram_iterations 调高后旧密码会自动变强吗?

不会。scram_iterations 只影响新生成 secret 的迭代次数,已经存在的 rolpassword 字符串里写着自己的迭代次数,后续认证按 secret 里的值执行。所以调高 scram_iterations 后,如果不轮换用户密码(ALTER ROLE … PASSWORD 或用户改密),旧 secret 不会自动变强。迁移 SCRAM 的关键不是只改 password_encryption,而是让密码重新写入。

关键词:scram_iterations,迭代次数,密码轮换,password_encryption | 来源:202606/20260601_18.md

Q:PostgreSQL 为什么也会遭受 DOS 攻击?认证前有哪些可被利用的攻击面?

数据库同样存在 DOS 风险,典型是利用认证前阶段:客户端在完成认证前就能占用后端的连接槽位,攻击者通过海量连接把 max_connections 耗尽,导致正常用户无法接入。应对手段是设置 authentication_timeout 限制认证阶段时长,并配合连接限制、防火墙、pg_hba 白名单等。另一个认证前攻击面是 Query Cancel 攻击——客户端可以给 postmaster 发送 cancel 请求包,postmaster 需要定位并处理对应 backend,恶意客户端可借此消耗资源。

关键词:DOS,DDOS,authentication_timeout,连接槽,Query Cancel,postmaster | 来源:201904/20190422_01.md

Q:PostgreSQL 大对象(large object)从 9.0 起增加了什么安全相关改进?

PG9.0 起新增 pg_largeobject_metadata 系统表,用于记录每个大对象的 OID、owner 和权限信息。此前大对象没有独立的元数据表,权限管理困难;有了这张表后可以像普通对象一样查询大对象归属与 ACL,并配合 GRANT/REVOKE 对 large object 做访问控制,弥补了大对象安全管理的空白。

关键词:大对象,pg_largeobject_metadata,large object,ACL,OID | 来源:202105/20210507_03.md

Q:PostgreSQL 如何使用 SSL 证书实现无密码登录(cert 认证)?

使用证书认证时,客户端持有私钥和客户端证书,服务端持有 CA 根证书。服务端在 pg_hba.conf 中把认证方法设为 cert(或 hostssl + clientcert=verify-full),客户端连接串提供 sslcert、sslkey、sslrootcert。握手时服务端用 root.crt 校验客户端证书,并默认把证书的 CN(或通过 map 映射)作为登录用户名,从而无需密码完成身份认证。

关键词:SSL证书,cert认证,无密码登录,sslcert,sslkey,clientcert | 来源:202006/20200619_01.md

Q:PostgreSQL 如何对日志中的敏感信息进行遮罩(Redacting)?

通过扩展的 emit_log_hook 钩子拦截即将写入日志的消息,对其中敏感字段(如密码、token、身份证号等)做脱敏替换后再落盘。该钩子由扩展注册,可在 C 层拿到 ErrorData 并改写消息文本或字段,从而在不侵入内核主代码的前提下实现日志级别的数据遮蔽,降低日志、审计、慢查询采集中的明文泄露风险。

关键词:emit_log_hook,日志脱敏,敏感信息,Redacting,钩子 | 来源:201909/20190901_01.md

Q:PostgreSQL 用户密码的两种存储方式是什么?为什么建议用 scram-sha-256?

PG 密码在 pg_authid.rolpassword 中有两种存储形态:md5 和 scram-sha-256。md5 存的是 md5(password+username),安全性弱,密码库泄露后防护不足,且官方已标注 deprecated。scram-sha-256 保存 salt+迭代次数+StoredKey+ServerKey,不存可直接重放的 proof,还能做服务端签名和 channel binding。因此新系统应把 password_encryption 设为 scram-sha-256 并轮换旧密码。

关键词:md5,scram-sha-256,密码存储,rolpassword,deprecated | 来源:202106/20210625_02.md

Q:PostgreSQL 的 SSL root.crt 文件在什么时候需要配置?它起什么作用?

root.crt 存放的是受信任的 CA 根证书,用于验证对端证书链。当服务端要求验证客户端证书(pg_hba.conf 用 cert 认证或 clientcert=verify-full)时,服务端需要用 root.crt 校验证书;客户端在 sslmode=verify-ca/verify-full 时也需要 root.crt 校验服务端证书。简单说:只要你需要校验对端证书,就应当在对应侧配置 root.crt;如果只加密不校验身份(如 sslmode=require),则不一定需要。

关键词:SSL,root.crt,CA证书,cert认证,verify-full | 来源:201904/20190405_10.md

Q:PostgreSQL 的 pg_remote_exec(shell 命令插件)是什么?

pg_remote_exec 插件允许在数据库内执行 shell 命令(如调用系统工具、脚本),把 OS 命令封装成 SQL 函数。它便于在存储过程里触发外部操作,但存在安全风险(SQL 注入可能导致任意命令执行),需严格限制权限。类似还有 pg_curl 插件(库内发 HTTP 请求)。这类插件扩展了数据库与外界的交互能力,但需谨慎授权。

关键词:pg_remote_exec,shell命令,pg_curl,安全 | 来源:202103/20210324_41.md

Q:SCRAM-SHA-256 中 StoredKey 和 ServerKey 分别起什么作用?

服务端保存的是 StoredKey 和 ServerKey,而不是明文密码或 ClientKey。StoredKey = H(ClientKey),用于验证客户端 proof:服务端用 StoredKey 算 ClientSignature,再通过 ClientProof XOR ClientSignature 恢复候选 ClientKey,比较 H(ClientKey) 是否等于 StoredKey。ServerKey 用于生成 ServerSignature,让客户端能验证服务端确实持有该用户的认证 secret,实现双向认证。泄露 StoredKey 不能直接冒充客户端,但仍可离线猜密码。

关键词:SCRAM,StoredKey,ServerKey,ClientKey,双向认证 | 来源:202606/20260601_18.md

Q:SCRAM-SHA-256-PLUS 的 channel binding 解决什么问题?

普通 SCRAM 能防密码嗅探和重放,但中间人仍可能把客户端和真服务端之间的 SCRAM 消息转发起来。channel binding 把 TLS 服务端证书哈希(tls-server-end-point)纳入 client-final-message 的 c= 字段,使其参与 AuthMessage,进而绑定 ClientProof 和 ServerSignature。这样客户端证明自己知道密码的同时,也把这次证明绑定到了它实际看到的 TLS 服务端身份。高安全场景应使用 sslmode=verify-full + channel_binding=require。

关键词:channel binding,SCRAM-SHA-256-PLUS,中间人,tls-server-end-point | 来源:202606/20260601_18.md

Q:SECURITY DEFINER 函数为什么必须固定 search_path?

SECURITY DEFINER 函数以函数 owner 的高权限执行,如果 search_path 含不可信 schema,攻击者可在可写 schema 中放置同名对象(表、函数、操作符),诱导函数在运行期解析到恶意对象,实现权限提升。因此必须 SET search_path 为受信 schema 加 pg_temp(且 pg_temp 放最后),函数体内对象尽量 schema-qualified,并 REVOKE PUBLIC 默认执行权限后仅授予明确角色。

关键词:SECURITY DEFINER,search_path,pg_temp,权限提升,search_path劫持 | 来源:202606/20260601_17.md

Q:anon 和 sepgsql 这两个 security label provider 分别是做什么的?

两者都是 PG 的 security label(安全标签)provider,通过 SECURITY LABEL 机制工作。anon 用于数据脱敏/匿名化,可对列配置脱敏规则,让非授权用户看到脱敏后的值;sepgsql 是基于 SELinux 的强制访问控制(MAC)provider,把 SELinux 安全上下文标签绑定到数据库对象,实现操作系统级的安全策略强制执行。它们与 pgsodium 类似,都借助 label provider 扩展 PostgreSQL 的安全语义。

关键词:anon,sepgsql,security label,脱敏,SELinux,MAC | 来源:202307/20230707_01.md

Q:column_encrypt 扩展的 KEK/DEK 两层密钥模型是怎么设计的?

column_encrypt 采用两层密钥:外层 KEK(key encryption key / master passphrase)不存数据库,由外部 KMS 或应用注入;内层 DEK(data encryption key)用于实际加密列数据,DEK 密文(被 KEK 包裹)才存库。列密文头带 2 字节 key version 支撑轮换。这样即使拿到数据库表和数据文件,没有 KEK 也无法解开 DEK,从而保护敏感列。它还通过 session keyring 控制谁能读明文,用 SECURITY DEFINER 与 column_encrypt_user 角色收口权限。

关键词:column_encrypt,KEK,DEK,列加密,密钥轮换,key version | 来源:202604/20260416_06.md

Q:column_encrypt 的 blind index 是做什么的?有什么安全代价?

blind index(盲索引)用于在加密列上支撑等值查询:对明文计算一个确定性/带密钥的摘要值单独存储并建索引,查询等值时匹配摘要而非解密密文。代价是相同明文产生相同 blind index,攻击者可通过摘要分布推断频率,对低基数字段(性别、状态、地区)不适合。同时它不支持范围查询,这是有意为之的设计取舍。

关键词:column_encrypt,blind index,盲索引,等值查询,频率泄露 | 来源:202604/20260416_06.md

Q:credcheck 插件如何加强 PostgreSQL 用户名与密码安全策略?

credcheck 是一个密码/用户名校验插件,可在建角色或改密码时强制执行安全策略:如密码最小长度、复杂度、禁止使用用户名作为密码、禁止常见弱口令、限制密码有效期等。它通过 hook 在密码写入前做检查,从源头阻断弱密码进入系统,是对 SCRAM 等认证机制在「密码质量治理」层面的补充。

关键词:credcheck,密码策略,弱口令,复杂度,用户名校验 | 来源:202107/20210708_02.md

Q:pg_dump 导出带 RLS 行安全策略的表时为什么要加 –enable-row-security?

RLS 表在 pg_dump 导出时,默认 dump 进程运行在会绕过 RLS 的语境(或受策略影响)下,可能报错或导不出数据。加 –enable-row-security 开关后,pg_dump 明确以启用行安全策略的方式读取,从而正确导出符合策略可见的数据。因此导出带 RLS 策略的表时必须显式带上该开关,否则会因策略拦截而失败。

关键词:RLS,pg_dump,–enable-row-security,行级安全,导出 | 来源:202109/20210929_02.md

Q:pg_restrict 插件如何实现更精细的 ACL 访问控制?

pg_restrict 提供 master_roles 等配置,形成一套更细粒度的访问控制层。它允许指定若干「master」角色,只有 master 角色成员才能执行受限的 DDL/管理操作,普通用户即使拥有对象权限也会被拦截,从而把「谁能改结构/谁能管理」这类操作从原生 ACL 中剥离出来单独管控,实现类似「白名单角色」的精细化授权。

关键词:pg_restrict,master_roles,ACL,精细化权限,DDL管控 | 来源:202005/20200527_05.md

Q:pgcrypto 的 pgp_sym_encrypt / pgp_sym_decrypt 如何做对称加密?

pgp_sym_encrypt 用口令对文本做 OpenPGP 对称加密,返回 bytea 密文,可通过选项指定 cipher-algo(如 aes256)、compress-algo/compress-level、s2k-mode、s2k-count 等。pgp_sym_decrypt 用相同口令解密,口令错误会报「Wrong key or corrupt data」。它适合存少量敏感值(如账号 token),但要注意密钥容易进入 SQL 文本或日志,生产更推荐配合外部密钥管理。

关键词:pgcrypto,pgp_sym_encrypt,pgp_sym_decrypt,对称加密,aes256 | 来源:202006/20200603_01.md

Q:pgsodium 是什么?它如何利用 security label 实现字段透明加解密?

pgsodium 是基于 libsodium 的 PG 扩展,提供 Server Key Management 和透明列加密 TCE。它通过 register_label_provider 注册 pgsodium label provider,用户用 SECURITY LABEL FOR pgsodium ON COLUMN … IS ‘ENCRYPT WITH KEY …’ 标记列,事件触发器(ddl_command_end)据此生成 BEFORE INSERT/UPDATE 加密触发器和解密视图。业务表存密文,应用通过解密视图读明文,密钥由启动时加载的 root key 派生,raw key 不经 SQL 暴露。

关键词:pgsodium,libsodium,security label,TCE,字段加密,root key | 来源:202307/20230707_02.md

Q:supa_audit 插件如何实现记录审计与版本跟踪?

supa_audit(Generic Table Auditing)是一个审计插件,可对指定表自动记录数据变更历史:每次 INSERT/UPDATE/DELETE 时把变更前后的记录、操作类型、时间、操作者等写入审计表,形成可回溯的版本跟踪。相比 pgaudit 记录 SQL 语句,supa_audit 更偏「行级数据审计/版本」,适合需要追溯每行数据变化历史的合规场景。

关键词:supa_audit,审计,版本跟踪,行级审计,数据变更 | 来源:202401/20240125_03.md

Q:为什么参数化查询能防 SQL 注入,而手写转义只是兜底?

参数化查询(如 libpq 的 PQexecParams、驱动占位符、EXECUTE … USING)让 SQL 模板和参数值分通道进入数据库:解析器只解析模板,参数值由类型输入函数处理,不参与 SQL 语法切分,因此攻击者输入的内容只是值而非语法。而转义只处理字符串字面量问题,处理不了标识符、排序方向、第二条语句、search_path 劫持、动态 SQL 等。真正的目标是让用户输入在整个生命周期里保持为值。

关键词:SQL注入,参数化,占位符,转义,PQexecParams,类型输入 | 来源:202606/20260601_17.md

Q:为什么在 PG 里有时不需要密码就能连接数据库?

这由 pg_hba.conf 的认证方法决定:trust 方法对匹配的连接无条件放行(不需要密码);peer 方法在本地套接字上通过操作系统用户名与数据库用户名匹配直接认证;ident 通过 ident 协议认证。这些都是「无需密码」的合法配置。所以「不需要密码就能连」通常是 HBA 配了 trust/peer 且规则命中,需要按安全要求收紧 HBA 规则。

关键词:trust,peer,ident,pg_hba.conf,无密码连接 | 来源:202112/20211220_06.md

Q:为什么字段加密推荐用 AEAD(认证加密)而不是只加密?

只加密只保证「看不懂」,但攻击者可能篡改密文、nonce 或上下文字段,系统无法发现。AEAD(如 ChaCha20-Poly1305、XChaCha20-Poly1305、SIV 类)同时提供保密性和完整性认证,读取时若密文/nonce/associated data 被篡改,认证校验失败会报错而不是返回伪造明文。pgsodium 的 TCE 还支持 ASSOCIATED (tenant_id, secret_name) 把上下文绑定进认证,防止密文跨行搬移攻击。

关键词:AEAD,ChaCha20,Poly1305,认证加密,associated data,nonce | 来源:202606/20260601_19.md

Q:为什么说 PostgreSQL 的审计功能还有巨大增强空间?

DB 吐槽大会指出 PG 原生审计能力偏弱:缺少内置的细粒度 SQL 审计(谁在什么时候对什么对象执行了什么、影响多少行),通常要依赖 pgaudit 等外部扩展,而外部扩展在对象粒度、语句类型覆盖、审计日志的存储与检索、权限审计等方面仍不完善。相比商业数据库原生的审计中心,PG 需要更强的内置审计与合规能力。

关键词:审计,pgaudit,DB吐槽,SQL审计,合规 | 来源:202109/20210929_06.md

Q:为什么说不建议用 superuser 维护 PG?有哪些内置角色可以替代?

superuser 拥有最高权限,一旦被应用或运维脚本误用,容易造成误删、越权、安全失控。PG 提供了多个内置预制角色来替代 superuser 的常见用途:pg_read_all_data/pg_write_all_data(全库读写)、pg_monitor(监控视图)、pg_signal_backend(取消/终止后端)、pg_maintain(维护操作)、pg_create_subscription(建订阅)等。用这些角色按需授予,能实现最小权限、缩小爆炸半径。

关键词:superuser,内置角色,pg_monitor,pg_signal_backend,最小权限 | 来源:202509/20250920_03.md

Q:字段加密到底解决什么问题?它不能解决什么?

字段加密回答的是窄问题:当表文件、备份、WAL、逻辑导出或只读副本落到不该拿到的人手里时,敏感字段是否仍是明文。它不能解决:已有解密视图权限的账号读明文、应用被入侵后正常查询读明文、超级用户/root/调试器读进程内存、以及业务仍要对密文做范围/模糊查询的需求。所以字段加密是威胁模型选择,牺牲查询能力和运维便利,换取离线副本泄露后的损失收敛。

关键词:字段加密,威胁模型,离线副本,明文,范围查询 | 来源:202606/20260601_19.md

1.14 其他 / 技术杂项(65 条)

Q:Anti Join 的 join 顺序为什么不能像 inner join 一样随便重排?它的物理实现有哪些?

Anti Join 的右侧只用于否决左侧行,如果把右侧提前或滞后到错误位置,可能改变「哪些左侧行被认为存在匹配」的范围。PostgreSQL 用 SpecialJoinInfo 记录外连接、Semi Join、Anti Join 的约束,保存在 PlannerInfo.join_info_list 中,供 join_is_legal 排除非法 join order,因此复杂查询里反连接会限制搜索空间。JOIN_ANTI 是逻辑算子,可落成 Hash Anti Join、Merge Anti Join、Nested Loop Anti Join、Hash Right Anti Join 等物理形态。执行器语义统一:对当前外侧行查找匹配,命中即丢弃(Hash join 设 HJ_NEED_NEW_OUTER,Nestloop 设 nl_NeedNewOuter),候选查完仍无匹配才输出。成本上「有匹配」可提前停,「无匹配」则必须完整探测,因此 Anti Join 的成本风险主要在确认不存在这一步。

关键词:Anti Join,SpecialJoinInfo,join order,Hash Anti Join,Merge Anti Join,Nested Loop Anti Join | 来源:202605/20260530_38.md

Q:EXISTS、IN、= ANY 这三个写法与 Semi Join 是什么关系?它们的 NULL 语义有何区别?

EXISTS 的结果只取决于子查询是否返回至少一行;IN 等价于 = ANY;ANY 只要任意一行比较为 true 就为 true。解析/分析阶段它们分别对应 EXISTS_SUBLINK、ANY_SUBLINK(IN 是 = ANY 的一种)。三者都可能被优化器识别并转成 JOIN_SEMI。NULL 语义上:IN 和 ANY 在「无匹配但存在 NULL 比较结果」时可能返回 NULL 而不是 false,因此并非任何时候都能等价为二值逻辑的半连接;EXISTS 则按子查询是否返回行判断,NULL 风险更低。这也是实践上「表达存在」优先写 EXISTS 的原因——语义清晰且最贴近 Semi Join 入口。

关键词:Semi Join,EXISTS,IN,ANY,SubLink,NULL语义,JOIN_SEMI | 来源:202605/20260530_37.md

Q:EXPLAIN ANALYZE 显示 quicksort 和 external merge 有什么区别?如何据此调优 work_mem?

显示 Sort Method: quicksort 说明数据完全在内存完成,Memory 表示峰值内存;显示 Sort Method: external merge Disk 说明输入超过 work_mem 落了盘,产生了临时文件和归并 pass。调优方向:work_mem 太小会产生更多 run 和 merge pass、临时 IO 增加;work_mem 太大则每个排序/哈希节点、每个并行 worker 都有自己的预算,会把并发查询推入内存压力甚至 OOM。排序比较器本身也可能很贵(多列、复杂 collation、宽 tuple、pass-by-reference 类型)。另外注意:SQL 结果需要稳定同 key 顺序时必须显式写 tie-breaker(如追加主键),不要依赖排序算法稳定性。若索引或上游节点已提供目标顺序,优化器可能直接避免显式 Sort。

关键词:external merge,quicksort,work_mem,临时文件,EXPLAIN ANALYZE,Sort Method,tie-breaker | 来源:202605/20260530_30.md

Q:Incremental Sort 的前提是什么?它的成本模型有什么风险?

前提不是「有索引」,而是下层路径的 pathkeys 覆盖了目标排序键的前缀,顺序可能来自 B-tree Index Scan、GiST 距离扫描、上游 Sort、MergeAppend、Merge Join 外侧等。优化器用 pathkeys_count_contained_in() 判断:目标 pathkeys 被完全覆盖则无需排序,只覆盖前缀且 enable_incremental_sort=on 时构造 IncrementalSortPath。成本模型(cost_incremental_sort)先估算前缀键把输入切成多少个 group(estimate_num_groups),再估算单组 tuplesort 成本并乘以组数,加上分组检测、tuple copy、tuplesort_reset 的额外成本。核心风险是 input_groups 估计:统计信息低估组大小会以为每组很小、实际遇到少数巨型组;高估组数则会低估频繁 reset 的开销。

关键词:Incremental Sort,pathkeys,estimate_num_groups,cost_incremental_sort,enable_incremental_sort,tuplesort_reset | 来源:202605/20260530_31.md

Q:Incremental Sort(增量排序)解决什么问题?它的核心思想是什么?

它解决「目标排序键有多列,而输入已经按前若干列有序」的问题。普通排序把 N 行按完整 key 从零排,全部排完才能输出;Incremental Sort 则把输入按已有序的前缀键(如索引扫描已按 hundred 输出)切成连续的前缀组,只在每组内补排后缀列,排完一组即可输出一组。收益有三:更低启动延迟(LIMIT 特别受益)、更低峰值内存(更可能落在 work_mem 内)、更低落盘概率。EXPLAIN 里显示 Sort Key(完整目标键)和 Presorted Key(下层已保证的前缀键)。代价是要检测前缀组边界带来 tuple copy/比较成本,小组极多时频繁 reset tuplesort 会抵消收益,且成本模型依赖前缀组数估计,统计信息不准时可能选错计划。

关键词:Incremental Sort,增量排序,presorted key,work_mem,LIMIT,tuplesort,前缀有序 | 来源:202605/20260530_31.md

Q:LATERAL JOIN 解决什么问题?它有哪些语义要点和代价?

LATERAL 解决「依赖式 FROM 项」问题:右侧 FROM 项的输入参数来自左侧已产生的行。典型场景包括每行取子表 Top-N、每行调用返回集合的函数(如 jsonb_array_elements、unnest)、每行执行低代价派生查询、用 LEFT JOIN LATERAL … ON true 保留无匹配外侧行。四个语义要点:右侧 LATERAL 项只能引用左侧已可见的 FROM 项(从左到右解析);对每个外侧行右侧重新求值;FROM 中函数参数天然可引用左侧,LATERAL 关键字对函数可选;组合 join 类型必须是 INNER 或 LEFT。代价是依赖关系限制 join 顺序,参数化内侧路径通常在 Nested Loop 内部反复执行,外侧行多、内侧无索引、右侧结果集大时可能把一次大扫描变成大量小扫描。

关键词:LATERAL JOIN,依赖式FROM项,参数化路径,Nested Loop,Left Join Lateral,横向引用 | 来源:202605/20260530_39.md

Q:LATERAL 在 PostgreSQL 优化器里如何建模依赖并生成执行计划?

解析阶段从左到右处理 FROM,新 FROM 项先标记为 lateral_only(只对 LATERAL 表达式可见),处理完整个 FROM 列表才变成普通可见;函数 RTE 只要参数引用了同层外侧变量,即使没写 LATERAL 也会被标记为 lateral。进入优化器后,create_lateral_join_info() 为每个 base relation 填充 direct_lateral_relids、lateral_relids(传递闭包,X 依赖 Y、Y 依赖 Z 则 X 依赖 Z)和 lateral_referencers,用 lateral_relids 限制 join 顺序——被引用的外侧关系必须先算。随后优化器为含 lateral 引用的 RTE 生成参数化路径,这类路径必须由外侧关系提供参数。计划生成阶段 create_nestloop_plan() 把外侧 Var/PlaceHolderVar 替换成 NestLoopParam(PARAM_EXEC),执行期由 Nested Loop 给内侧填参数并重扫。

关键词:lateral_relids,参数化路径,PARAM_EXEC,NestLoopParam,create_lateral_join_info,lateral_only | 来源:202605/20260530_39.md

Q:LEFT JOIN 在什么条件下会被优化器降级为 inner join 或删除?

两类改写。一是外连接降级(reduce_outer_joins):当 WHERE 条件对右表列施加严格条件时,如 LEFT JOIN b ON … WHERE b.y=42,若 = 是严格操作符,b.y 为 NULL 时条件不可能为 true,LEFT JOIN 为未匹配 a 行补出的 NULL 行必然被过滤,故可降级为 inner join;进一步若 WHERE b.z IS NULL 且能证明匹配行的 b.z 必非空,则实际表达的是 anti join。二是无用连接移除(remove_useless_joins):当 LEFT JOIN 右侧列不被上层引用、且能证明右侧在连接键上唯一(否则删除会改变重复行数)时,该 join 不改变结果行数,可整体删除。核心约束是必须先证明语义正确,不能只图看起来优雅。

关键词:外连接降级,reduce_outer_joins,无用连接移除,LEFT JOIN降级,inner join,唯一性证明 | 来源:202605/20260531_16.md

Q:PostgreSQL 14 为什么移除了 non-fast promotion?

fast promotion 在 9.3 引入后,non-fast promotion 就变成未文档化特性,主要留作调试或 fast promote 有问题时的应急手段。到 PG14 时多个版本已经验证 fast promote 足够稳定,再保留 non-fast promotion 没有意义,因此提交 b5310e4 将其移除。fast promote 只写一个轻量级 end-of-recovery 记录即完成提升,速度更快。

关键词:fast promote,non-fast promotion,PG14,end-of-recovery,提升 | 来源:202008/20200803_09.md

Q:PostgreSQL 14 引入 WaitLatch/WaitEventSet 优化了什么?

PG14 用 WaitLatch 和 WaitEventSet 统一了等待机制:此前 condition variable 等需要为每次等待创建长期 WaitEventSet,或硬编码等待,带来额外 epoll/kqueue 系统调用。引入后 WaitLatch 内部复用类似的 WaitEventSet,避免每次等待都做系统调用,也省去多余的内核描述符。例如 stats collector 的等待改为一个 WaitEventSet 管理 latch、postmaster death、socket 可读等事件。

关键词:WaitLatch,WaitEventSet,epoll,kqueue,condition variable,PG14 | 来源:202008/20200803_06.md

Q:PostgreSQL 15 引入 MERGE 语法解决什么问题?与 INSERT ON CONFLICT 有何关系?

MERGE 用于 ETL、数据合并等场景,根据匹配条件统一执行 INSERT/UPDATE/DELETE(WHEN MATCHED / WHEN NOT MATCHED 分支),语义比 INSERT … ON CONFLICT 更通用。ON CONFLICT 只能处理基于唯一约束冲突的 upsert,而 MERGE 可基于任意 join 条件做更复杂的同步。PG15 引入基础 MERGE,PG17 进一步支持 RETURNING 和 WHEN NOT MATCHED BY SOURCE。

关键词:MERGE,INSERT ON CONFLICT,ETL,数据合并,PG15 | 来源:202106/20210615_03.md

Q:PostgreSQL 17 有哪些值得期待的重量级特性?

PG17 亮点:pg_basebackup 支持块级增量备份(pg_combinebackup 重构,大库备份不必全量拷贝);逻辑复制 failover/switchover(0 丢失),pg_upgrade 可保留逻辑复制槽;COPY 支持 skip error row(SAVE_ERROR_TO);vacuum 引入 TidStore 打破 dead tuple 上限、省 20 倍内存并提速;btree 倒序扫描优化、brin 并行建索引;WAL 锁优化使高并发写入提升约 2 倍;MERGE 支持 RETURNING 和 WHEN NOT MATCHED BY SOURCE;新增 MAINTAIN 权限等。

关键词:PG17,增量备份,逻辑复制failover,TidStore,MERGE,MAINTAIN | 来源:202404/20240411_01.md

Q:PostgreSQL 17 的 TidStore 数据结构改进了什么?

vacuum 需要记录 dead tuple 的 tids,之前用数组存储有上限(对应单表记录数受限,旧说法约 8.9 亿条)。PG17 引入 TidStore 数据结构,只要内存足够,dead tuple ids 不再有固定上限,索引不再需要被多次扫描,相比以往能节省约 20 倍内存,并大幅提升 vacuum 效率,一定程度缓解 xid wraparound 问题。

关键词:TidStore,vacuum,dead tuple,内存,索引扫描,xid wraparound | 来源:202404/20240411_01.md

Q:PostgreSQL 18 的 AIO 子系统在 io_method 上有哪些选择?

PG18 新增 io_method GUC,可选 sync(旧的同步 IO)、worker(专用 IO 工作进程,通过 io_workers 配置数量,主后端入队请求后继续执行)、io_uring(仅 Linux,用内核 io_uring API 提交和完成 IO,无需单独工作进程)。配套参数 io_combine_limit/io_max_combine_limit 控制单次请求可合并多少相邻块,effective_io_concurrency 默认提到 16。可用 pg_aios 视图监控进行中的异步 IO。

关键词:io_method,io_uring,worker,io_combine_limit,pg_aios,AIO | 来源:202509/20250912_05.md

Q:PostgreSQL 18 的 AIO 目前覆盖哪些场景,写操作呢?

PG18 中 AIO 覆盖顺序扫描、bitmap heap scan 以及 VACUUM 等维护操作(配合 ReadStream 预读)。写操作目前保持同步。AIO 通过并发发起多个读请求,减少云盘/网络存储高延迟下的 CPU 空闲,冷缓存场景读取性能可提升一倍到三倍,云环境收益尤其明显。

关键词:AIO,顺序扫描,bitmap heap scan,VACUUM,ReadStream,写同步 | 来源:202509/20250912_05.md

Q:PostgreSQL 18 被谈及最多的三个特性是什么?

  1. 异步 I/O(AIO):让后端并发发起多个读请求,云盘/网络存储下 OLAP 查询性能显著提升;2) UUID v7(uuidv7()):时间戳编码在最高 48 位,分布式无协调生成且时间有序,插入在 B-tree 右侧聚集,索引局部性好、减少 WAL 和页分裂;3) OAuth 2.0 身份验证:pg_hba.conf 新增 oauth 方法,接受 RFC 6750 bearer token,配合 oauth_validator_libraries 验证,支持企业 SSO。

关键词:PG18,AIO,UUID v7,uuidv7,OAuth 2.0,bearer token | 来源:202509/20250912_05.md

Q:PostgreSQL 为什么需要 TOAST?它如何做到「行不能跨页」却仍能存大字段?

PostgreSQL 使用固定页面大小(常见 8 KB)且不允许物理 tuple 跨多个页面,大字段无法直接无限放进主表行。TOAST(The Oversized-Attribute Storage Technique)把问题改写为主表行保持短小、大值先压缩、必要时切成小 chunk 存到关联的 TOAST 表,主表只保存一个 18 字节的 on-disk 指针。指针(varatt_external)包含 va_rawsize(原始大小)、va_extinfo(外部大小+压缩方法)、va_valueid(chunk_id)、va_toastrelid(TOAST 表 OID)。TOAST 表只有 3 列 chunk_id(oid)、chunk_seq(int4)、chunk_data(bytea),并有唯一 B-tree 索引 (chunk_id, chunk_seq) 供 detoast 按序重组。

关键词:TOAST,大字段,页面跨行,chunk,varatt_external,8KB,TOAST表 | 来源:202605/20260525_07.md

Q:PostgreSQL 从库的刷脏策略由哪些参数控制?

从库的脏页刷新分两类:Background Writer 相关(bgwriter_delay、bgwriter_lru_maxpages、bgwriter_lru_multiplier、bgwriter_flush_after)控制常规脏页刷新;Restartpoint 相关(checkpoint_timeout、checkpoint_completion_target、checkpoint_flush_after)控制重启点期间的刷盘。WAL buffer 由 wal_writer_delay 和 wal_writer_flush_after 单独控制。这些参数可在 postgresql.conf 设置,多数 SIGHUP 重载生效。

关键词:从库,刷脏,bgwriter,restartpoint,checkpoint_timeout,wal_writer | 来源:202603/20260310_01.md

Q:PostgreSQL 单个 varlena 值为什么上限约 1 GB?什么时候才会真正触发 TOAST?

varlena 头部要用两个 bit 标记短头、压缩、外部指针等特殊形态,导致 TOAST-able 类型单个 datum 的逻辑大小上限变成 2^30-1 字节,即约 1 GB(这不是 TOAST 表总大小上限,表本身可增长到很多 segment)。触发条件不是「字段超过 2 KB 就一定外置」:TOAST 判断的是整行是否过宽(默认 8KB block 下 TOAST_TUPLE_TARGET 约 2KB、TOAST_TUPLES_PER_PAGE=4),当待存行宽超过阈值时才触发,随后按列策略先压缩、再外置,直到行宽降到目标以下或没有收益。短值即使属于 text 也可能完全内联。

关键词:TOAST,varlena,1GB上限,TOAST_TUPLE_TARGET,触发条件,行宽 | 来源:202605/20260525_07.md

Q:PostgreSQL 外部归并排序(External Merge Sort)如何工作?run 是怎么生成的?

当输入超过 work_mem 时,tuplesort 进入外部排序:在 memtuples[] 中积累 tuple,超过 work_mem 后 dumptuples() 把当前内存批次排序成一条有序 run,写入 logical tape(logtape.c),清空内存继续接收下一批;输入结束后对多条 run 做 balanced k-way merge 输出全局有序结果。关键澄清:当前外部排序不是所有阶段都用 mergesort——run 内部由 quicksort 或 radix sort 排序(tuplesort_sort_memtuples 对整数类 leading key 用 radix、单 key fast path 用 qsort_ssup、通用多列用 qsort_tuple),run 之间才是 balanced k-way merge。所以 EXPLAIN ANALYZE 里同时出现 quicksort 和 external merge 并不矛盾。状态机从 TSS_INITIAL 切到 TSS_BUILDRUNS 生成 run,TSS_SORTEDONTAPE 表示最终结果在 tape,TSS_FINALMERGE 表示边归并边返回、省掉最终物化的一轮 IO。

关键词:外部归并排序,External Merge Sort,tuplesort,work_mem,logical tape,k-way merge,run | 来源:202605/20260530_30.md

Q:PostgreSQL 大对象(large object)为什么需要?和 bytea 有什么区别?

大对象本质是带 ACID 的文件操作 API 封装。bytea 一行最多存 1GB,而大对象可存超过 1GB 的单个文件;大对象支持 seek 局部读写(普通类型只能整体 replace);支持稀疏写入(seek 到 10GB 只写 1MB 只占 1MB,未写 block 读返回 0)。大对象数据存 pg_largeobjects 表,通过 OID 引用,一个 OID 可被多条记录引用。注意删除记录往往只删引用不删大对象本体,需用 lo_unlink(oid) 或 lo 插件的触发器自动清理。

关键词:大对象,large object,bytea,OID,lo_unlink,稀疏写入 | 来源:202012/20201205_01.md

Q:PostgreSQL 如何在十进制、十六进制、二进制、八进制之间转换?

十进制转十六进制用 to_hex(10)=‘a’,转二进制用 10::bit(4)=‘1010’(注意 bit(n) 长度不足会截断,如 10::bit(1)=‘0’)。十六进制转十进制用 x’A’::int=10,转二进制用 x’A’::bit(4)=‘1010’。二进制转十进制用 B'1010’::int=10,转十六进制用 to_hex(B'1010’::int)=‘a’。varbit 类型如 x’bcd’::varbit 可得到变长二进制串。

关键词:to_hex,bit,varbit,进制转换,十六进制,二进制 | 来源:202012/20201205_02.md

Q:PostgreSQL 如何用自关联外键表达树形元数据结构?

在表里让 parent_id 列 REFERENCES 同一张表(self-referential foreign key)。例如 CREATE TABLE tree(node_id int PRIMARY KEY, parent_id int REFERENCES tree, name text),顶层节点的 parent_id 为 NULL,非顶层节点的 parent_id 必须指向已存在的行。可扩展多个自关联外键表达多汇报关系(实线/虚线汇报)。插入不存在的父节点会报违反外键约束。

关键词:自关联外键,树形结构,REFERENCES,parent_id,PRIMARY KEY | 来源:202105/20210501_01.md

Q:PostgreSQL 存在哪些单核瓶颈场景?

PG 虽支持并行查询,但仍有一些单核路径:WAL writer、vacuum 单表/单分区、checkpointer、崩溃 recovery、bgwriter。写压力大时可能撞上 data block extend exclusive lock 或 wal insert exclusive lock;大表高并发更新会导致 vacuum 赶不上垃圾产生速度,引发表膨胀;shared_buffer 大且脏页多时 checkpoint 周期长,崩溃恢复需重放大量 WAL。缓解靠拆库、拆表/分区、用更快的 SSD,未来方向是内核支持更并行化的后台任务。

关键词:单核瓶颈,WAL writer,vacuum,checkpointer,recovery,表膨胀 | 来源:202109/20210930_02.md

Q:PostgreSQL 孤儿文件(orphaned file)是怎么产生的?如何发现和清理?

孤儿文件类似内存泄露:数据库崩溃时有未提交事务(内含 DDL 和大量导入),重启后 pg_class 等元数据回滚,但对应数据文件未被清理。典型场景:pg_dump 导入中崩溃、事务内建表写大量数据后提交前崩溃。发现时不能用 pg_class.oid 直接对照文件名,因为 table rewrite(vacuum full、cluster、alter table)后 filenode 会变,正确做法是用 pg_relation_filenode(pg_class.oid) 得到真实文件名再对照 pg_ls_dir 列出的文件名。

关键词:孤儿文件,orphaned file,pg_relation_filenode,filenode,table rewrite | 来源:202406/20240621_01.md

Q:PostgreSQL 异步提交(synchronous_commit=off)有哪些风险点?

异步提交指事务返回成功后 WAL 可能尚未持久化,风险是数据丢失而非数据损坏:最多丢失约 3 倍 wal_writer_delay 时间内的 WAL(且小于 wal_buffer)。OOM、shutdown immediate、数据库/服务器 crash 都会导致 wal buffer 内容丢失。DDL 和 2PC 事务强制同步提交不受影响。业务有逻辑依赖(后续事务依赖前面事务的提交)时要注意 crash 后「已提交」事务可能回退。任何情况都不要用 fsync=off(那会破坏一致性导致 corruption)。

关键词:异步提交,synchronous_commit,wal_writer_delay,数据丢失,fsync | 来源:202102/20210219_03.md

Q:PostgreSQL 引入 Direct I/O 和 Asynchronous I/O 的动机分别是什么?

Direct I/O 的动机:降低 CPU 开销(避免内核 page cache 到 shared buffer 的拷贝,可用 DMA)、避免 OS cache 与 shared_buffers 双份缓存、更好地控制脏数据写回时机、支持 WAL 并发写。AIO 的动机:没有 AIO 就无法用 DIO;AIO 让启动 IO 与等待结果分离,可并发发起多个 IO 并在等待时执行 CPU 任务,对 fdatasync 这类操作系统无法隐藏延迟的操作用异步发出能显著提升吞吐,尤其是 WAL 写入。

关键词:Direct IO,Asynchronous IO,AIO,DIO,page cache,双缓冲 | 来源:202102/20210224_03.md

Q:PostgreSQL 有哪些数据扫描方法?分别适用什么场景?

常见扫描类型:Seq Scan 顺序扫描读全表,适合小表或返回行占比较高;Index Scan 索引扫描两步(查索引+回表取行),适合大表取少量行;Bitmap Index Scan + Bitmap Heap Scan 位图扫描,先把匹配的索引页聚成位图再按物理顺序读堆页,适合命中行数中等、多列各自有索引用 AND/OR 连接;Parallel Seq Scan 并行顺序扫描,把表分块给多个 worker 同时扫再 Gather 汇总,适合大表。约返回 10% 行以上时顺序扫描往往更快。

关键词:扫描方法,Seq Scan,Index Scan,Bitmap Scan,Parallel Seq Scan | 来源:202512/20251212_08.md

Q:PostgreSQL 物理从库有检查点吗?它叫什么?

物理从库没有自己的 checkpoint,但有类似机制叫 restartpoint(重启点)。从库的 checkpointer 进程在恢复期间执行的是 restartpoint 而非新 checkpoint。它不能创建新的 checkpoint 记录,只能在回放到主库的 checkpoint 记录位置时执行 restartpoint,且受 checkpoint_timeout 时间条件限制,可能跳过。restartpoint 用于回收 WAL 文件、刷新脏页、更新 pg_control,避免崩溃后重扫大量 WAL。

关键词:restartpoint,checkpoint,standby,checkpointer,恢复 | 来源:202603/20260308_01.md

Q:PostgreSQL 的 query rewrite(查询重写)发生在哪几个层次?与规则系统是什么关系?

可分成三层。第一层是「查询规则重写」,位于 src/backend/rewrite,处理视图展开、自定义规则、行安全策略(RLS)、可更新视图改写等,入口是 QueryRewrite(),它位于 parser 之后、planner 之前。第二层是 planner preprocessing,位于 optimizer/prep 与 planner.c,做 ANY/EXISTS 拉起、函数 RTE 内联、子查询 pull-up、外连接降级等,典型调用顺序见 prepjointree.c:pull_up_sublinks → preprocess_function_rtes → pull_up_subqueries → flatten_simple_union_all → reduce_outer_joins → remove_useless_result_rtes。第三层是 planner simplification,在统计信息可用后进一步删减搜索空间(如无用左连接移除、唯一性证明)。规则系统是用户可定义的语义展开,preprocessing 则是 planner 内部的语义保持变换,两者容易被混淆。

关键词:query rewrite,规则系统,视图展开,planner preprocessing,pull_up_subqueries,reduce_outer_joins | 来源:202605/20260531_16.md

Q:PostgreSQL 的 simplehash 和 dynahash 各有什么优缺点?

dynahash 的优点:支持分区(便于共享内存加锁访问)、共享内存哈希启动时分配固定区域且可被其他进程按名称发现、冲突时不移动条目对大条目性能更好、保证稳定指针。simplehash 的优点:模板化生成、无间接函数调用(小条目更快)、开放寻址有更好 CPU cache 行为、类型安全、在 MemoryContext 分配无需单独内存上下文,但不适合共享内存。简言之 dynahash 适合共享内存大条目,simplehash 适合进程内小条目高性能。

关键词:simplehash,dynahash,开放寻址,共享内存,哈希表 | 来源:202008/20200803_02.md

Q:PostgreSQL 的 work_mem 到底什么时候释放?

work_mem 不是预分配、也不是申请后一直保留到事务结束的内存。它是排序/哈希等操作可用的软预算:用多少申请多少,超限转 spill 到磁盘,大量内存在 SQL 执行过程中就被提前回收,最晚在语句结束时由 executor 统一回收,一般不会等到事务提交。三类算子释放方式不同:Sort 边做边回收(bounded sort 淘汰、tape 用尽即释放),Hash Join 按 batch reset 批量回收,Hash Agg 在 tuple 级、spill batch 级和节点结束多粒度释放。

关键词:work_mem,内存释放,spill,Sort,Hash Join,Hash Agg | 来源:202603/20260323_03.md

Q:PostgreSQL 连接失败常见的排查点有哪些?

从网络到数据库逐层排查:客户端到数据库网络是否通、防火墙是否放行、listen_addresses 是否监听对应网段、客户端认证方法是否与 pg_hba.conf 一致、HBA 是否从上至下第一条匹配规则放行/拒绝、HBA 是否配置了允许该 ip/user/db 登录、用户是否有 login 权限、是否有 login hook 拦截。HBA 规则是自上而下匹配,命中第一条后不再看后续。

关键词:连接失败,pg_hba.conf,listen_addresses,login,防火墙 | 来源:202112/20211220_05.md

Q:Prepared Statement(绑定变量)在连接池事务级复用下为什么可能失效?

事务级连接池复用模式下,每个事务结束后后端连接可能切换给其他会话,下次请求用的可能是不同后端连接。而绑定变量(prepared statement)等会话级属性绑定在特定后端连接的会话上,连接切换后这些会话状态不复存在,导致绑定变量失效。代价是无法复用解析和计划,高并发下性能下降、CPU 上升。这也是 PG 期望内核支持共享会话状态连接池(类似 Oracle shared server)的原因。

关键词:绑定变量,prepared statement,连接池,事务级复用,会话属性 | 来源:202109/20210930_03.md

Q:SQL 在 PostgreSQL 中运行经过哪五个阶段?

五个阶段:解析 Parsing(文本转解析树,识别 SQL 句法成分但不知语义)→ 分析 Analysis(解析表/列引用、类型检查、权限检查,得到语义验证的查询树)→ 重写 Rewriting(视图展开、RLS 策略注入、自定义规则等自动转换)→ 规划 Planning(选择访问路径、连接顺序和连接算法,生成执行计划)→ 执行 Execution(执行器按计划产出结果)。

关键词:SQL执行,解析,分析,重写,规划,执行,Parsing,Planner | 来源:202511/20251107_13.md

Q:Semi Join(半连接)解决什么问题?它与「普通 join + DISTINCT」的区别是什么?

Semi Join 解决「存在性过滤」问题:保留左表中那些在右表能找到至少一个匹配的行,只输出左表行。它与 INNER JOIN + DISTINCT 的差别在于:INNER JOIN 关心「所有匹配行对」,右表一条订单匹配 3 笔支付就产生 3 个行对,业务还得再 DISTINCT 去重;Semi Join 只关心「右表是否至少存在一条匹配」,找到第一条就足够,右表重复不会放大输出。收益有三:避免重复放大、避免无用列传递、给执行器留下「首个匹配即停止」的空间(省 CPU/IO/内存)。牺牲是它不返回右表列,也不告诉匹配了哪一条;需要流水号、最近时间、匹配数量等字段时要改用普通 join、聚合、窗口函数或 LATERAL … LIMIT 1。

关键词:Semi Join,半连接,EXISTS,IN,ANY,存在性过滤,DISTINCT | 来源:202605/20260530_37.md

Q:TOAST 的四种 storage 策略(PLAIN/EXTENDED/EXTERNAL/MAIN)分别是什么含义?插入更新时的处理顺序?

pg_attribute.attstorage 控制列存储方式:PLAIN 禁止压缩也禁止外置(固定长度或禁止 TOAST);EXTENDED 允许压缩也允许外置,是默认主力策略,先压缩再外置;EXTERNAL 允许外置不压缩,利于大 text/bytea 的切片读取;MAIN 允许压缩但尽量留在主表,实在放不下才外置。插入/更新时 heap_toast_insert_or_update() 按四轮处理:先对 EXTENDED 列尝试内联压缩,若某 EXTENDED/EXTERNAL 列本身极大立即外置;整行仍超目标则继续外置 EXTENDED/EXTERNAL 列;还放不下才对 MAIN 列尝试内联压缩;最后仍放不下才外置 MAIN 列并使用更宽松目标。若 PLAIN 列导致行最终仍放不下,插入或更新会失败。

关键词:TOAST,storage策略,PLAIN,EXTENDED,EXTERNAL,MAIN,attstorage,外置 | 来源:202605/20260525_07.md

Q:pg_stat_statements 没有 p95/p99,如何估算 SQL 响应时间的百分位数?

pg_stat_statements 只统计执行次数、min/max/均值、标准差、总和。可假设数据服从某种分布来估算百分位数:正态分布用 X_p = μ + Z_p·σ(P90 Z=1.282、P95 Z=1.645、P99 Z=2.326);对数正态分布 X_p = e^(μ_L + Z_p·σ_L),其中 σ_L=√ln(1+(σ/μ)²)、μ_L=ln(μ)-σ_L²/2;均匀分布 X_p = min + p·(max-min);指数分布 X_p = -ln(1-p)/λ(λ=1/μ)。前提是分布假设合理,否则结果不准。

关键词:pg_stat_statements,p95,p99,百分位数,正态分布,对数正态 | 来源:202506/20250617_03.md

Q:pgbench 的 random_zipfian 用来生成什么分布的数据?

random_zipfian 生成有界 Zipfian 分布(离散幂律/长尾)随机数,用于模拟长尾模型,如热键集中的场景。parameter 越大分布越偏斜,靠近区间起点的值被抽中越频繁:抽到 k 与 k+1 的概率比为 ((k+1)/k)**parameter。例如 random_zipfian(1,…,2.5) 中 1 出现频率是 2 的 (2/1)**2.5≈5.66 倍。配合 permute 可把热值映射到随机位置,生成贴近真实的热点数据做压测。

关键词:pgbench,random_zipfian,Zipfian,长尾分布,幂律,permute | 来源:202105/20210519_03.md

Q:为什么 EXISTS 有时变成 Hash Semi Join、有时仍是 SubPlan?子查询拉起的收益和限制是什么?

pull_up_sublinks() 会尝试把顶层 WHERE/JOIN-ON 中的 ANY、EXISTS、NOT EXISTS 改写成 semi join 或 anti join,使子查询内部关系进入 rangetable、相关条件变成 join qual,从而让 planner 可以选择 hash/merge/nested loop、参与 join 顺序搜索和索引选择。但改写范围受限:它只在顶层条件中安全,因为嵌在复杂布尔表达式里的 ANY 涉及 NULL 时可能需返回 FALSE 或 NULL,不能简单改成 join;此外 NOT IN 尤其危险——右侧出现 NULL 时三值逻辑会改变结果,只有能证明 NULL 语义不被破坏才可转为 anti join。相关子查询含易失函数、CTE 物化边界等也会阻止改写,此时保留 SubPlan。

关键词:子查询拉起,pull_up_sublinks,Semi Join,Anti Join,NOT IN,NULL语义,SubPlan | 来源:202605/20260531_16.md

Q:为什么 NOT IN 遇到 NULL 时结果可能是 NULL 而不是 true?

这是三值逻辑问题。官方文档规定 NOT IN 在两种情况返回 NULL:左侧表达式为 NULL;右侧没有相等值但至少有一行让比较结果为 NULL。例如 SELECT 2 NOT IN (1, NULL) 的结果是 NULL,因为 2 和 NULL 比较(2=NULL)得到 unknown,而不是 false。在 WHERE 中 NULL 和 false 一样不保留行,所以 WHERE a.k NOT IN (SELECT b.k FROM b) 会「悄悄丢行」,与 NOT EXISTS 的语义不一致。要安全转成 Anti Join,必须证明外层表达式与子查询输出列都非空、且操作符对非 NULL 输入不会返回 NULL。这也是为什么列有明确 NOT NULL 约束时 NOT IN 才相对安全。

关键词:NOT IN,NULL,三值逻辑,unknown,Anti Join,NOT EXISTS,NULL语义 | 来源:202605/20260530_38.md

Q:为什么 NOTIFY 即使不在显式事务里也会触发同样的全局锁问题?

因为单条 NOTIFY 语句自带隐式事务(每执行一条语句 PG 会隐式开启并提交一个事务,txid 会递增)。所以即便没有 BEGIN…COMMIT,NOTIFY 仍然在隐式事务的提交阶段获取那个 database 0 的 AccessExclusiveLock,全局锁问题依旧存在。

关键词:NOTIFY,隐式事务,全局锁,txid,提交阶段 | 来源:202507/20250723_07.md

Q:为什么 PG 高并发短连接、大量连接写小事务性能差?

PG 是进程模型,每个新建连接在服务端 fork 一个新进程对接,频繁建连断开导致 fork/资源开销大。大量连接写小事务还伴随锁竞争和 WAL 竞争。缓解:在业务和数据库之间加连接池(如 pgbouncer),用事务级复用模式。代价是多一跳增加 RT,且事务级复用下会话级属性(绑定变量、临时表、SET 等)无法跨连接保留,可能降低高并发性能。

关键词:进程模型,连接池,pgbouncer,高并发短连接,fork | 来源:202109/20210930_03.md

Q:为什么 PostgreSQL 的 count(*) 查询慢?

PG 没有行数计数器,count 必须真正扫描数据(seq scan/index scan/index only scan/bitmap scan),IO/CPU/内存开销大。不引入计数器是因为:计数器更新会成为并发写入热点影响插入删除性能、通常只能做全表计数场景有限、且计数器无版本信息无法满足 tuple 可见性判断(不符合 ACID)。优化:判断有无记录用 LIMIT 1 而非 count;实时 PV/UV 用 redis/物化视图/流计算;偶尔 count 用并行;静态日志/历史表用列存或 index only scan;行数估算用 reltuples/explain/采样/HLL。

关键词:count,计数器,seq scan,index only scan,可见性,行数估算 | 来源:202112/20211221_01.md

Q:为什么 Recall.ai 说 LISTEN/NOTIFY 在高并发写入下会「吃掉」CPU?

根源是 NOTIFY 在事务提交阶段会获取一个针对整个实例的全局锁:LockSharedObject(DatabaseRelationId, InvalidOid, 0, AccessExclusiveLock),即「object 0 of class 1262 of database 0」,横跨所有数据库所有对象。任何带 NOTIFY 的事务提交都会持有该排它锁,导致所有并发提交串行化。大量并发写入时表现为锁等待激增、CPU/IO 反而下降(都在等锁),造成「CPU 被吃」的假象。高扩展多写场景应避免在事务里用 LISTEN/NOTIFY。

关键词:LISTEN,NOTIFY,全局锁,AccessExclusiveLock,提交串行化,PreCommit_Notify | 来源:202507/20250723_07.md

Q:为什么 spill 到磁盘不一定是坏事?

spill 是 PG 在「内存安全」和「执行效率」之间的合理平衡:当排序/哈希工作集超预算时,把部分数据写到磁盘、降低内存压力,而不是让内存无限膨胀导致 OOM。如果看到 spill 就一味调大 work_mem,单个算子确实更少 spill,但复杂 SQL 有多个排序/哈希节点时整体内存峰值可能暴涨,并发一上来反而更危险。因此适度 spill 往往是更稳妥的选择。

关键词:spill,work_mem,内存安全,磁盘,OOM | 来源:202603/20260323_03.md

Q:为什么分布式场景推荐用 UUID v7 而不是 UUID v4 或自增 ID?

自增整数需要单一事实来源,分片/多主下协调序列号有网络延迟和单点风险。UUID v4 全局唯一、各节点独立生成,但完全随机导致插入分散到整个 B-tree,索引页分裂多、缓存命中差。UUID v7 把毫秒级时间戳放最高 48 位、其余随机,既本地生成无协调,又时间有序——同时刻生成的 ID 相邻,插入集中在 B-tree 右侧,减少 WAL 和页分裂,提高写入和缓存命中率,特别适合分布式水平扩展。

关键词:UUID v7,uuidv7,UUID v4,自增ID,B-tree,分布式 | 来源:202509/20250912_05.md

Q:为什么有的 SQL 用 pg_cancel_backend / pg_terminate_backend 都杀不掉?

后端不是瞬间响应中断信号,而是在安全点通过 CHECK_FOR_INTERRUPTS() 检查并处理 QueryCancel(SIGINT)/ProcDie(SIGTERM) 标志。若代码处于 HOLD_INTERRUPTS() … RESUME_INTERRUPTS() 区间(或 critical section),中断被推迟,直到离开 hold 区间后才处理。因此杀不掉往往是因为进程正处在不处理中断信号的阶段。可用 pstack 查看进程卡在哪段代码,确认是否调用了 hold 中断。

关键词:pg_cancel_backend,pg_terminate_backend,HOLD_INTERRUPTS,CHECK_FOR_INTERRUPTS,信号 | 来源:202112/20211220_07.md

Q:为什么用 telnet 探测 PG 端口会出现「invalid length of startup packet」日志?

telnet 只是建立 TCP 连接,不会发送符合 PG 协议的 startup packet,服务端收到不合法长度的启动包就报 08P01 invalid length of startup packet。这属于未遵循 PG 通信协议的探测方式,正常但会污染日志。建议改用 PG 官方探测客户端 pg_isready,它遵循 PG 协议更友好。

关键词:invalid length of startup packet,telnet,pg_isready,startup packet,协议 | 来源:202112/20211220_02.md

Q:为什么说 AIO 之后 PG 未来将大力发展 Direct I/O?

Direct I/O 绕过 OS page cache 层,避免了内核开销和可扩展性限制。实测中开启 debug_io_direct=‘data’ 后大表顺序扫描吞吐从约 3.7GB/s 提升到 6GB/s 且 CPU 占用更低,perf 显示耗时从内核转到 PG 内部。但 DIO 依赖 AIO(否则慢得不可用)、需要显式预取(ReadStream 已应用于顺序扫描/bitmap heap scan/VACUUM,普通索引扫描尚未支持),且 page cache 的写缓冲能力 AIO 目前也不支持写。因此 DIO 是方向但短期不会完全落地。

关键词:Direct I/O,page cache,debug_io_direct,ReadStream,预取,写缓冲 | 来源:202510/20251003_04.md

Q:为什么说 work_mem=64MB 不等于这条 SQL 最多只用 64MB?

work_mem 是每个排序/哈希操作的预算上限,而不是整个 SQL 或整个连接的总预算。一条 SQL 里可能有多个 Sort、多个 Hash Join、多个 Hash Agg,每个节点可分别使用自己的预算;叠加并行执行,实际内存消耗会成倍放大。另外 Hash 类操作还会乘 hash_mem_multiplier。所以内存峰值来自「同时申请预算的节点数量叠加」,这是调优 work_mem 最易踩的坑。

关键词:work_mem,预算上限,节点叠加,并行,hash_mem_multiplier | 来源:202603/20260323_03.md

Q:什么是 PG 的 Double Cache 问题?如何缓解?

PG 数据读写走 buffer IO,数据在 OS page cache 和 PG shared_buffers 各缓存一份,形成双重缓存,浪费内存,且 OS 层 bg write 调度不当还会导致 IO hang。缓解手段有限:调大 shared_buffer 并配 huge page、用 pgfincore 把 fd 的 adviceFlag 设为 POSIX_FADV_DONTNEED 尽快淘汰 page。根治要靠内核 DIO(PG16 引入 io_direct 开发者选项,存算分离架构如 PolarDB 用 DIO 解决)。

关键词:Double Cache,page cache,shared_buffers,pgfincore,DIO,io_direct | 来源:202108/20210828_06.md

Q:使用 Direct I/O 有哪些代价和不适用场景?

代价:没有 AIO 时 DIO 慢得无法使用;即便有 AIO 也要改造多处内核逻辑做显式预取;当 shared_buffers 无法设得足够大(如同一主机跑多个实例)时,DIO 性能往往反而不如 buffered IO。因此 DIO 不是无条件更好,需要 AIO 配合、shared_buffers 足够大、以及存储和预取逻辑支持才划算。

关键词:Direct IO,AIO,预取,shared_buffers,代价 | 来源:202102/20210224_03.md

Q:如何判断当前 PostgreSQL 数据库是否处于一致状态?

一致状态指所有数据块无 partial write(一半新一半旧),且不存在「此位点之前已提交事务不存在、之后提交事务存在」的错乱。判断方法:若初始化开启了 checksum,停库用 pg_verify_checksums 校验所有块;没开 checksum 则无法主动检测,只能查询到坏块时报错,可用 zero_damaged_pages 跳过。PITR 恢复时看日志是否打印 consistent recovery state reached;崩溃恢复要保证一致性需开启 fsync 和 full page write(COW 文件系统可不开 fpw)。可用 recovery_target=‘immediate’ 在到达一致位点后立即停止恢复。

关键词:一致性,checksum,pg_verify_checksums,zero_damaged_pages,fpw,recovery_target | 来源:202405/20240521_01.md

Q:如何用 RULE + LISTEN/NOTIFY 实现「垂帘听政」式异步消息预警?

在表上建 CREATE RULE,用 WHERE 条件过滤出异常数据(如传感器温度≥60、CPU≥80%),命中时 DO ALSO 执行 pg_notify 向通道发消息;再配合一条 DO INSTEAD NOTHING 规则把正常数据丢弃,从而大幅减少写入量。应用侧 LISTEN 该通道接收异步消息实时预警。相比定时器全量扫描,规则+异步消息避免了为发现问题数据建立大量索引和频繁轮询,实时性好。

关键词:CREATE RULE,pg_notify,LISTEN,异步消息,预警,规则过滤 | 来源:202105/20210530_01.md

Q:异步提交 + 异步流复制时,从库的 WAL 会不会超前于主库?

不会。PG 只会把已经持久化的 WAL 内容发送给从库。因此即使主库异步提交产生大量未持久化的 wal buffer,这些内容也不会被发给从库;主库 crash 重启后从库不会出现 WAL 比主库更前的情况。好处是从库不会因异步提交而出现 WAL 超前,坏处是从库延迟可能更大。

关键词:异步提交,异步流复制,WAL发送,持久化,从库 | 来源:202102/20210219_03.md

Q:异步提交和 commit_delay(组提交)有什么区别?

异步提交(synchronous_commit=off)在 WAL 落盘前就返回成功,牺牲持久性。commit_delay 其实是同步提交方法:它在事务 flush WAL 前延迟一小段时间,希望多个并发事务合并成一次 flush,均摊 fsync 成本(commit_delay 在异步提交时被忽略)。即异步提交降低持久性换吞吐,commit_delay 保持持久性但用组提交提升吞吐,两者机制和风险完全不同。

关键词:异步提交,commit_delay,组提交,commit_siblings,fsync | 来源:202102/20210219_03.md

Q:把数据库所有 superuser 都改成普通账号后,如何找回超级账号?

用单用户模式直接改系统目录:先 pg_ctl stop -m fast 停库,再 postgres –single 进入单用户 backend,执行 update pg_authid set rolsuper=true where rolname=‘postgres’; 即可把指定角色重新标记为 superuser,最后 pg_ctl start 启动。单用户模式绕过常规认证和权限检查,是找回超级账号的兜底手段。

关键词:单用户模式,pg_authid,rolsuper,superuser,找回超级账号 | 来源:202105/20210528_01.md

Q:把数据库服务器系统时间调小(往回调)有什么风险?

主要风险有三类:1) 事务 commit/abort 记录里的时间戳变小,PITR 按时间恢复时可能无法恢复到目标时间段(只能用 xid 指定恢复,因为 xid 始终自增);2) 用 now()/clock_timestamp() 作默认值的字段,在时间追平前,后插入记录的时间戳比先插入的小;3) autovacuum/autoanalyze、统计信息 reset 等系统时间戳短暂不准(影响小)。调大时间无影响。建议用 ntp/chrony 保持时钟准确。

关键词:系统时间,PITR,commit ts,now,clock_timestamp,时间戳 | 来源:202404/20240408_01.md

Q:数据库连接长时间空闲有时会自动断开,可能是什么原因?

常见原因是链路层设备(防火墙、负载均衡、NAT)设置了无数据包传输超时断开会话,而空闲连接确实不发包(或在等长 SQL 执行结果)。解决:调大设备超时,或配置数据库 TCP keepalive 心跳包频率。此外数据库侧 statement_timeout、lock_timeout、idle_in_transaction_session_timeout、idle_session_timeout 等参数也可能主动断开超时会话。

关键词:连接断开,keepalive,idle_session_timeout,statement_timeout,空闲连接 | 来源:202112/20211220_01.md

Q:用 HLL 类型做滑动窗口 UV 分析为什么能提速上千倍?

传统方案要存明细(每天每 gid 每个 uid),count(distinct) 计算 UV 和新增/流失用户需要扫描海量明细,几十秒到几分钟。HLL(HyperLogLog)类型只存近似基数摘要,每天每 gid 一条,存储从 4GB 缩到 2MB。UV 用 # hll_union_agg 计算,新增/流失用户用 hll_union 做并集后相减,毫秒级完成,精度约 97%~105%。代价是结果是近似值,但换来了存储和速度数量级提升。

关键词:HLL,HyperLogLog,UV,滑动窗口,count distinct,基数估计 | 来源:202106/20210614_01.md

Q:窗口函数滑动聚合的 inverse transition(反向转移函数)解决什么问题?代价是什么?

它解决「窗口帧头部移动」带来的重复计算。普通聚合只做 state=sfunc(state,row);窗口聚合作为 window function 时,相邻两行的窗口帧高度重叠(ROWS BETWEEN 59 PRECEDING AND CURRENT ROW 每次只少一条旧行、多一条新行)。没有 inverse transition 时,帧起点一动执行器就必须从头重算当前帧,代价 N×帧宽;有 MINVFUNC/MSFUNC 时,运行时间与输入行数成正比。代价:聚合状态必须支持删掉最早加入的输入值;moving mode 需要独立的 MSTYPE/MSFUNC/MINVFUNC/可选 MFINALFUNC/MINITCOND;反向撤销必须精确恢复状态;有些值无法撤销时 MINVFUNC 返回 NULL 会触发当前帧重算;对浮点、分位数、top-k、去重等聚合「撤销一行」往往不是简单减法。

关键词:inverse transition,Moving Aggregate,MSFUNC,MINVFUNC,滑动窗口,WindowAgg,窗口帧 | 来源:202605/20260531_11.md

Q:第 1 条 SQL 执行慢,为什么可能和缓存无关而和 preload libraries 有关?

使用插件功能(类型、函数、操作符、索引等)时需要加载插件库文件,第一次查询若触发加载库,会有额外开销导致首条 SQL 慢。库文件加载方式:shared_preload_libraries 在启动时加载(改需重启)、session_preload_libraries 连接时加载(超户可设)、local_preload_libraries 连接时加载(普通用户可设,库须在 $libdir/plugins)、或手工 LOAD 命令。对类似 PostGIS、pg_jieba 等大库,首次加载耗时明显,可预先 preload 避免首查变慢。

关键词:preload libraries,shared_preload_libraries,首条SQL慢,插件加载,LOAD | 来源:202406/20240626_02.md

Q:聚合/窗口函数的 FILTER 子句解决什么问题?

FILTER (WHERE …) 允许在聚合或窗口计算前先过滤参与计算的行,用于「排除噪点后的方差/均值」等需要收敛到子集空间的场景。传统 case when 对上下文相关记录(如标准差、平均值)无法正确表达子集语义且结果不一致,还需要多遍扫描。FILTER 语法简单、只扫一遍表、无语义问题,例如 stddev(value) FILTER (WHERE c=‘bee’)。

关键词:FILTER,聚合过滤器,窗口过滤器,stddev,case when | 来源:202108/20210825_01.md

Q:表达「不存在」的三种写法 NOT EXISTS、LEFT JOIN IS NULL、NOT IN 有什么区别?哪个最稳?

NOT EXISTS 语义最贴近 Anti Join,是推荐入口:把关联条件放在子查询 WHERE 里,优化器能清晰拉平为 JOIN_ANTI。LEFT JOIN … IS NULL 依赖补 NULL 表达无匹配,需保证 IS NULL 的那一列只可能来自未匹配补空,reduce_outer_joins() 能证明匹配行该列必非空时才能降级为 Anti Join,否则可能误判「匹配到但字段为 NULL」的行。NOT IN 最容易踩 NULL 坑:当左侧为 NULL,或右侧没有相等值但存在让比较为 NULL 的行时,结果是 NULL 而非 true,在 WHERE 中 NULL 不保留行,因此 NOT IN 不等价于 NOT EXISTS;只有在能证明两侧都不为 NULL 且操作符安全时才能转 Anti Join。业务表默认允许 NULL 时优先用 NOT EXISTS。

关键词:Anti Join,NOT EXISTS,LEFT JOIN IS NULL,NOT IN,NULL语义,JOIN_ANTI,reduce_outer_joins | 来源:202605/20260530_38.md


第2部分:AI 向量数据库(pgvector / VectorChord)

2.1 向量数据库 / AI 检索(30 条)

Q:1 亿条向量建索引需要多久,VectorChord 在 16 核机器上表现如何?

VectorChord 新版在 16 核机器上对 1 亿条向量建索引,借助 IVF+RaBitQ 量化和并行构建,能在很短时间内完成(相比 pgvector HNSW 全内存构建快得多、内存也省得多)。量化让单条向量占用的内存和磁盘降到极小,构建时 CPU 主要花在聚类和量化上,配合并行框架可线性加速,这是其宣称比 pgvector 快 100 倍的底气之一。

关键词:1亿向量,建索引,16核,VectorChord,RaBitQ,并行 | 来源:202511/20251113_01.md

Q:AI 搜索为什么不等于向量搜索?

向量搜索只是 AI 检索的一环,完整的 AI 搜索通常需要稠密向量(语义召回)、稀疏向量/BM25(关键词召回)、向量量化(省内存加速)和重排序(rerank)等多个技术协同。单靠稠密向量难以覆盖精确词匹配、冷门实体和长尾查询。所以『AI 搜索』是一个组合工程,稀疏+稠密+量化+rerank 缺一不可,这也是 pgvector、VectorChord-bm25 等要同时支持多种向量与全文能力的原因。

关键词:AI搜索,向量搜索,稠密向量,稀疏向量,量化,rerank | 来源:202509/20250930_06.md

Q:BM25 全文检索里 Block-WeakAnd 算法是什么?

Block-WeakAnd(又称 WAND 变体)是一种 top-k 检索剪枝算法:它把倒排索引按 block 组织,通过维护候选文档的分数上界,优先扫描可能进入 top-k 的文档,提前跳过分数注定不够的块,从而在不牺牲太多精度下大幅减少文档评分计算量。VectorChord-bm25 在 Postgres 里实现原生 BM25 排名时就采用 Block-WeakAnd 来加速,避免对全部命中文档逐一算分。

关键词:BM25,Block-WeakAnd,WAND,top-k,剪枝,倒排索引 | 来源:202505/20250522_05.md

Q:DiskANN 是什么,和 HNSW 有什么区别?

DiskANN 是微软提出的磁盘友好型图索引(论文 Fast Accurate Billion-scale),核心思想是把图分层:上层热数据常驻内存、下层数据放 SSD,查询时按需加载,从而用很小内存支撑十亿级向量。与传统 HNSW 全内存驻留不同,DiskANN 通过『内存+SSD』混合降低内存成本。TimescaleDB 和 pgvectorscale 的 StreamingDiskANN 都基于这套思路,把 DiskANN 移植进 PostgreSQL 作为扩展。

关键词:DiskANN,SSD,图索引,pgvectorscale,StreamingDiskANN,十亿级 | 来源:202107/20210729_03.md

Q:DuckDB 如何通过 Lance 扩展把 AI 向量检索变成一等公民?

DuckDB 的 Lance 扩展让 SQL 工作流从分析表延伸到检索表:INSTALL lance; LOAD lance 后可读写 Lance 表,提供 lance_vector_search、lance_fts、lance_hybrid_search 三类检索函数。向量、全文、图片字节和标量元数据可在同一套 SQL 里协同,混合搜索里向量距离、全文分数和 _hybrid_score 可同表排序。这标志着向量检索正式成为 DuckDB 内的一等公民能力。

关键词:DuckDB,Lance,向量检索,混合搜索,全文检索,SQL | 来源:202605/20260520_08.md

Q:RaBitQ 向量量化算法的原理是什么?

RaBitQ 是一种面向相似度检索的量化算法,核心是『随机二值化 + 误差补偿』:先把向量投影到随机正交基上做二值量化,再用残差修正量化误差,从而在极小 bit 下保持高召回。相比传统 PQ(乘积量化)更省内存、构建更快,配合 IVF 索引可显著压缩向量规模。VectorChord 的 IVF+RaBitQ 方案正是靠它把内存和索引体积压到 pgvector 的几十分之一,从而做到比 pgvector 快上百倍。

关键词:RaBitQ,量化,随机二值化,误差补偿,VectorChord,PQ | 来源:202511/20251119_09.md

Q:SQL:2028 为什么可能定义 vector 标准?

随着向量检索在各数据库普及,SQL 标准组织考虑在 SQL:2028 中加入 vector 类型与相似度查询的标准化定义,以避免各数据库(Postgres pgvector、DuckDB、MySQL 等)各自为政、语法不兼容。标准化的 vector 类型和近邻查询语法,能让应用在不同数据库间移植向量检索代码更平滑,也让向量成为数据库的一等公民类型。

关键词:SQL:2028,vector,标准,标准化,向量类型 | 来源:202507/20250701_03.md

Q:VectorChord 为什么比 pgvector 快 100 倍?

VectorChord 用『IVF + RaBitQ 量化』组合,把高维 float32 向量量化成极小的 bit 表示,内存和磁盘占用只有 pgvector HNSW 的几十分之一,同样的内存能装更多数据、减少换页和 IO。同时它内置 Graph(DiskANN 和 HNSW)索引、SIMD 加速和高效的召回重排序管线。官方称在相同召回率下,VectorChord 的查询速度比 pgvector 快约 100 倍,1 亿条向量建索引在 16 核机器上也能在很短时间内完成。

关键词:VectorChord,IVF,RaBitQ,量化,100倍,pgvector | 来源:202512/20251213_08.md

Q:pg_bestmatch + pgvector 如何打造适合自己语料的文本检索?

pg_bestmatch 结合 pgvector 和 TF-IDF 思路,为特定语料定制文本相似检索:先用 PostgreSQL 的 ts 全文检索和 madlib 等工具对本地海量文本计算专属的 TF(词频)/IDF(逆文档频率)权重,得到符合该领域语料特点的关键词权重,再结合向量相似度做召回排序。相比通用 embedding,这种『本地语料定制』能更贴合特定领域的检索需求。

关键词:pg_bestmatch,pgvector,TF-IDF,全文检索,语料定制,召回 | 来源:202406/20240620_01.md

Q:pg_turbovec / TurboQuant 为什么能省 20 倍内存?

pg_turbovec 采用 TurboQuant 量化技术,把高维向量的存储压缩到极低 bit(如 4bit/8bit),配合高效的 SIMD 检索,在几乎不损失召回的前提下把向量内存占用降到传统 float32 的约 1/20。这对内存敏感的大规模向量检索场景非常有吸引力,用同样的内存可以承载 20 倍的数据量,是 PG 向量检索内存优化的代表方案之一。

关键词:pg_turbovec,TurboQuant,量化,省内存,20倍,SIMD | 来源:202607/20260724_08.md

Q:pg_vectorize 插件如何把 pgvector 和 AI 结合?

pg_vectorize 是一个把 pgvector、OpenAI(及本地模型)集成进 Postgres 的插件,让用户能直接在 SQL 里完成 embedding 生成、向量存储和相似检索,把『数据库+AI』的流程收敛到数据库内。它抽象了 embedding 模型调用和向量索引管理,降低在 PG 上搭建 RAG/语义搜索应用的门槛,是 DB&AI 融合的典型实践。

关键词:pg_vectorize,pgvector,OpenAI,embedding,DB&AI,RAG | 来源:202401/20240108_03.md

Q:pgvecto.rs 是什么,和其他向量插件比有什么特点?

pgvecto.rs 是一个用 Rust 编写的 PostgreSQL 向量索引扩展,支持 IVFFlat 和 HNSW 等索引,强调用 Rust 实现以获得内存安全和较高性能,并支持向量+标量混合过滤。它和 pgvector、VectorChord 一样是 PG 生态里的向量检索选项,主要卖点是 Rust 实现带来的安全性,以及较完整的混合检索与过滤能力。

关键词:pgvecto.rs,Rust,向量索引,IVFFlat,HNSW,混合过滤 | 来源:202308/20230807_01.md

Q:pgvector HNSW 索引在高频更新场景有什么坑?

HNSW 的删除是惰性的——被删除的节点不会立刻从图中移除,而是被标记,导致图结构逐渐退化、检索质量下降。频繁 UPDATE/DELETE 会让 HNSW 图里残留大量死节点,召回率和性能随时间变差。缓解办法是定期对表做 vacuum 清理、必要时重建索引(REINDEX),或者对频繁更新的向量数据避免用 HNSW 而改用其他方案。

关键词:HNSW,高频更新,vacuum,REINDEX,图退化,死节点 | 来源:202505/20250507_01.md

Q:pgvector 插件支持哪几种向量数据类型,各自有什么用途?

pgvector 提供 vector、halfvec、sparsevec、bit 四种类型。vector 是默认的 float32 稠密向量;halfvec 用 float16 存储,内存占用只有 vector 的一半,适合大维度、内存敏感场景;sparsevec 是稀疏向量,只存非零维的坐标和值,适合稀疏 embedding;bit 是二值向量,配合 Hamming 距离做二值化检索,存储极小。选择类型本质是在召回精度与内存/存储之间做权衡。

关键词:pgvector,vector,halfvec,sparsevec,bit,float16,稀疏向量 | 来源:202511/20251103_13.md

Q:pgvector 支持哪几种相似度距离操作符,如何选?

pgvector 用操作符表达距离:<-> 是欧氏距离 L2(越小越相似)、<#> 是负内积(值越大越相似)、<=> 是余弦距离(越小越相似),bit 类型用 <~> 计算 Hamming 距离。内积适合词向量这类方向敏感的场景,余弦适合文本 embedding 且对模长不敏感,L2 适合坐标类数据。内积操作符返回负值是因为索引内部按从小到大排序,取负号让『越大越相似』转成『越小越靠前』。

关键词:pgvector,L2,内积,余弦,Hamming,距离操作符 | 来源:202511/20251104_06.md

Q:pgvector 的 HNSW 索引原理和关键参数是什么?

HNSW(Hierarchical Navigable Small World)是多层跳表式图索引,每层是邻近图,上层稀疏下层稠密,查询从顶层贪心下降到底层做近似最近邻。核心参数:m 是每个节点在图中的最大邻居数(默认 16),越大召回越高但内存和建索引越慢;ef_construction 是建索引时的动态候选队列长度(默认 64);ef_search 是查询时的候选队列长度,可运行时通过 SET hnsw.ef_search 调节,越大越准越慢。HNSW 建索引比 IVFFlat 慢、内存更大,但查询召回和 QPS 通常更优。

关键词:HNSW,m,ef_construction,ef_search,多层图,近似最近邻 | 来源:202511/20251104_11.md

Q:pgvector 的 IVFFlat 索引原理和关键参数是什么?

IVFFlat 是倒排文件(Inverted File)+ 平坦存储,建索引时先用 kmeans 把向量聚成 lists 个簇,查询时只探测 probes 个最近的簇,而不是全表扫。核心参数:lists 是聚类中心数(一般取行数/1000,或直接设 100),probes 是查询时探测的簇数,建议取 sqrt(lists)。probes 越大召回越高但越慢,lists 越大每个簇越小、候选更精准但可能漏簇。IVFFlat 是近似检索,需要先灌一批数据再建索引以获得好的聚类中心。

关键词:IVFFlat,lists,probes,kmeans,倒排文件,近似检索 | 来源:202511/20251104_12.md

Q:pgvector 的 bit 类型和 Hamming 距离适合什么场景?

pgvector 的 bit 类型用二值向量表示数据,用 <~> 操作符计算 Hamming 距离(两个二进制向量不同 bit 的个数)。二值向量每个维度只占 1 bit,存储极小、计算极快,适合对精度要求不高但数据规模巨大、内存敏感的检索场景(如大规模图像指纹去重)。代价是丢失了实数值的精度,召回通常低于 float32 向量。

关键词:bit,Hamming,二值向量,pgvector,去重 | 来源:202511/20251103_16.md

Q:pgvectorscale 的 StreamingDiskANN 和 SBQ 是什么?

pgvectorscale 是 Timescale 开源的 pgvector 扩展,核心是 StreamingDiskANN——一种流式磁盘 ANN 索引,向量不全部驻留内存,构建和查询时流式读写,大幅降低大向量集合的内存占用。SBQ(Scalar Binary Quantization)是它的标量二值量化压缩,把向量压缩存储以省内存和带宽。整体让 pgvector 在十亿级向量上也能以较小内存工作,同时对 pgvector 保持兼容。

关键词:pgvectorscale,StreamingDiskANN,SBQ,标量量化,磁盘索引 | 来源:202511/20251109_08.md

Q:什么是召回率(recall),近似最近邻为什么需要它?

召回率指 ANN 返回结果中包含真实最近邻的比例,通常以 recall@k 衡量(top-k 里命中了多少真近邻)。因为 IVF/HNSW/DiskANN 都是近似检索,用剪枝换速度,必然可能漏掉部分真近邻,所以用召回率来量化精度损失。实践中通过调大 probes/ef_search/lists 等参数提高召回,但要与 QPS、内存做权衡,通常目标是 95%~99% 召回。

关键词:召回率,recall,recall@k,近似最近邻,精度 | 来源:202512/20251211_12.md

Q:什么是多向量(multi-vector)相似搜索,和单向量有何区别?

多向量搜索用多个向量共同表示一个文档/查询,典型如 ColBERT 把文档的每个 token 都编码成一个向量。查询时用 MaxSim:对查询的每个 token 向量,在文档向量里找最相似的那个取最大值,再求和作为整体相似度。相比把整篇文档压成一个稠密向量的单向量检索,多向量能保留更细粒度语义,召回更高,但存储和算力开销也成倍增加,常配合 ColBERT 做 rerank。

关键词:多向量,MaxSim,ColBERT,rerank,单向量,相似搜索 | 来源:202508/20250828_10.md

Q:什么是混合搜索(hybrid search),为什么比纯向量搜索效果好?

混合搜索把多种检索信号融合在一起,典型是『稠密向量 + 稀疏向量(BM25 关键词) + 结构化过滤』,用 RRF(Reciprocal Rank Fusion)等算法把各路的排序结果合并。纯向量搜索擅长语义相关但可能漏掉精确关键词命中,纯 BM25 擅长精确词但不懂语义,混合搜索两者互补,能显著提升检索相关性。Postgres 借助 pgvector + 原生 BM25/VectorChord-bm25 可以在一个 SQL 里完成混合检索。

关键词:混合搜索,RRF,BM25,稠密向量,稀疏向量,融合 | 来源:202512/20251208_13.md

Q:向量数据为什么需要归一化?

归一化(单位化)后所有向量的模长变成 1,好处有三:一是此时余弦相似度与内积等价,计算可复用;二是 L2 距离与余弦距离也等价,排序结果一致;三是避免不同模长的向量在比较时引入长度偏差。做归一化后,用内积操作符 <#> 就能得到与余弦一致的相关性排序,且内积计算比余弦省一次除法。

关键词:归一化,余弦,内积,L2,单位向量 | 来源:202107/20210723_01.md

Q:向量索引建索引时 maintenance_work_mem 是不是越大越好?

不是。maintenance_work_mem 决定建索引时的工作内存,但给太大反而可能变慢:当工作内存超过 CPU 三级缓存(L3)容量时,排序/聚类的工作集会溢出缓存、命中内存延迟上升,同时超大内存易触发操作系统脏页抖动和 swap。经验上要给得适中,让它装下关键工作集即可,而不是无脑拉满,对大规模向量建索引尤其要结合 L3 cache 大小调。

关键词:maintenance_work_mem,L3 cache,脏页,建索引,内存调优 | 来源:202406/20240613_01.md

Q:向量索引的『前置/预过滤器』指的是什么?

向量索引里的预过滤(pre-filter)指在进入向量近邻搜索前,先用结构化条件(如 WHERE 过滤类别、时间、标签)缩小候选集合,再在这个子集里做 ANN 检索。相比之下后过滤(post-filter)是先做 ANN 取出 top-k 再套过滤条件,容易因为过滤掉部分结果导致返回不足 k 条。预过滤能保证结果满足所有约束,是混合搜索正确性的关键,pgvector 和 VectorChord 等插件都支持把过滤条件下推到索引扫描。

关键词:预过滤,前置过滤,post-filter,pre-filter,混合搜索,索引下推 | 来源:202509/20250901_01.md

Q:向量索引预热(prewarm)的原理和作用是什么?

向量索引预热指在查询高峰前,把索引的热数据预先加载到内存/页缓存里,避免首批查询发生大量磁盘 IO 和冷启动延迟。对基于磁盘的索引(如 DiskANN/StreamingDiskANN)尤其重要,预热后首次查询即可命中内存。VectorChord 等插件提供 prewarm 机制,把常用分片或图的上层节点提前加载,从而消除首查抖动。

关键词:prewarm,预热,索引,内存,冷启动,DiskANN | 来源:202508/20250829_11.md

Q:向量量化有哪些主流技术,压缩和量化的区别是什么?

主流量化技术包括:标量量化(把 float32 映射到 int8/4bit)、乘积量化 PQ(把向量切段分别聚类,用码本 ID 表示)、残差向量量化 RVQ(逐级量化残差)、二值量化(每维 1bit)以及 RaBitQ。『压缩』泛指降低存储(如 float32→float16 或降维),『量化』特指用有限码本/离散值近似原始值。量化本质是用精度换内存和算力,召回率会略有下降,需要在压缩比与召回精度间权衡。

关键词:标量量化,PQ,RVQ,二值量化,乘积量化,残差量化,压缩 | 来源:202511/20251106_07.md

Q:残差矢量量化(RVQ)的原理是什么?

RVQ(Residual Vector Quantization)是矢量量化的增强:先对向量做一次量化,算出量化后的残差(误差向量),再对残差做下一级量化,如此逐级叠加多个码本,用多级码本 ID 共同逼近原向量。相比单级 VQ,RVQ 能用更小码本达到更高精度,是谷歌 SoundStream、Meta Encodec 等神经音频编解码器(也是 AudioLM 基础)的核心压缩技术。VectorChord 等向量插件也借鉴 RVQ 做高压缩比量化。

关键词:RVQ,残差量化,矢量量化,码本,SoundStream,Encodec | 来源:202508/20250827_04.md

Q:阿里云 PG 的 pase 插件在高维向量上做了什么?

pase(PostgreSQL 向量索引)是阿里云 PG 早期的高维向量检索插件,支持 512 维向量索引,用于图像识别、人脸识别等相似搜索场景。它针对高维向量的近似最近邻做优化,是国产云 PG 向量能力早期的代表。后来 pgvector 成为事实标准后,这些早期自研插件逐步被替代或整合。

关键词:pase,高维向量,阿里云,图像检索,人脸识别,512维 | 来源:201912/20191219_02.md

Q:高维向量如何做可视化降维?

高维向量无法直接画在二维平面上,常用 T-SNE(t-Distributed Stochastic Neighbor Embedding)等降维算法,把高维空间里的近邻关系尽可能保留地映射到 2D/3D,用于观察向量聚类的分布。T-SNE 通过在高维用高斯、低维用 t 分布建模点对相似度,并优化 KL 散度来保持局部结构,是向量数据集探索和质检的常用工具。

关键词:T-SNE,降维,可视化,高维向量,聚类 | 来源:202409/20240905_01.md


第3部分:国产数据库内核与 Oracle 兼容(加分项)

3.1 国产数据库内核(19 条)

Q:A 国产数据库 PolarDB 能不能跑在 H 国产操作系统 openEuler 上?

文章讨论国产数据库与国产操作系统的适配问题:PolarDB(A 国产库)能否跑在 openEuler(H 国产操作系统)上,核心在于依赖库(glibc、内核参数、编译环境、驱动)的兼容性和官方认证。国产化『信创』要求数据库+操作系统+芯片全栈适配,跨厂商组合常遇到未认证、依赖不匹配、性能未调优等问题。答案是可跑但需要做依赖适配和参数调优,且最好用官方认证过的组合以保证支持。

关键词:PolarDB,openEuler,国产化,信创,适配,依赖 | 来源:202501/20250115_03.md

Q:ACE 装国产数据库花了 2 周,反映了国产数据库什么现状?

文章用一位 ACE(数据库专家)装某国产数据库耗时 2 周的经历,吐槽国产数据库在安装部署、文档、依赖、环境适配上的成熟度参差不齐。相比之下作者试自家产品很快装好,说明国产库之间的工程化程度差异很大。它点出的现状是:内核可能不错,但安装、运维、兼容性、文档这些『最后一公里』体验是国产数据库普遍短板,也是用户选型时最痛的环节。

关键词:国产数据库,安装部署,运维,文档,ACE,选型 | 来源:202404/20240409_01.md

Q:Atlas 950 SuperPoD 登顶与『华为韬定律』是什么?

文章把华为 Atlas 950 SuperPoD 超级计算节点站上世界之巅的现象,类比为『华为韬定律』(借韬光养晦之意,指华为在算力/硬件上持续投入最终登顶)。它关联到国产数据库和 AI 算力的底座能力:国产芯片+国产操作系统+国产数据库全栈崛起是长期积累的结果,华为在昇腾/鲲鹏硬件上的突破为 openGauss 等国产数据库提供了算力支撑。

关键词:Atlas 950,SuperPoD,华为,算力,鲲鹏,昇腾,国产 | 来源:202607/20260718_01.md

Q:BemiDB 如何让 PolarDB PostgreSQL 提速 10 倍以上?

BemiDB 整合 PolarDB PostgreSQL 与对象存储/列式能力,针对 DataLake 场景做优化,实现 10x+ 提速。思路是让 PG 引擎直接高效读取对象存储(如 OSS)上的列式数据,利用并行扫描、谓词下推、列存压缩等减少 IO 和计算,把 PG 变成能直接查数据湖的引擎。这代表了『PG 内核 + 存算分离 + 列式』融合加速的国产演进方向。

关键词:BemiDB,PolarDB,对象存储,DataLake,10倍,列式 | 来源:202412/20241213_02.md

Q:HW 放弃 OpenGauss TP 售卖对用户是好还是坏?

文章分析华为放弃 OpenGauss 在 TP(事务处理)市场的售卖策略,对用户的影响。OpenGauss 本身开源,华为若收缩商业售卖,用户短期可能面临商业支持收缩、服务不确定性,但长期看开源社区和生态(如众多发行版)会继续演进。好坏取决于用户是否有自主运维能力:有能力的用户乐见其开源属性、成本更低;依赖原厂支持的客户则要重新评估支持保障。

关键词:OpenGauss,华为,TP,开源,商业支持,用户影响 | 来源:202108/20210804_01.md

Q:OpenTeleDB 的 XStore 引擎如何解决 vacuum 抖动?

PG 原生 MVCC 下 UPDATE 会产生 dead tuple、写两份 heap 和 index page,导致表膨胀、vacuum 期间性能抖动 40% 以上。天翼云 OpenTeleDB 用 contrib/xstore 的 XStore 引擎实现『原位更新 + Undo 体系』:原地覆盖旧版本、用 Undo 保存旧值供回滚和旧快照,从而不再产生 dead tuple、不重复写页。效果是把 vacuum 抖动压到 5% 以内,是 PG 存储引擎的重要国产改进。

关键词:OpenTeleDB,XStore,原位更新,Undo,vacuum抖动,MVCC | 来源:202609/20260904_04.md

Q:OpenTeleDB 的代码规模有多大?

OpenTeleDB 主源码 + contrib 合计约 256,572 行 C/C++,约为 PG 17 主干的四分之一,是精简后的实现,部分功能走 contrib 模块化。它由 XStore(存储引擎)、XProxy(代理)、XRaft(Raft 复制)等模块组成,基于 PG 内核做电信级增强,定位是面向电信场景的开源 PG 发行版。

关键词:OpenTeleDB,256,572行,XStore,XProxy,XRaft,天翼云 | 来源:202609/20260904_04.md

Q:OpenTenBase 的 CN/DN/GTM 三组件架构是什么?

OpenTenBase 是腾讯系、从 Postgres-XL 演进而来的分布式数据库(经 Postgres-XC→TransLattice→Postgres-XL 再到 OpenTenBase,最新 v2.6.0)。架构分三组件:CN(Coordinator)负责解析、重写和分布式规划,把 SQL 拆成多分片推到 DN;DN(DataNode)实际存储分片数据并执行;GTM(Global Transaction Manager)负责全局事务号、全局快照和全局序列。一个 SQL 要跨 CN→GTM→DN 协作,是 PG 系里真正的分布式数据库。

关键词:OpenTenBase,CN,DN,GTM,分布式,Postgres-XL,腾讯 | 来源:202609/20260904_06.md

Q:OpenTenBase 的代码规模和 GTM 为何是核心?

OpenTenBase 主源码约 17.8 万行 C/C++(主 src/,不含 contrib),其中 GTM 目录就占 76,237 行、约 42%,是最大的非标准 PG 代码块。GTM 负责全局唯一 64-bit GXID、全局快照(全集群 MVCC 一致)、全局序列(跨 DN nextval 一致)和 GTM 自己的 WAL 持久化。因为分布式一致性全压在 GTM 上,它的可用性和性能直接决定集群能力,是 OpenTenBase 与单机 PG 差异最大的地方。

关键词:OpenTenBase,GTM,17.8万行,GXID,全局快照,76,237行 | 来源:202609/20260904_06.md

Q:PG 比 MySQL 快这么多为什么会让国产内核研发被『洗脑』?

文章反讽一种现象:某国产数据库内核研发人员认为『PG 比 MySQL 快这么多是不符合预期的』,暴露了对两者架构差异的误解。PG 和 MySQL 的并发模型、存储引擎、优化器能力不同,某些负载下 PG 更快是正常结果,不能用『MySQL 应更快』的预设来否定实测。文章提醒内核研发要尊重基准测试和架构事实,避免用偏见替代数据。

关键词:PG,MySQL,性能对比,国产内核,基准测试,架构 | 来源:202506/20250611_03.md

Q:VexDB 容器里同时暴露 PG/openGauss/vastbase 意味着什么?

VexDB 是一个容器化体验方案,能在同一环境里暴露 PostgreSQL、openGauss、vastbase(海量数据的国产库)等多个引擎,方便快速对比和体验不同国产/开源数据库。它解决了国产数据库『装起来麻烦、试起来门槛高』的问题,用 docker 一键拉起多种内核做功能与性能对比,是选型和学习国产库的实用工具。

关键词:VexDB,容器,docker,openGauss,vastbase,国产库体验 | 来源:202509/20250925_07.md

Q:oGRAC 是什么,它和传统 PG 分布式数据库的核心区别在哪?

oGRAC 是华为开源的『开源版 RAC』,实现应用透明的多主强一致写入——任意节点都能执行 DDL/DML/DCL,所有节点看到同一份强一致数据,像用单机一样用集群,只要有任一存活节点集群仍可用。这与 PG 主从(单点写)、逻辑复制(应用层冲突检测)本质不同。核心在 DSS(分布式存储服务)+ DTC/DLS/DCS 三件套:DLS 分布式锁、DCS 分布式共识、DRC 分布式行缓存,配合共享存储实现存算分离多写。

关键词:oGRAC,RAC,多主,强一致,华为,DLS,DCS,DRC | 来源:202609/20260904_03.md

Q:oGRAC 的代码规模和多主恢复的工程难点在哪?

oGRAC 主源码约 88.8 万行 C/C++,比 PG 16 主干(约 110 万行)略小、比 openGauss(约 170 万行)小一半。多主核心在 pkg/src/cluster/ 下:dtc_recovery.c 单文件 10,217 行是整个项目最大文件,dtc_dcs.c(3,464 行,分布式共识)、dtc_dls.c(2,109 行,分布式锁)、dtc_dc.c(1,403 行,远程 page 缓存)。崩溃恢复是 82 个 API、涉及跨节点 redo 和主从切换,是工程上最难的部分。

关键词:oGRAC,88.8万行,dtc_recovery,多主恢复,DCS,DLS,DRC | 来源:202609/20260904_03.md

Q:openGauss 内核在 INSERT 上做了哪些极致优化?

openGauss 把一条 INSERT 拆成 8 个步骤优化:包括 NUMA 感知的 buffer/clog 分区、并行 redo、JIT 编译 LLVM IR 直接执行等,目标是亚毫秒级完成。对 MOT 内存引擎表,JIT 编译的 LLVM IR 直接执行且不进 WAL,旁路常规存储路径。在两路鲲鹏 128 核上跑出 150 万 tpmC,靠的就是这 8 个步骤里每个细节的极致优化(NUMA 亲和、内存引擎、并行恢复、JIT)。

关键词:openGauss,MOT,内存引擎,JIT,LLVM,NUMA,150万tpmC | 来源:202609/20260904_02.md

Q:openGauss 的代码规模和五大模块构成是什么?

openGauss-server 主源码约 49.7 万行 C/C++(不含 contrib/lib/tools),codegraph 索引出 4,967 文件、143,586 节点、543,067 边。内核按 5 大模块组织(存储、执行器、优化器、事务、恢复等),其中 MOT 内存引擎是最大亮点——内存行存、免 WAL、JIT 执行,专攻高并发 OLTP。openGauss 是国产顶级数据库内核的代表,从 PG 分叉后做了大量面向信创和高性能的定制。

关键词:openGauss,49.7万行,MOT,国产内核,OLTP,信创 | 来源:202609/20260904_02.md

Q:『多个引擎一份存储』(CockroachDB/SequoiaDB)的架构意义是什么?

CockroachDB、SequoiaDB 等采用『多个引擎共享一份存储』的思路:计算引擎(SQL 层)与存储层解耦,多个计算节点/引擎访问同一份分布式存储,实现弹性伸缩和资源隔离。这与传统『每库自带存储』的单体架构不同,更接近云原生。对 PG 生态的启示是:可以把 PG 的 SQL 引擎接到共享存储上(类似 PolarDB 计算存储分离),兼顾 PG 生态兼容与弹性能力。

关键词:CockroachDB,SequoiaDB,存算分离,共享存储,云原生 | 来源:202009/20200928_03.md

Q:为了体验 OpenTeleDB 的 XStore,作者做了什么?

作者为体验电信 OpenTeleDB 开源的 PG XStore 存储引擎,专门做了一个 docker 镜像,一键拉起带 XStore 的 OpenTeleDB 环境,方便直接测试其原位更新+Undo 特性、对比 vacuum 抖动。这反映了国产库开源组件『体验成本高、缺少现成镜像』的现状,用容器降低门槛是社区推广的有效手段。

关键词:OpenTeleDB,XStore,docker,体验,容器化 | 来源:202601/20260106_02.md

Q:为什么说『千万别学国产数据库』?

这是一篇反讽/警醒性质的文章,核心观点是:国产数据库多基于开源(尤其 PG/MySQL)二次开发,内核门槛高、投入大、周期长,盲目跟风自研容易『重复造轮子』且难以超越上游;真正该做的是站在开源肩上做差异化(如存储引擎、分布式、兼容性),而不是从零写内核。文章用调侃语气提醒从业者理性看待国产数据库热,避免低水平重复建设。

关键词:国产数据库,自研,开源,二次开发,内核,警醒 | 来源:202411/20241120_02.md

Q:对象存储计算引擎 hawq/gpdb 的思路是什么?

Hawq 和 Greenplum(GPDB)是基于 PG 的 MPP 分析型数据库,早期采用『计算与存储在 HDFS/对象存储分离』的思路:数据放分布式文件系统,多个 segment 并行扫描计算。这种存算分离架构支持弹性扩缩容和大规模并行分析,是 PG 体系里大数据分析引擎的代表。后来 GPDB 转向自管理存储,Hawq 融入 Apache 生态,但存算分离思想影响了后续云原生数据库设计。

关键词:hawq,greenplum,GPDB,MPP,存算分离,对象存储 | 来源:202004/20200423_03.md

3.2 Oracle 兼容 / 迁移 / 去 O(36 条)

Q:Alien 转换 rpm 到 deb 安装包在 PG 环境里有什么用?

alien 是一个把 rpm 转成 deb(或反向)的安装包转换工具。在 PG 生态里,很多第三方工具、插件、客户端只提供 rpm 包(面向 RHEL/CentOS 系),而目标服务器是 Debian/Ubuntu 系(只用 deb),此时可用 alien 转换后安装。不过 alien 转换的包可能缺少依赖关系处理,生产环境更推荐用对应发行版源里原生打包的 PG 及插件。

关键词:alien,rpm,deb,安装包转换,PG部署 | 来源:202401/20240131_01.md

Q:Babelfish 如何让 PostgreSQL 兼容 SQL Server?

Babelfish 是 AWS 开源的 SQL Server 兼容层,跑在 Aurora PostgreSQL 上,让应用用 T-SQL 方言和 SQL Server 协议连到 PG。它有 single-mode(整个库只讲 T-SQL)和 multi-mode(同一实例里 PG 库和 T-SQL 库共存)两种模式。Babelfish 把 T-SQL 解析翻译成 PG 内部结构,兼容数据类型、语法、系统视图,用于 SQL Server 迁移到 PG 场景,大幅降低迁移改写量。

关键词:Babelfish,SQL Server,T-SQL,single-mode,multi-mode,AWS | 来源:202012/20201204_01.md

Q:EDB PPAS/EPAS 的 Oracle 兼容思路是什么?

EDB 的 PPAS(后改名 EPAS,Postgres Advanced Server)是商业级 Oracle 兼容数据库,在 PostgreSQL 内核上实现了 Oracle 的 PL/SQL、内置包、数据类型、SQL 语法、sqlplus 兼容客户端等,目标让 Oracle 应用『近乎零修改』迁移。EDB 提供 EDB*Plus 兼容 sqlplus 的命令行工具,还有兼容 Oracle 的 PL/SQL 引擎。它是商业化去 O 方案里兼容度最高的代表之一,代价是闭源收费。

关键词:EDB,PPAS,EPAS,Oracle兼容,PL/SQL,sqlplus | 来源:201903/20190301_01.md

Q:IvorySQL 是什么,它如何做 Oracle 兼容?

IvorySQL 是瀚高开源、基于 PostgreSQL 的 Oracle 兼容数据库,把 Oracle 的 PL/SQL 语法、内置包、数据类型等兼容能力以开源方式提供。它吸收 orafce 等兼容思路,目标是让 Oracle 用户能以较低成本迁移到 PG 体系。作为开源 Oracle 兼容产品,它填补了『开源 + 较强 Oracle 兼容』的空缺,与 EDB(闭源)形成对照。

关键词:IvorySQL,瀚高,Oracle兼容,PL/SQL,开源,去O | 来源:202112/20211214_01.md

Q:KingbaseES KFS 迁移 Oracle 的全量+增量同步怎么做?

KingbaseES(人大金仓)提供 KFS 迁移工具,先做全量数据搬迁,再通过增量同步(解析 Oracle redo 或触发器捕获)持续追平源库,最后在业务低峰期做切换,实现 Oracle→KingbaseES 的平滑迁移。实操手册强调迁移前做兼容性评估、类型映射、对象转换(存储过程/触发器/序列),迁移后做 count/hash 一致性校验和性能基线对比,再灰度切流。

关键词:KingbaseES,KFS,迁移,全量,增量同步,Oracle,金仓 | 来源:202608/20260814_05.md

Q:Oracle 与 PostgreSQL 的概念术语对照里最关键的差异是什么?

最关键的差异:Oracle 的『数据库=实例+库』概念里,实例(instance)与数据库(database)分离,一个实例对应一个库;而 PG 一个实例(cluster)可包含多个 database。Oracle 的 schema 等同于用户(user=schema),PG 的 schema 是 namespace、与用户解耦。Oracle 表空间(tablespace)与 PG 的表空间语义也不同。理解这些术语差异是去 O 迁移、对象映射和权限设计的前提。

关键词:术语对照,instance,database,schema,tablespace,Oracle,PG | 来源:202002/20200202_01.md

Q:Oracle 的 pljson 与 PG 原生 JSON 能力如何对应?

Oracle 用 pljson 包处理 JSON,PG 原生就内置强大的 JSON 能力(json/jsonb 类型、jsonpath、丰富函数),去 O 时无需再依赖 pljson 这类第三方包。PG 的 jsonb 支持索引(GIN)、jsonpath 类似 XPath 的路径查询,能力上覆盖并超出 pljson。迁移时把 Oracle 的 pljson 调用改写成 PG 原生 JSON 函数即可,反而更简洁高效。

关键词:pljson,JSON,jsonb,jsonpath,Oracle兼容 | 来源:201906/20190611_02.md

Q:PG 与 Oracle 在 storage/segment/tablespace 上的概念差异是什么?

Oracle 用表空间(tablespace)组织数据文件,数据文件按 segment(段)管理,表/索引对应不同 segment;PG 的表空间只是存储目录,表和索引都放进对应表空间目录下,没有 Oracle 那么细的 segment/数据文件层级。理解这个差异有助于迁移时规划存储:Oracle 的多个 datafile/segment 在 PG 里简化为目录+文件,容量管理和备份策略要相应调整。

关键词:tablespace,segment,datafile,存储,Oracle,PG | 来源:202002/20200202_01.md

Q:PG 如何兼容 MySQL 的 bit(n) 用法?

MySQL 的 bit(n) 在超出范围时按位填充 1 等行为与 PG 原生 bit 类型不完全一致,PG 兼容 MySQL bit(n) 需要处理其特殊的溢出/填充语义。PG 有 bit varying 和 bit(n) 类型,但边界行为不同,迁移 MySQL 时要做类型映射和行为校验,必要时用函数模拟 MySQL 的位运算习惯。这提醒异构迁移不能只改类型名,还要验证边界行为一致性。

关键词:bit(n),MySQL,兼容,类型映射,边界行为 | 来源:202001/20200105_03.md

Q:PG 如何兼容 MySQL 的 order by 拼音或 binary 排序?

MySQL 可用 GBK/utf8 的 collation 或 binary 关键字控制按拼音、按字节排序。PG 通过设置不同的 collation(如 zh_CN、C locale)和 lc_collate 参数控制排序规则,用 C collation 得到按字节的 binary 排序。去 MySQL 迁移时,要把 MySQL 的 collation 语义映射成 PG 的 collation,才能保证 order by 结果与原来一致,避免中文字段排序结果漂移。

关键词:MySQL,order by,collation,拼音排序,binary,兼容 | 来源:202010/20201031_04.md

Q:PG 如何兼容 MySQL 的『指定位置加列/修改列位置』?

MySQL 支持 ALTER TABLE … ADD COLUMN x AFTER y 等指定列位置操作,PG 原生不支持列位置调整(列顺序由系统表 attnum 决定,逻辑上无关紧要)。PG 兼容方式是用 CREATE TABLE AS 重建或插件模拟列位置语义,但本质上 PG 通过列名而非位置引用,迁移时应改造 SQL 用列名而非位置。这是 MySQL→PG 迁移常见的不兼容点。

关键词:MySQL,指定位置加列,ALTER TABLE,列位置,兼容 | 来源:202010/20201031_10.md

Q:PG 如何兼容 Oracle 的 binary_float/binary_double?

Oracle 有 binary_float、binary_double 两种二进制浮点类型(近似值、运算快、精度略低)。PG 对应使用 real(4 字节浮点)和 double precision(8 字节浮点),语义基本对应。去 O 迁移时把 binary_float→real、binary_double→double precision 映射即可,注意两者都是近似存储,等值比较可能因精度差异有细微不同,迁移需评估对账逻辑。

关键词:binary_float,binary_double,real,double precision,Oracle兼容 | 来源:201907/20190722_01.md

Q:PG 如何兼容 Oracle 的 sqlplus 变量和交互式用法?

Oracle 的 sqlplus 支持 & 变量替换、DEFINE、ACCEPT 等交互式特性,PG 的 psql 有对应的 :变量、\set、\prompt 机制,但语法和交互行为不同。去 O 迁移时要把 sqlplus 脚本里的 &var 改成 psql 的 :var,把 DEFINE 改成 \set,交互输入用 \prompt 模拟。EDB 的 EDB*Plus 则直接兼容 sqlplus 语法,可减少脚本改写。

关键词:sqlplus,psql,变量替换,DEFINE,交互式,兼容 | 来源:201907/20190718_01.md

Q:PG 如何兼容 SQL Server 的大小写不敏感(CI)?

SQL Server 默认排序规则大小写不敏感,PG 默认大小写敏感。PG 兼容 CI 有几种方式:用 citext 类型存字符串、建函数索引对列 lower()、或使用大小写不敏感的 collation。citext 是官方推荐的 CI 文本类型,比较时自动忽略大小写,最接近 SQL Server 行为,适合 SQL Server→PG 迁移中需要保持原有 SQL 不因大小写改写的场景。

关键词:citext,大小写不敏感,SQL Server,兼容,CI,collation | 来源:201911/20191112_02.md

Q:PG 的 clone schema 如何实现,去 O 有什么用?

PG 原生没有一键 clone schema 的命令,但可以用 pg_dump 只导出某个 schema 再导入到新 schema,或用 CREATE TABLE … LIKE 系列克隆表结构,实现 schema 级别的复制。去 O 场景中常用于搭建测试库、复制标准 schema 模板、批量建结构相同的分表。相比 Oracle 的 expdp/remap_schema,PG 用 pg_dump 的 –schema 选项配合导入即可实现类似效果。

关键词:clone schema,pg_dump,schema复制,CREATE TABLE LIKE,去O | 来源:201908/20190821_01.md

Q:PG17 对 pg_upgrade 保留订阅状态做了什么改进?

PG17 起 pg_upgrade 大版本升级可以保留逻辑复制的订阅状态(slot、subscription 等),升级后不需要重新建订阅、重新全量同步,订阅端能直接接着旧位置继续消费。这对依赖逻辑复制的生产库是重大改善,省去了升级后重建复制链路和初始同步的耗时,降低了升级复杂度和停机影响。

关键词:PG17,pg_upgrade,订阅状态,逻辑复制,升级 | 来源:202401/20240104_01.md

Q:PG18 pg_upgrade 的 FILE_COPY strategy 是什么?

PG18 给 pg_upgrade 新增 FILE_COPY strategy(file-copy 策略),用标准文件拷贝替代默认的 hardlink 或 reflink 方式。默认 –link 用硬链接省空间但要求新旧目录同一文件系统,且风险是升级失败会污染旧数据;FILE_COPY 则真正复制文件,更安全、可跨文件系统,代价是更慢更占空间。这给用户在『速度/空间』与『安全/隔离』之间提供了更多选择。

关键词:FILE_COPY,pg_upgrade,PG18,硬链接,文件拷贝,升级策略 | 来源:202503/20250326_01.md

Q:PG18 pg_upgrade 的 swap 选项是干什么的?

swap 选项让 pg_upgrade 在完成升级后,把新旧两个数据目录互换(swap),从而减少停机窗口内的数据搬移时间,并在需要回滚时能快速切回旧版本。它改变了传统的『复制后切换』流程,让升级切换和回退更快更安全,是高可用升级场景的实用增强。

关键词:swap,pg_upgrade,PG18,数据目录,切换,回滚 | 来源:202502/20250221_02.md

Q:PG18 pg_upgrade 的并行框架是什么?

PG18 为 pg_upgrade 引入并行升级框架,让 catalog 重建、对象处理等可并行的阶段用多进程并行执行,大幅缩短大库的升级时间。此前 pg_upgrade 大量工作是串行的,库对象一多升级就很慢。并行框架按表/索引等对象粒度划分任务并行处理,配合 –jobs 类参数控制并行度,是 pg_upgrade 性能的一次重要飞跃。

关键词:并行框架,pg_upgrade,PG18,–jobs,并行升级 | 来源:202409/20240918_01.md

Q:PG18 号称的十大特性为什么被说能『干掉 Oracle 的 IMCS 内存表』?

Oracle 的 IMCS(In-Memory Column Store)是内存列式加速表,PG 社区通过列式存储引擎(如 zedstore/列存插件)+ 内存优化,提供了类似的内存/列式加速能力,配合并行、JIT、向量化执行,让 PG 也能在分析型负载上逼近 IMCS 的效果。文章调侃 PG 要『干掉 Oracle 引以为傲的 IMCS』,指 PG 生态用开源组合拳实现了内存列存加速,去 O 时不用再依赖 Oracle 的这一卖点。

关键词:IMCS,内存列存,列式存储,PG18,去O,zedstore | 来源:202410/20241012_03.md

Q:PG18 把生产环境的查询计划『打包带走』是什么特性?

PG18 支持导出/导入查询计划(plan 打包),可以把生产环境里某条 SQL 的实际执行计划(连同统计信息、环境参数)打包带走,在测试环境复现并分析,用于排查执行计划回归。这让『生产计划漂移』问题可离线诊断:DBA 不用在生产反复试错,把计划带回测试环境就能定位是统计信息、参数还是数据分布导致计划变化。

关键词:查询计划,打包,PG18,执行计划回归,诊断 | 来源:202603/20260314_13.md

Q:PG18 统计信息迁移对 pg_upgrade 意味着什么?

PG18 支持 pg_upgrade 时导出/导入统计信息,升级后不再需要重新跑 ANALYZE,优化器立刻就能用旧统计信息生成好的执行计划。此前升级后统计信息全丢,必须全库 ANALYZE 才能恢复执行计划质量,大库 ANALYZE 很耗时。统计信息迁移打通了 pg_upgrade 的『最后一公里』,让升级后数据库立即达到生产可用状态。

关键词:统计信息,pg_upgrade,ANALYZE,PG18,导出导入,执行计划 | 来源:202602/20260224_01.md

Q:PGTT 插件如何实现 Oracle 的全局临时表?

Oracle 的全局临时表(GTT)是『表结构全局共享、数据会话私有、事务级/会话级提交』,而 PG 原生临时表是『结构+数据都私有』。PGTT 插件模拟 Oracle GTT 语义:表定义持久化,数据按 session 隔离,支持 ON COMMIT PRESERVE/DELETE ROWS 两种行为。使用 PGTT 能让依赖 GTT 的 Oracle 存储过程迁移后不改逻辑,是去 O 场景常用的兼容组件。

关键词:PGTT,全局临时表,GTT,Oracle,会话私有,去O | 来源:202003/20200326_05.md

Q:PG_DBMS_JOB 插件为什么能降低 Oracle 迁移成本?

PG_DBMS_JOB 是 MigOps 开源的插件,兼容 Oracle 的 DBMS_JOB 定时任务接口。PG 原生有 pg_cron、pg_timetable、pg_agent 等定时方案,但函数接口与 Oracle 不一致,迁移时所有 DBMS_JOB 调用都要改写。PG_DBMS_JOB 提供与 Oracle 相同的 DBMS_JOB.SUBMIT/REMOVE/RUN 等风格接口,让 Oracle 定时任务代码几乎不改直接运行,是『为降迁移成本而生』的兼容插件。

关键词:PG_DBMS_JOB,DBMS_JOB,Oracle兼容,定时任务,迁移成本 | 来源:202108/20210828_01.md

Q:PolarDB 开源版如何通过 orafce 支持 Oracle 兼容?

PolarDB 开源版(阿里云 PG 生态)通过 orafce 插件提供 Oracle 兼容能力,让迁移到 PolarDB 的 Oracle 应用能继续使用常用的 Oracle 函数和包。PolarDB 本身基于 PG 内核做计算存储分离等增强,叠加 orafce 后兼具云原生弹性与 Oracle 兼容,是国产云 PG 去 O 的代表方案。

关键词:PolarDB,orafce,Oracle兼容,云原生,去O | 来源:202212/20221207_03.md

Q:PostgreSQL 如何兼容 Oracle 的 10046/10053 SQL trace?

Oracle 用 event 10046 做 SQL trace(记录等待事件、执行统计),10053 输出 CBO 优化器决策过程。PG 没有直接对应物,但可以用插件模拟:如 pg_trace 类插件、或开启 log_statement/log_min_duration_statement 记录 SQL,配合 auto_explain 输出执行计划,再结合 pg_stat_statements 统计,达到接近 10046/10053 的 SQL 诊断能力。德哥文章介绍用插件实现 sql_trace 兼容 10046/10053,帮助 DBA 分析慢 SQL 和优化器选择。

关键词:10046,10053,sql_trace,auto_explain,执行计划,Oracle诊断 | 来源:202109/20210904_04.md

Q:orafce 插件提供了哪些 Oracle 兼容能力?

orafce 是 PostgreSQL 上最常用的 Oracle 兼容插件之一,提供大量 Oracle 内置函数和包的兼容实现,包括日期函数、字符串函数、nvl/nvl2/decode、regexp 系列、DBMS_* 常用包等。它让从 Oracle 迁移过来的 SQL 和存储过程能少改甚至不改直接运行,降低去 O 迁移成本。PolarDB 开源版也通过 orafce 提供 Oracle 兼容性。

关键词:orafce,Oracle兼容,去O,内置函数,DBMS包 | 来源:202103/20210317_03.md

Q:orafce 新版本为什么增加 rlike 之类的函数?

orafce 不断扩充 Oracle 兼容函数,新版增加了 regexp/rlike 等正则相关函数,覆盖更多 Oracle SQL 里常用的正则表达式用法。rlike 是 Oracle/MySQL 风格的正则匹配运算符,orafce 提供对应实现让迁移 SQL 少改。这反映了 orafce 持续补齐 Oracle 函数覆盖度、降低去 O 改写量的演进方向。

关键词:orafce,rlike,regexp,正则,Oracle兼容 | 来源:202103/20210317_03.md

Q:pg_hint_plan 插件如何实现 Oracle 的 SQL Outline?

SQL Outline 是 Oracle 用来固定执行计划、给特定 SQL 挂 hint 的机制。pg_hint_plan 插件让 PostgreSQL 支持在 SQL 注释里写 hint(如指定索引、join 顺序、扫描方式),也能通过配置表按 SQL 指纹绑定 hint,实现类似 SQL Outline 的『不修改应用代码就干预执行计划』。这解决了 PG 没有官方 hint 的痛点,在去 O 迁移和 SQL 调优中很常用。

关键词:pg_hint_plan,SQL Outline,hint,执行计划,固定计划,去O | 来源:202104/20210406_01.md

Q:pg_upgrade 升级后从库为什么要重建,PG 有没有改善?

传统 pg_upgrade 只升级主库,从库因为数据文件被改动无法继续流复制,必须重建(重新做基础备份)或重搭。这在大库场景耗时很长,是 pg_upgrade 长期被吐槽的点。DB 吐槽大会专门提到『升级后从库要重建、不支持增量』。后来的 PG 版本(如 PG18 并行/统计信息迁移)优化了主库升级,但从库重建这一痛点仍主要靠基础备份工具加速,或改用逻辑复制做 minimal downtime 升级来规避。

关键词:从库重建,pg_upgrade,流复制,基础备份,升级痛点 | 来源:202406/20240625_03.md

Q:pg_upgrade 大版本升级的基本原理是什么?

pg_upgrade 通过复用旧版本的数据文件(物理拷贝或硬链接),只重建系统 catalog 和必要元数据,把老版本的数据目录升级到新版本,避免了 pg_dump 逻辑导出再导入的漫长过程。它对数据文件做版本兼容转换,速度远快于 dump/restore,适合数据量大的升级。限制是要求新旧版本二进制兼容、插件同步升级,且需要停机(或用 –link 减少拷贝时间),升级前要跑 –check 做兼容性预检。

关键词:pg_upgrade,大版本升级,数据文件,硬链接,–check,catalog | 来源:202109/20210902_08.md

Q:pgpro-pwr 插件如何实现 Oracle 的 AWR 报告?

pgpro-pwr 是 PostgreSQL 的 AWR(Automatic Workload Repository)兼容插件,定时采集实例的性能快照(等待事件、负载、SQL 统计、IO 等),生成类似 Oracle AWR 的性能报告。它帮助 PG DBA 做性能基线、负载对比和瓶颈定位,弥补 PG 官方没有内置 AWR 的空白,是去 O 后保留 Oracle 运维习惯的重要工具。

关键词:pgpro-pwr,AWR,性能报告,快照,等待事件,去O | 来源:202110/20211004_02.md

Q:xDB Replication Server 在 Oracle 到 PG 迁移里扮演什么角色?

xDB(Replication Server)支持 Oracle、PostgreSQL、SQL Server 等异构数据库间的增量同步复制,迁移场景下常用来做『全量迁移 + 增量同步』,在切换前让目标库持续追平源库,实现近零停机切换。它通过日志解析或触发器捕获源库变更并应用到目标库,相比一次性 dump 更适合需要滚动迁移、双跑验证的场景。

关键词:xDB,Replication Server,异构同步,增量,零停机迁移 | 来源:201902/20190203_01.md

Q:大版本迁移前为什么要做业务兼容性评估?

PG 大版本间存在不兼容变更(如移除的函数、改变的行为、SQL 语法差异、扩展版本要求),迁移前不评估会导致上线后报错或行为异常。评估包括:用 pg_upgrade –check 检查二进制兼容,检查已用扩展在新版本是否有对应版本,扫描 SQL 里用的废弃特性,测试关键查询结果差异。德哥强调跨版本兼容性评估工具长期缺失,需要 DBA 手动或借助工具梳理,是升级风险控制的第一道关。

关键词:兼容性评估,大版本迁移,pg_upgrade,–check,扩展,风险 | 来源:202008/20200826_02.md

Q:异构迁移后如何做数据一致性校验?

用 count、hash 等方法做不对等迁移的一致性校验:迁移后在源库和目标库分别对每张表做行数 count,再对关键列做 hash 聚合(如 md5/聚合 hash 拼接)比对,或抽样全行 hash 比对。对超大表可以按主键分段(分片)分别 count/hash 后对比,避免单次全表聚合过慢。校验通过才能切换业务,是异构迁移(Oracle/SQL Server→PG)必不可少的收尾步骤。

关键词:数据一致性,count,hash,迁移校验,异构,分片 | 来源:202003/20200311_01.md

Q:用 ora_migrator + oracle_fdw 迁移 Oracle 到 PG 的流程是什么?

ora_migrator 是基于 oracle_fdw 的自动化迁移工具:oracle_fdw 让 PG 通过外部表直接访问 Oracle 数据,ora_migrator 则自动分析 Oracle 元数据、在 PG 建对应 schema/表、做类型映射和数据搬迁。流程大致是:配置 Oracle 连接 → 创建外部表 → 迁移表结构 → 拷贝数据 → 校验 → 迁移视图/序列/存储过程等对象。适合中小规模迁移,存储过程等复杂对象仍需人工改写。

关键词:ora_migrator,oracle_fdw,迁移,外部表,Oracle,去O | 来源:201903/20190311_01.md


附录:主题与条数统计

主题 条数
SQL 特性与新版本能力 211
查询优化 / 性能 84
Vacuum / 存储引擎 83
索引 41
事务 / 锁 / 并发 79
高可用 / 流复制 54
备份恢复 / PITR 35
逻辑复制 / CDC / 异构同步 26
分区表 44
监控 / 诊断 66
运维 / 工具 / 部署 / 参数 64
扩展 / 插件 64
安全 38
其他 / 技术杂项 65
向量数据库 / AI 检索 30
国产数据库内核 19
Oracle 兼容 / 迁移 / 去 O 36
合计 1039