PostgreSQL面试题及详细答案120道(61-80)
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

文章目录
- 一、本文面试题目录
- 61. 事务提交(COMMIT)与回滚(ROLLBACK)的底层原理是什么?
- 62. 什么是savepoint(保存点)?如何在事务中使用保存点?
- 63. 高并发场景下,如何优化事务的响应速度?
- 64. 解释MVCC中事务ID(XID)的作用,XID wraparound问题如何解决?
- 65. 如何监控数据库的锁等待情况?使用哪些系统视图(如pg_locks)?
- 66. 常用的备份方式有哪些?pg_dump与pg_basebackup的区别是什么?
- 67. 如何实现数据库的定时备份?备份文件如何验证有效性?
- 68. 写出使用pg_restore恢复数据库的命令,如何只恢复特定表或数据?
- 69. 什么是WAL归档?如何配置WAL归档实现时间点恢复(PITR)?
- 70. 数据库恢复过程中,如何处理索引和约束的重建?
- 71. 简述VACUUM的作用,VACUUM与VACUUM FULL的区别是什么?
- 72. 如何配置自动清理(Autovacuum)?自动清理的触发条件是什么?
- 73. 什么是数据库的统计信息?如何更新统计信息(ANALYZE)?
- 74. 如何查看数据库的连接数、活跃会话?如何限制最大连接数?
- 75. 写出检查并修复表数据一致性的方法,如使用pg_checksums。
- 76. 如何迁移数据库(如从低版本迁移到高版本)?迁移前需做哪些准备?
- 77. 数据库日志(如pg_log)包含哪些信息?如何配置日志级别和轮转策略?
- 78. 如何监控表的增长趋势?使用哪些工具或SQL语句?
- 79. 什么是表碎片?如何检测和清理表碎片?
- 80. 备份文件的存储策略有哪些?如何确保备份的安全性(如加密、异地存储)?
- 二、120道面试题目录列表
一、本文面试题目录
61. 事务提交(COMMIT)与回滚(ROLLBACK)的底层原理是什么?
COMMIT原理:
- WAL写入:将事务日志(WAL)写入磁盘,确保持久性。
- 事务状态更新:在
pg_clog
(事务提交日志)中标记事务为“已提交”。 - 释放锁:释放事务持有的所有行锁和表锁。
- 客户端响应:向客户端返回成功信号。
ROLLBACK原理:
- 撤销操作:通过WAL日志中的回滚记录(undo information)撤销未完成的变更。
- 释放锁:立即释放所有锁,无需等待WAL写入。
- 状态更新:在
pg_clog
中标记事务为“已回滚”。
62. 什么是savepoint(保存点)?如何在事务中使用保存点?
保存点:
事务中的中间标记点,允许部分回滚而不影响整个事务。
示例:
BEGIN;
INSERT INTO users (name) VALUES ('Alice');
SAVEPOINT sp1;
INSERT INTO users (name) VALUES ('Bob');
ROLLBACK TO sp1; -- 回滚到保存点,Bob记录被撤销
INSERT INTO users (name) VALUES ('Charlie');
COMMIT; -- 最终提交Alice和Charlie
应用场景:
- 复杂事务中的部分重试。
- 分阶段提交(如金融交易中的预授权)。
63. 高并发场景下,如何优化事务的响应速度?
优化方法:
- 减少事务持有锁的时间:
-- 低效:长事务 BEGIN; SELECT * FROM orders WHERE status = 'pending' FOR UPDATE; -- 执行耗时操作(如调用外部API) COMMIT;-- 高效:短事务 BEGIN; UPDATE orders SET status = 'processing' WHERE id = $id; COMMIT; -- 异步处理业务逻辑
- 降低隔离级别:
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED;
- 批量操作:
-- 单次提交执行多个操作 UPDATE users SET points = points + 10 WHERE user_id IN (1,2,3,4,5);
- 优化查询计划:
ANALYZE users; -- 更新统计信息
64. 解释MVCC中事务ID(XID)的作用,XID wraparound问题如何解决?
XID作用:
- 每个事务分配唯一的32位无符号整数XID。
- 元组通过
xmin
(创建事务)和xmax
(删除/更新事务)标记可见性。
XID wraparound问题:
- 当XID接近最大值(约40亿)时,新事务可能获得比旧事务更小的XID,导致可见性判断错误。
解决方案:
- 定期冻结元组:
VACUUM (FREEZE) large_table; -- 冻结元组的XID
- 监控XID使用:
SELECT datname, age(datfrozenxid) FROM pg_database; -- 检查各库XID年龄
- 设置自动冻结阈值:
autovacuum_freeze_max_age = 200000000 -- 自动VACUUM FREEZE的阈值
65. 如何监控数据库的锁等待情况?使用哪些系统视图(如pg_locks)?
监控方法:
- 当前锁状态:
SELECT l.pid, a.usename, a.query, l.mode, l.granted, age(now(), a.query_start) AS query_age FROM pg_locks l JOIN pg_stat_activity a ON l.pid = a.pid WHERE NOT l.granted; -- 仅显示等待中的锁
- 锁等待关系:
SELECT blocked_locks.pid AS blocked_pid,blocked_activity.usename AS blocked_user,blocking_locks.pid AS blocking_pid,blocking_activity.usename AS blocking_user,blocked_activity.query AS blocked_query,blocking_activity.query AS blocking_query FROM pg_catalog.pg_locks blocked_locks JOIN pg_catalog.pg_stat_activity blocked_activity ON blocked_locks.pid = blocked_activity.pid JOIN pg_catalog.pg_locks blocking_locks ON blocked_locks.locktype = blocking_locks.locktypeAND blocked_locks.database IS NOT DISTINCT FROM blocking_locks.databaseAND blocked_locks.relation IS NOT DISTINCT FROM blocking_locks.relationAND blocked_locks.page IS NOT DISTINCT FROM blocking_locks.pageAND blocked_locks.tuple IS NOT DISTINCT FROM blocking_locks.tupleAND blocked_locks.virtualxid IS NOT DISTINCT FROM blocking_locks.virtualxidAND blocked_locks.transactionid IS NOT DISTINCT FROM blocking_locks.transactionidAND blocked_locks.classid IS NOT DISTINCT FROM blocking_locks.classidAND blocked_locks.objid IS NOT DISTINCT FROM blocking_locks.objidAND blocked_locks.objsubid IS NOT DISTINCT FROM blocking_locks.objsubidAND blocked_locks.pid != blocking_locks.pid JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_locks.pid = blocking_activity.pid WHERE NOT blocked_locks.granted;
66. 常用的备份方式有哪些?pg_dump与pg_basebackup的区别是什么?
备份方式:
- 逻辑备份(
pg_dump
):导出SQL命令或文本格式。 - 物理备份(
pg_basebackup
):复制数据文件。 - WAL归档:连续归档预写日志。
区别:
特性 | pg_dump | pg_basebackup |
---|---|---|
备份类型 | 逻辑备份(SQL语句) | 物理备份(数据文件) |
恢复粒度 | 表/模式级 | 全库级 |
备份期间可用性 | 可读可写(低锁级别) | 需归档WAL(流式复制) |
备份速度 | 慢(需解析数据) | 快(直接复制文件) |
压缩选项 | 支持(-Z参数) | 不支持(需外部压缩) |
适用场景 | 小规模数据、跨版本迁移 | 大规模数据、时间点恢复 |
67. 如何实现数据库的定时备份?备份文件如何验证有效性?
定时备份:
- Cron任务:
0 2 * * * pg_dump -U postgres -d mydb -F c -f /backup/mydb_$(date +\%Y\%m\%d).dump
- pgBackRest(推荐工具):
pgbackrest --stanza=main backup
验证方法:
- 恢复测试:
pg_restore -l /backup/mydb.dump # 列出备份内容 pg_restore -d testdb /backup/mydb.dump # 恢复到测试库
- 校验和检查:
sha256sum -c /backup/mydb.dump.sha256 # 验证哈希值
- 目录结构检查(物理备份):
tar -tf /backup/basebackup.tar # 检查文件完整性
68. 写出使用pg_restore恢复数据库的命令,如何只恢复特定表或数据?
恢复全量备份:
pg_restore -U postgres -d target_db -C -v /path/to/backup.dump
恢复特定表:
pg_restore -U postgres -d target_db -t users -t orders /path/to/backup.dump
恢复特定模式:
pg_restore -U postgres -d target_db -n public /path/to/backup.dump
仅恢复数据(不包含表结构):
pg_restore -U postgres -d target_db -a -t users /path/to/backup.dump
仅恢复结构(不包含数据):
pg_restore -U postgres -d target_db -s /path/to/backup.dump
69. 什么是WAL归档?如何配置WAL归档实现时间点恢复(PITR)?
WAL归档:
将预写日志(WAL)文件持续复制到安全位置,用于崩溃恢复或时间点恢复。
配置步骤:
- 修改
postgresql.conf
:wal_level = replica # 至少设置为replica archive_mode = on # 启用归档 archive_command = 'cp %p /path/to/archive/%f' # 归档命令 max_wal_senders = 10 # 最大WAL发送进程数
- 重启PostgreSQL:
pg_ctl restart -D /var/lib/postgresql/data
- 验证归档:
SELECT pg_switch_wal(); # 手动触发WAL切换,检查归档目录是否生成新文件
PITR恢复流程:
- 恢复基础备份(使用
pg_basebackup
)。 - 配置
recovery.conf
指定恢复目标:restore_command = 'cp /path/to/archive/%f %p' recovery_target_time = '2023-07-25 12:00:00' # 指定时间点
- 启动恢复:
pg_ctl start -D /var/lib/postgresql/data
70. 数据库恢复过程中,如何处理索引和约束的重建?
恢复流程:
- 基础恢复:
pg_restore -C -d postgres /path/to/backup.dump # 恢复全量备份
- 自动重建(默认行为):
- 索引和约束会随表结构自动恢复,无需额外操作。
手动优化:
- 恢复时跳过索引:
pg_restore -s -d postgres /path/to/backup.dump # 仅恢复结构(不含索引)
- 批量创建索引:
CREATE INDEX CONCURRENTLY idx_users_email ON users (email);
- 检查约束:
ALTER TABLE orders VALIDATE CONSTRAINT fk_customer_id; # 验证外键约束
No. | 大剑师精品GIS教程推荐 |
---|---|
0 | 地图渲染基础- 【WebGL 教程】 - 【Canvas 教程】 - 【SVG 教程】 |
1 | Openlayers 【入门教程】 - 【源代码+示例 300+】 |
2 | Leaflet 【入门教程】 - 【源代码+图文示例 150+】 |
3 | MapboxGL 【入门教程】 - 【源代码+图文示例150+】 |
4 | Cesium 【入门教程】 - 【源代码+综合教程 200+】 |
5 | threejs 【中文API】 - 【源代码+图文示例200+】 |
6 | Shader 编程 【图文示例 100+】 |
71. 简述VACUUM的作用,VACUUM与VACUUM FULL的区别是什么?
VACUUM作用:
- 回收被删除或更新元组占用的空间。
- 更新统计信息,帮助查询优化器。
- 冻结旧XID,防止wraparound。
区别:
特性 | VACUUM | VACUUM FULL |
---|---|---|
空间回收 | 标记空间可重用(不缩小文件) | 重组数据文件(缩小文件) |
锁级别 | 行级锁(不阻塞读写) | 表级ACCESS EXCLUSIVE 锁 |
执行速度 | 快 | 慢 |
临时空间需求 | 低 | 高(可能需要2倍表空间) |
适用场景 | 日常维护 | 空间紧张时手动优化 |
72. 如何配置自动清理(Autovacuum)?自动清理的触发条件是什么?
配置步骤(修改postgresql.conf
):
autovacuum = on # 启用自动清理
log_autovacuum_min_duration = 0 # 记录所有自动清理操作
autovacuum_vacuum_threshold = 50 # 至少50行变更触发VACUUM
autovacuum_analyze_threshold = 50 # 至少50行变更触发ANALYZE
autovacuum_vacuum_scale_factor = 0.2 # 表大小的20%变更触发VACUUM
autovacuum_analyze_scale_factor = 0.1 # 表大小的10%变更触发ANALYZE
触发条件:
当表的变更行数超过阈值时(阈值 = 固定值 + 表大小 × 比例因子),autovacuum会启动工作进程执行清理。
73. 什么是数据库的统计信息?如何更新统计信息(ANALYZE)?
统计信息:
PostgreSQL优化器用于生成查询计划的数据,包括:
- 表行数(
reltuples
)。 - 列数据分布(如直方图、相关性)。
- 唯一值比例(选择性)。
更新方法:
ANALYZE users; -- 更新单个表ANALYZE VERBOSE orders; -- 详细模式,显示进度VACUUM ANALYZE products; -- 同时执行VACUUM和ANALYZE
自动更新(通过autovacuum):
autovacuum_analyze_scale_factor = 0.1 # 表大小的10%变更触发ANALYZE
74. 如何查看数据库的连接数、活跃会话?如何限制最大连接数?
查看连接数:
-- 当前总连接数
SELECT COUNT(*) FROM pg_stat_activity;-- 按数据库分组的连接数
SELECT datname, COUNT(*)
FROM pg_stat_activity
GROUP BY datname;-- 活跃会话(执行中查询)
SELECT pid, usename, query, state, query_start
FROM pg_stat_activity
WHERE state = 'active';
限制连接数:
- 全局限制(修改
postgresql.conf
):max_connections = 200 # 最大连接数
- 单数据库限制:
ALTER DATABASE mydb SET CONNECTION LIMIT 50; -- 限制mydb最多50个连接
- 用户限制:
ALTER ROLE readonly_user CONNECTION LIMIT 10; -- 用户最多10个连接
75. 写出检查并修复表数据一致性的方法,如使用pg_checksums。
启用数据校验和(需重建集群):
initdb -D /var/lib/postgresql/data --data-checksums # 初始化时启用
检查一致性:
pg_checksums --verify -D /var/lib/postgresql/data # 离线检查
修复损坏:
- 使用WAL归档恢复:
pg_restore -C -d postgres /path/to/backup.dump # 恢复备份 pg_ctl start -D /var/lib/postgresql/data -o "-c restore_command='cp /archive/%f %p'" # 应用WAL
- 修复单个表:
REINDEX TABLE corrupted_table; -- 重建索引 VACUUM FULL corrupted_table; -- 重组表
76. 如何迁移数据库(如从低版本迁移到高版本)?迁移前需做哪些准备?
迁移方法:
- 逻辑迁移(推荐):
# 旧版本导出 pg_dump -U postgres -d mydb -F c -f /backup/mydb.dump# 新版本导入 pg_restore -U postgres -d mydb -C /backup/mydb.dump
- 物理迁移(需相同架构):
pg_basebackup -D /new/data/dir -U replication_user -X stream
迁移前准备:
- 备份数据:
pg_dumpall > all_databases.sql
- 检查兼容性:
pg_upgrade --check -b /old/bin -B /new/bin -d /old/data -D /new/data
- 清理和分析:
VACUUM FULL ANALYZE; -- 优化表和索引
- 禁用触发器(可选):
ALTER TABLE users DISABLE TRIGGER ALL; -- 迁移期间禁用触发器
77. 数据库日志(如pg_log)包含哪些信息?如何配置日志级别和轮转策略?
日志内容:
- 启动/关闭信息。
- SQL语句执行(取决于
log_statement
设置)。 - 错误和警告信息。
- 自动清理(autovacuum)活动。
- 锁等待和死锁检测。
配置日志级别(postgresql.conf
):
log_destination = 'csvlog' # 输出格式:csv或stderr
logging_collector = on # 启用日志收集
log_directory = 'pg_log' # 日志目录
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # 日志文件名
log_min_messages = warning # 日志级别:debug5, debug4, ..., warning, error
log_min_error_statement = error # 记录错误级别的SQL
log_statement = 'ddl' # 记录DDL语句(可选:'all', 'none')
日志轮转:
- 自动轮转(通过
log_rotation_age
和log_rotation_size
):log_rotation_age = 1d # 每天轮转 log_rotation_size = 10MB # 每10MB轮转
- 手动轮转:
pg_ctl -D /var/lib/postgresql/data rotate-log
78. 如何监控表的增长趋势?使用哪些工具或SQL语句?
监控方法:
- 定期查询表大小:
SELECT relname AS table_name,pg_size_pretty(pg_total_relation_size(relid)) AS total_size,pg_size_pretty(pg_relation_size(relid)) AS data_size,pg_size_pretty(pg_indexes_size(relid)) AS index_size FROM pg_stat_user_tables ORDER BY pg_total_relation_size(relid) DESC;
- 记录历史数据:
CREATE TABLE table_size_history (capture_time TIMESTAMP DEFAULT NOW(),table_name TEXT,row_count BIGINT,total_size BIGINT );INSERT INTO table_size_history (table_name, row_count, total_size) SELECT relname,reltuples,pg_total_relation_size(relid) FROM pg_class WHERE relkind = 'r';
- 使用监控工具:
- pg_stat_activity:实时查询活动。
- pgBadger:生成HTML格式的日志分析报告。
- Prometheus + Grafana:长期趋势监控。
79. 什么是表碎片?如何检测和清理表碎片?
表碎片:
- 行迁移导致的空间碎片化。
- 频繁更新/删除导致的空闲空间未被有效利用。
- 索引页分裂导致的索引碎片化。
检测方法:
-- 查询表膨胀率
SELECT schemaname || '.' || relname AS table_name,pg_size_pretty(pg_total_relation_size(relid)) AS total_size,CASE WHEN relpages * 8192 < 1048576 THEN 'NA'ELSE pg_size_pretty(pgstattuple(relid)::text::json->>'dead_tuple_len')END AS dead_space
FROM pg_stat_user_tables
ORDER BY pg_total_relation_size(relid) DESC;
清理方法:
VACUUM FULL ANALYZE large_table; -- 重组表(阻塞)REINDEX CONCURRENTLY idx_large_table; -- 重建索引(非阻塞)
80. 备份文件的存储策略有哪些?如何确保备份的安全性(如加密、异地存储)?
存储策略:
- 本地存储:快速恢复,但易受本地灾难影响。
- 异地存储:通过网络复制到远程服务器。
- 云存储:如AWS S3、Azure Blob Storage。
- 磁带存储:长期归档,成本低但恢复慢。
安全措施:
- 加密备份:
# 使用pg_dump加密 pg_dump -U postgres -d mydb | gpg -c -o mydb.dump.gpg# 使用pgBackRest加密 pgbackrest --stanza=main --repo1-cipher-type=aes-256-cbc backup
- 访问控制:
chmod 600 /backup/*.dump # 限制备份文件权限
- 异地容灾:
rsync -avz /backup/ user@remote:/backup/ # 定期同步到远程服务器
- 多版本保留:
find /backup -type f -mtime +30 -delete # 保留最近30天的备份
- 监控与验证:
pg_restore -t users -l /backup/mydb.dump # 定期验证备份可用性
二、120道面试题目录列表
文章序号 | PostgreSQL面试题120道 |
---|---|
1 | PostgreSQL面试题及详细答案120道(01-20) |
2 | PostgreSQL面试题及详细答案120道(20-40) |
3 | PostgreSQL面试题及详细答案120道(41-60) |
4 | PostgreSQL面试题及详细答案120道(61-80) |
5 | PostgreSQL面试题及详细答案120道(81-100) |
5 | PostgreSQL面试题及详细答案120道(101-120) |