一、PostgreSQL 简介
1.1 什么是 PostgreSQL
PostgreSQL(常被称为 Postgres)是一个功能强大的开源对象关系型数据库管理系统(ORDBMS)。它起源于 1986 年加州大学伯克利分校的 POSTGRES 项目,至今已有超过 35 年的活跃开发历史。
PostgreSQL 以其可靠性、功能健壮性和性能而著称,被广泛认为是最先进的开源数据库系统。它完全符合 ACID 原则,支持绝大多数 SQL:2011 标准,并提供了许多先进特性。
PostgreSQL(常被称为 Postgres)是一个功能强大的开源对象关系型数据库管理系统(ORDBMS)。它起源于 1986 年加州大学伯克利分校的 POSTGRES 项目,至今已有超过 35 年的活跃开发历史。
PostgreSQL 以其可靠性、功能健壮性和性能而著称,被广泛认为是最先进的开源数据库系统。它完全符合 ACID 原则,支持绝大多数 SQL:2011 标准,并提供了许多先进特性。
PostgreSQL 采用典型的客户端/服务器架构,由多个进程协同工作。
# 查看 PostgreSQL 进程
ps aux | grep postgres
# 典型输出:
# postgres 1234 postmaster # 主进程
# postgres 1235 checkpointer # 检查点进程
# postgres 1236 background writer # 后台写进程
# postgres 1237 walwriter # WAL 写进程
# postgres 1238 autovacuum launcher # 自动清理启动器
# postgres 1239 stats collector # 统计收集器
# postgres 1240 logical replication launcher # 逻辑复制启动器
# postgres 1241 postgres: user db [active] # 后端进程
PostgreSQL 提供了非常丰富的数据类型系统,这是其区别于其他数据库的重要特性之一。
| 类型 | 存储大小 | 范围 | 使用场景 |
|---|---|---|---|
| SMALLINT | 2 字节 | -32768 ~ 32767 | 小范围整数、状态码 |
| INTEGER | 4 字节 | -2147483648 ~ 2147483647 | 常规整数、主键 |
| BIGINT | 8 字节 | -9223372036854775808 ~ 9223372036854775807 | 大数值、大表主键 |
索引是数据库中用于加速数据检索的数据结构。它类似于书籍的目录,通过索引可以快速定位到目标数据,而不需要扫描整个表。
PostgreSQL 提供了六种内置索引类型,每种都有其特定的使用场景:
| 索引类型 | 适用场景 | 支持的操作符 |
| ----------- | ---------------------------- | -------------------------------------------- | ---- |
| B-Tree | 范围查询、排序、等值查询 | <, <=, =, >=, >, BETWEEN, IN, LIKE 'prefix%' |
| Hash | 等值查询 | = |
| GiST | 几何数据、全文搜索、范围类型 | @>, <@, &&, @@ |
| SP-GiST | 非平衡数据结构 | <<, >>, ~= |
| GIN | 数组、JSONB、全文搜索 | @>, ?, ?&, ? | , @@ |
| BRIN | 大表、物理有序数据 | <, <=, =, >=, > |
事务(Transaction)是数据库操作的基本单位,它是一组不可分割的操作序列,要么全部执行成功,要么全部不执行。
-- 开始事务
BEGIN;
-- 或
START TRANSACTION;
-- 执行操作
INSERT INTO accounts (user_id, balance) VALUES (1, 1000);
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
-- 提交事务
COMMIT;
-- 回滚事务
ROLLBACK;
-- 设置事务特性
BEGIN ISOLATION LEVEL SERIALIZABLE;
BEGIN READ ONLY;
BEGIN ISOLATION LEVEL READ COMMITTED READ WRITE;
-- 保存点(Savepoint)
BEGIN;
INSERT INTO users (name) VALUES ('Alice');
SAVEPOINT sp1;
INSERT INTO users (name) VALUES ('Bob');
-- 发现错误,回滚到保存点
ROLLBACK TO SAVEPOINT sp1;
-- Bob 的插入被回滚,Alice 保留
INSERT INTO users (name) VALUES ('Charlie');
COMMIT;
-- 释放保存点
RELEASE SAVEPOINT sp1;
EXPLAIN 是分析查询性能的最重要工具,它展示了查询优化器选择的执行计划。
-- 基本用法
EXPLAIN SELECT * FROM users WHERE id = 1;
-- 显示实际执行信息
EXPLAIN ANALYZE SELECT * FROM users WHERE id = 1;
-- 完整选项
EXPLAIN (
ANALYZE, -- 实际执行并显示统计
BUFFERS, -- 显示缓冲区使用情况
COSTS, -- 显示成本估算(默认开启)
TIMING, -- 显示实际时间
FORMAT TEXT -- 输出格式:TEXT, XML, JSON, YAML
) SELECT * FROM users WHERE id = 1;
-- 不实际执行(只看计划)
EXPLAIN (COSTS, VERBOSE) SELECT * FROM users WHERE id = 1;
窗口函数在一组相关的行上执行计算,同时保留原始行。与 GROUP BY 不同,窗口函数不会合并行。
-- 基本语法
function_name(args) OVER (
[PARTITION BY partition_expression]
[ORDER BY sort_expression [ASC|DESC] [NULLS {FIRST|LAST}]]
[frame_clause]
)
-- 窗口帧子句
ROWS BETWEEN frame_start AND frame_end
RANGE BETWEEN frame_start AND frame_end
GROUPS BETWEEN frame_start AND frame_end
-- frame_start / frame_end 选项
UNBOUNDED PRECEDING -- 分区开始
N PRECEDING -- 当前行前 N 行
CURRENT ROW -- 当前行
N FOLLOWING -- 当前行后 N 行
UNBOUNDED FOLLOWING -- 分区结束
-- 默认窗口帧
-- 有 ORDER BY: RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
-- 无 ORDER BY: ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
PL/pgSQL(Procedural Language/PostgreSQL)是 PostgreSQL 的过程化编程语言,用于编写存储过程、函数和触发器。
-- 函数基本结构
CREATE [OR REPLACE] FUNCTION function_name(
param1 data_type,
param2 data_type DEFAULT default_value
)
RETURNS return_type
LANGUAGE plpgsql
AS $$
DECLARE
-- 变量声明
variable_name data_type;
BEGIN
-- 函数体
RETURN result;
END;
$$;
-- 存储过程(PostgreSQL 11+)
CREATE [OR REPLACE] PROCEDURE procedure_name(
param1 data_type,
INOUT param2 data_type
)
LANGUAGE plpgsql
AS $$
BEGIN
-- 过程体
END;
$$;
-- 调用函数
SELECT function_name(arg1, arg2);
-- 调用存储过程
CALL procedure_name(arg1, arg2);
| 特性 | 流复制 | 逻辑复制 |
|---|---|---|
| 复制单位 | 整个实例 | 表/数据库 |
| 数据格式 | WAL 物理日志 | 逻辑变更 |
| 从库可写 | 否 | 是 |
| 跨版本 | 需相同主版本 | 可以 |
| 跨平台 | 需相同平台 | 可以 |
| DDL 复制 | 自动 | 不复制 |
| 性能影响 | 低 | 较高 |
| 复杂度 | 低 | 中等 |
-- 1. 检查系统整体状态
SELECT
numbackends AS connections,
xact_commit AS commits,
xact_rollback AS rollbacks,
blks_read AS disk_reads,
blks_hit AS cache_hits,
round(100.0 * blks_hit / NULLIF(blks_read + blks_hit, 0), 2) AS cache_hit_ratio,
tup_returned AS rows_returned,
tup_fetched AS rows_fetched,
tup_inserted AS rows_inserted,
tup_updated AS rows_updated,
tup_deleted AS rows_deleted
FROM pg_stat_database
WHERE datname = current_database();
-- 2. 检查活动连接
SELECT
state,
COUNT(*) AS count,
MAX(NOW() - query_start) AS max_duration
FROM pg_stat_activity
GROUP BY state;
-- 3. 检查慢查询
SELECT
pid,
NOW() - query_start AS duration,
query,
state
FROM pg_stat_activity
WHERE state != 'idle'
AND query_start < NOW() - INTERVAL '5 seconds'
ORDER BY duration DESC;
-- 4. 检查锁等待
SELECT
blocked.pid AS blocked_pid,
blocked.query AS blocked_query,
blocking.pid AS blocking_pid,
blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_locks blocked_locks ON blocked.pid = blocked_locks.pid
JOIN pg_locks blocking_locks ON
blocked_locks.locktype = blocking_locks.locktype
AND blocked_locks.relation = blocking_locks.relation
AND blocked_locks.pid != blocking_locks.pid
JOIN pg_stat_activity blocking ON blocking_locks.pid = blocking.pid
WHERE NOT blocked_locks.granted;